diff options
Diffstat (limited to 'fs')
403 files changed, 12404 insertions, 9576 deletions
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 88e3787c6ea9..e298fe194093 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
| @@ -119,6 +119,7 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) | |||
| 119 | 119 | ||
| 120 | const struct file_operations v9fs_dir_operations = { | 120 | const struct file_operations v9fs_dir_operations = { |
| 121 | .read = generic_read_dir, | 121 | .read = generic_read_dir, |
| 122 | .llseek = generic_file_llseek, | ||
| 122 | .readdir = v9fs_dir_readdir, | 123 | .readdir = v9fs_dir_readdir, |
| 123 | .open = v9fs_file_open, | 124 | .open = v9fs_file_open, |
| 124 | .release = v9fs_dir_release, | 125 | .release = v9fs_dir_release, |
diff --git a/fs/Kconfig b/fs/Kconfig index 37db79a2ff95..abccb5dab9a8 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
| @@ -902,65 +902,7 @@ endif # BLOCK | |||
| 902 | 902 | ||
| 903 | menu "Pseudo filesystems" | 903 | menu "Pseudo filesystems" |
| 904 | 904 | ||
| 905 | config PROC_FS | 905 | source "fs/proc/Kconfig" |
| 906 | bool "/proc file system support" if EMBEDDED | ||
| 907 | default y | ||
| 908 | help | ||
| 909 | This is a virtual file system providing information about the status | ||
| 910 | of the system. "Virtual" means that it doesn't take up any space on | ||
| 911 | your hard disk: the files are created on the fly by the kernel when | ||
| 912 | you try to access them. Also, you cannot read the files with older | ||
| 913 | version of the program less: you need to use more or cat. | ||
| 914 | |||
| 915 | It's totally cool; for example, "cat /proc/interrupts" gives | ||
| 916 | information about what the different IRQs are used for at the moment | ||
| 917 | (there is a small number of Interrupt ReQuest lines in your computer | ||
| 918 | that are used by the attached devices to gain the CPU's attention -- | ||
| 919 | often a source of trouble if two devices are mistakenly configured | ||
| 920 | to use the same IRQ). The program procinfo to display some | ||
| 921 | information about your system gathered from the /proc file system. | ||
| 922 | |||
| 923 | Before you can use the /proc file system, it has to be mounted, | ||
| 924 | meaning it has to be given a location in the directory hierarchy. | ||
| 925 | That location should be /proc. A command such as "mount -t proc proc | ||
| 926 | /proc" or the equivalent line in /etc/fstab does the job. | ||
| 927 | |||
| 928 | The /proc file system is explained in the file | ||
| 929 | <file:Documentation/filesystems/proc.txt> and on the proc(5) manpage | ||
| 930 | ("man 5 proc"). | ||
| 931 | |||
| 932 | This option will enlarge your kernel by about 67 KB. Several | ||
| 933 | programs depend on this, so everyone should say Y here. | ||
| 934 | |||
| 935 | config PROC_KCORE | ||
| 936 | bool "/proc/kcore support" if !ARM | ||
| 937 | depends on PROC_FS && MMU | ||
| 938 | |||
| 939 | config PROC_VMCORE | ||
| 940 | bool "/proc/vmcore support (EXPERIMENTAL)" | ||
| 941 | depends on PROC_FS && CRASH_DUMP | ||
| 942 | default y | ||
| 943 | help | ||
| 944 | Exports the dump image of crashed kernel in ELF format. | ||
| 945 | |||
| 946 | config PROC_SYSCTL | ||
| 947 | bool "Sysctl support (/proc/sys)" if EMBEDDED | ||
| 948 | depends on PROC_FS | ||
| 949 | select SYSCTL | ||
| 950 | default y | ||
| 951 | ---help--- | ||
| 952 | The sysctl interface provides a means of dynamically changing | ||
| 953 | certain kernel parameters and variables on the fly without requiring | ||
| 954 | a recompile of the kernel or reboot of the system. The primary | ||
| 955 | interface is through /proc/sys. If you say Y here a tree of | ||
| 956 | modifiable sysctl entries will be generated beneath the | ||
| 957 | /proc/sys directory. They are explained in the files | ||
| 958 | in <file:Documentation/sysctl/>. Note that enabling this | ||
| 959 | option will enlarge the kernel by at least 8 KB. | ||
| 960 | |||
| 961 | As it is generally a good thing, you should say Y here unless | ||
| 962 | building a kernel for install/rescue disks or your system is very | ||
| 963 | limited in memory. | ||
| 964 | 906 | ||
| 965 | config SYSFS | 907 | config SYSFS |
| 966 | bool "sysfs file system support" if EMBEDDED | 908 | bool "sysfs file system support" if EMBEDDED |
| @@ -1441,6 +1383,19 @@ config MINIX_FS | |||
| 1441 | partition (the one containing the directory /) cannot be compiled as | 1383 | partition (the one containing the directory /) cannot be compiled as |
| 1442 | a module. | 1384 | a module. |
| 1443 | 1385 | ||
| 1386 | config OMFS_FS | ||
| 1387 | tristate "SonicBlue Optimized MPEG File System support" | ||
| 1388 | depends on BLOCK | ||
| 1389 | select CRC_ITU_T | ||
| 1390 | help | ||
| 1391 | This is the proprietary file system used by the Rio Karma music | ||
| 1392 | player and ReplayTV DVR. Despite the name, this filesystem is not | ||
| 1393 | more efficient than a standard FS for MPEG files, in fact likely | ||
| 1394 | the opposite is true. Say Y if you have either of these devices | ||
| 1395 | and wish to mount its disk. | ||
| 1396 | |||
| 1397 | To compile this file system support as a module, choose M here: the | ||
| 1398 | module will be called omfs. If unsure, say N. | ||
| 1444 | 1399 | ||
| 1445 | config HPFS_FS | 1400 | config HPFS_FS |
| 1446 | tristate "OS/2 HPFS file system support" | 1401 | tristate "OS/2 HPFS file system support" |
| @@ -1975,6 +1930,16 @@ config CIFS_WEAK_PW_HASH | |||
| 1975 | 1930 | ||
| 1976 | If unsure, say N. | 1931 | If unsure, say N. |
| 1977 | 1932 | ||
| 1933 | config CIFS_UPCALL | ||
| 1934 | bool "Kerberos/SPNEGO advanced session setup" | ||
| 1935 | depends on CIFS && KEYS | ||
| 1936 | help | ||
| 1937 | Enables an upcall mechanism for CIFS which accesses | ||
| 1938 | userspace helper utilities to provide SPNEGO packaged (RFC 4178) | ||
| 1939 | Kerberos tickets which are needed to mount to certain secure servers | ||
| 1940 | (for which more secure Kerberos authentication is required). If | ||
| 1941 | unsure, say N. | ||
| 1942 | |||
| 1978 | config CIFS_XATTR | 1943 | config CIFS_XATTR |
| 1979 | bool "CIFS extended attributes" | 1944 | bool "CIFS extended attributes" |
| 1980 | depends on CIFS | 1945 | depends on CIFS |
| @@ -2027,17 +1992,6 @@ config CIFS_EXPERIMENTAL | |||
| 2027 | (which is disabled by default). See the file fs/cifs/README | 1992 | (which is disabled by default). See the file fs/cifs/README |
| 2028 | for more details. If unsure, say N. | 1993 | for more details. If unsure, say N. |
| 2029 | 1994 | ||
| 2030 | config CIFS_UPCALL | ||
| 2031 | bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" | ||
| 2032 | depends on CIFS_EXPERIMENTAL | ||
| 2033 | depends on KEYS | ||
| 2034 | help | ||
| 2035 | Enables an upcall mechanism for CIFS which accesses | ||
| 2036 | userspace helper utilities to provide SPNEGO packaged (RFC 4178) | ||
| 2037 | Kerberos tickets which are needed to mount to certain secure servers | ||
| 2038 | (for which more secure Kerberos authentication is required). If | ||
| 2039 | unsure, say N. | ||
| 2040 | |||
| 2041 | config CIFS_DFS_UPCALL | 1995 | config CIFS_DFS_UPCALL |
| 2042 | bool "DFS feature support (EXPERIMENTAL)" | 1996 | bool "DFS feature support (EXPERIMENTAL)" |
| 2043 | depends on CIFS_EXPERIMENTAL | 1997 | depends on CIFS_EXPERIMENTAL |
| @@ -2093,20 +2047,6 @@ config CODA_FS | |||
| 2093 | To compile the coda client support as a module, choose M here: the | 2047 | To compile the coda client support as a module, choose M here: the |
| 2094 | module will be called coda. | 2048 | module will be called coda. |
| 2095 | 2049 | ||
| 2096 | config CODA_FS_OLD_API | ||
| 2097 | bool "Use 96-bit Coda file identifiers" | ||
| 2098 | depends on CODA_FS | ||
| 2099 | help | ||
| 2100 | A new kernel-userspace API had to be introduced for Coda v6.0 | ||
| 2101 | to support larger 128-bit file identifiers as needed by the | ||
| 2102 | new realms implementation. | ||
| 2103 | |||
| 2104 | However this new API is not backward compatible with older | ||
| 2105 | clients. If you really need to run the old Coda userspace | ||
| 2106 | cache manager then say Y. | ||
| 2107 | |||
| 2108 | For most cases you probably want to say N. | ||
| 2109 | |||
| 2110 | config AFS_FS | 2050 | config AFS_FS |
| 2111 | tristate "Andrew File System support (AFS) (EXPERIMENTAL)" | 2051 | tristate "Andrew File System support (AFS) (EXPERIMENTAL)" |
| 2112 | depends on INET && EXPERIMENTAL | 2052 | depends on INET && EXPERIMENTAL |
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt index 3263084eef9e..4a551af6f3fc 100644 --- a/fs/Kconfig.binfmt +++ b/fs/Kconfig.binfmt | |||
| @@ -30,7 +30,7 @@ config COMPAT_BINFMT_ELF | |||
| 30 | config BINFMT_ELF_FDPIC | 30 | config BINFMT_ELF_FDPIC |
| 31 | bool "Kernel support for FDPIC ELF binaries" | 31 | bool "Kernel support for FDPIC ELF binaries" |
| 32 | default y | 32 | default y |
| 33 | depends on (FRV || BLACKFIN) | 33 | depends on (FRV || BLACKFIN || (SUPERH32 && !MMU)) |
| 34 | help | 34 | help |
| 35 | ELF FDPIC binaries are based on ELF, but allow the individual load | 35 | ELF FDPIC binaries are based on ELF, but allow the individual load |
| 36 | segments of a binary to be located in memory independently of each | 36 | segments of a binary to be located in memory independently of each |
diff --git a/fs/Makefile b/fs/Makefile index 3b2178b4bb66..a1482a5eff15 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
| @@ -111,6 +111,7 @@ obj-$(CONFIG_ADFS_FS) += adfs/ | |||
| 111 | obj-$(CONFIG_FUSE_FS) += fuse/ | 111 | obj-$(CONFIG_FUSE_FS) += fuse/ |
| 112 | obj-$(CONFIG_UDF_FS) += udf/ | 112 | obj-$(CONFIG_UDF_FS) += udf/ |
| 113 | obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ | 113 | obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ |
| 114 | obj-$(CONFIG_OMFS_FS) += omfs/ | ||
| 114 | obj-$(CONFIG_JFS_FS) += jfs/ | 115 | obj-$(CONFIG_JFS_FS) += jfs/ |
| 115 | obj-$(CONFIG_XFS_FS) += xfs/ | 116 | obj-$(CONFIG_XFS_FS) += xfs/ |
| 116 | obj-$(CONFIG_9P_FS) += 9p/ | 117 | obj-$(CONFIG_9P_FS) += 9p/ |
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index fc1a8dc64d78..85a30e929800 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c | |||
| @@ -197,6 +197,7 @@ out: | |||
| 197 | 197 | ||
| 198 | const struct file_operations adfs_dir_operations = { | 198 | const struct file_operations adfs_dir_operations = { |
| 199 | .read = generic_read_dir, | 199 | .read = generic_read_dir, |
| 200 | .llseek = generic_file_llseek, | ||
| 200 | .readdir = adfs_readdir, | 201 | .readdir = adfs_readdir, |
| 201 | .fsync = file_fsync, | 202 | .fsync = file_fsync, |
| 202 | }; | 203 | }; |
diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 9e421eeb672b..26f3b43726bb 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c | |||
| @@ -249,7 +249,7 @@ static void adfs_destroy_inode(struct inode *inode) | |||
| 249 | kmem_cache_free(adfs_inode_cachep, ADFS_I(inode)); | 249 | kmem_cache_free(adfs_inode_cachep, ADFS_I(inode)); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | static void init_once(struct kmem_cache *cachep, void *foo) | 252 | static void init_once(void *foo) |
| 253 | { | 253 | { |
| 254 | struct adfs_inode_info *ei = (struct adfs_inode_info *) foo; | 254 | struct adfs_inode_info *ei = (struct adfs_inode_info *) foo; |
| 255 | 255 | ||
diff --git a/fs/affs/affs.h b/fs/affs/affs.h index 223b1917093e..e9ec915f7553 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include <linux/fs.h> | 2 | #include <linux/fs.h> |
| 3 | #include <linux/buffer_head.h> | 3 | #include <linux/buffer_head.h> |
| 4 | #include <linux/amigaffs.h> | 4 | #include <linux/amigaffs.h> |
| 5 | #include <linux/mutex.h> | ||
| 5 | 6 | ||
| 6 | /* AmigaOS allows file names with up to 30 characters length. | 7 | /* AmigaOS allows file names with up to 30 characters length. |
| 7 | * Names longer than that will be silently truncated. If you | 8 | * Names longer than that will be silently truncated. If you |
| @@ -98,7 +99,7 @@ struct affs_sb_info { | |||
| 98 | gid_t s_gid; /* gid to override */ | 99 | gid_t s_gid; /* gid to override */ |
| 99 | umode_t s_mode; /* mode to override */ | 100 | umode_t s_mode; /* mode to override */ |
| 100 | struct buffer_head *s_root_bh; /* Cached root block. */ | 101 | struct buffer_head *s_root_bh; /* Cached root block. */ |
| 101 | struct semaphore s_bmlock; /* Protects bitmap access. */ | 102 | struct mutex s_bmlock; /* Protects bitmap access. */ |
| 102 | struct affs_bm_info *s_bitmap; /* Bitmap infos. */ | 103 | struct affs_bm_info *s_bitmap; /* Bitmap infos. */ |
| 103 | u32 s_bmap_count; /* # of bitmap blocks. */ | 104 | u32 s_bmap_count; /* # of bitmap blocks. */ |
| 104 | u32 s_bmap_bits; /* # of bits in one bitmap blocks */ | 105 | u32 s_bmap_bits; /* # of bits in one bitmap blocks */ |
diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index c4a5ad09ddf2..dc5ef14bdc1c 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c | |||
| @@ -45,14 +45,14 @@ affs_count_free_blocks(struct super_block *sb) | |||
| 45 | if (sb->s_flags & MS_RDONLY) | 45 | if (sb->s_flags & MS_RDONLY) |
| 46 | return 0; | 46 | return 0; |
| 47 | 47 | ||
| 48 | down(&AFFS_SB(sb)->s_bmlock); | 48 | mutex_lock(&AFFS_SB(sb)->s_bmlock); |
| 49 | 49 | ||
| 50 | bm = AFFS_SB(sb)->s_bitmap; | 50 | bm = AFFS_SB(sb)->s_bitmap; |
| 51 | free = 0; | 51 | free = 0; |
| 52 | for (i = AFFS_SB(sb)->s_bmap_count; i > 0; bm++, i--) | 52 | for (i = AFFS_SB(sb)->s_bmap_count; i > 0; bm++, i--) |
| 53 | free += bm->bm_free; | 53 | free += bm->bm_free; |
| 54 | 54 | ||
| 55 | up(&AFFS_SB(sb)->s_bmlock); | 55 | mutex_unlock(&AFFS_SB(sb)->s_bmlock); |
| 56 | 56 | ||
| 57 | return free; | 57 | return free; |
| 58 | } | 58 | } |
| @@ -76,7 +76,7 @@ affs_free_block(struct super_block *sb, u32 block) | |||
| 76 | bit = blk % sbi->s_bmap_bits; | 76 | bit = blk % sbi->s_bmap_bits; |
| 77 | bm = &sbi->s_bitmap[bmap]; | 77 | bm = &sbi->s_bitmap[bmap]; |
| 78 | 78 | ||
| 79 | down(&sbi->s_bmlock); | 79 | mutex_lock(&sbi->s_bmlock); |
| 80 | 80 | ||
| 81 | bh = sbi->s_bmap_bh; | 81 | bh = sbi->s_bmap_bh; |
| 82 | if (sbi->s_last_bmap != bmap) { | 82 | if (sbi->s_last_bmap != bmap) { |
| @@ -105,19 +105,19 @@ affs_free_block(struct super_block *sb, u32 block) | |||
| 105 | sb->s_dirt = 1; | 105 | sb->s_dirt = 1; |
| 106 | bm->bm_free++; | 106 | bm->bm_free++; |
| 107 | 107 | ||
| 108 | up(&sbi->s_bmlock); | 108 | mutex_unlock(&sbi->s_bmlock); |
| 109 | return; | 109 | return; |
| 110 | 110 | ||
| 111 | err_free: | 111 | err_free: |
| 112 | affs_warning(sb,"affs_free_block","Trying to free block %u which is already free", block); | 112 | affs_warning(sb,"affs_free_block","Trying to free block %u which is already free", block); |
| 113 | up(&sbi->s_bmlock); | 113 | mutex_unlock(&sbi->s_bmlock); |
| 114 | return; | 114 | return; |
| 115 | 115 | ||
| 116 | err_bh_read: | 116 | err_bh_read: |
| 117 | affs_error(sb,"affs_free_block","Cannot read bitmap block %u", bm->bm_key); | 117 | affs_error(sb,"affs_free_block","Cannot read bitmap block %u", bm->bm_key); |
| 118 | sbi->s_bmap_bh = NULL; | 118 | sbi->s_bmap_bh = NULL; |
| 119 | sbi->s_last_bmap = ~0; | 119 | sbi->s_last_bmap = ~0; |
| 120 | up(&sbi->s_bmlock); | 120 | mutex_unlock(&sbi->s_bmlock); |
| 121 | return; | 121 | return; |
| 122 | 122 | ||
| 123 | err_range: | 123 | err_range: |
| @@ -168,7 +168,7 @@ affs_alloc_block(struct inode *inode, u32 goal) | |||
| 168 | bmap = blk / sbi->s_bmap_bits; | 168 | bmap = blk / sbi->s_bmap_bits; |
| 169 | bm = &sbi->s_bitmap[bmap]; | 169 | bm = &sbi->s_bitmap[bmap]; |
| 170 | 170 | ||
| 171 | down(&sbi->s_bmlock); | 171 | mutex_lock(&sbi->s_bmlock); |
| 172 | 172 | ||
| 173 | if (bm->bm_free) | 173 | if (bm->bm_free) |
| 174 | goto find_bmap_bit; | 174 | goto find_bmap_bit; |
| @@ -249,7 +249,7 @@ find_bit: | |||
| 249 | mark_buffer_dirty(bh); | 249 | mark_buffer_dirty(bh); |
| 250 | sb->s_dirt = 1; | 250 | sb->s_dirt = 1; |
| 251 | 251 | ||
| 252 | up(&sbi->s_bmlock); | 252 | mutex_unlock(&sbi->s_bmlock); |
| 253 | 253 | ||
| 254 | pr_debug("%d\n", blk); | 254 | pr_debug("%d\n", blk); |
| 255 | return blk; | 255 | return blk; |
| @@ -259,7 +259,7 @@ err_bh_read: | |||
| 259 | sbi->s_bmap_bh = NULL; | 259 | sbi->s_bmap_bh = NULL; |
| 260 | sbi->s_last_bmap = ~0; | 260 | sbi->s_last_bmap = ~0; |
| 261 | err_full: | 261 | err_full: |
| 262 | up(&sbi->s_bmlock); | 262 | mutex_unlock(&sbi->s_bmlock); |
| 263 | pr_debug("failed\n"); | 263 | pr_debug("failed\n"); |
| 264 | return 0; | 264 | return 0; |
| 265 | } | 265 | } |
diff --git a/fs/affs/dir.c b/fs/affs/dir.c index 6e3f282424b0..7b36904dbeac 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c | |||
| @@ -19,6 +19,7 @@ static int affs_readdir(struct file *, void *, filldir_t); | |||
| 19 | 19 | ||
| 20 | const struct file_operations affs_dir_operations = { | 20 | const struct file_operations affs_dir_operations = { |
| 21 | .read = generic_read_dir, | 21 | .read = generic_read_dir, |
| 22 | .llseek = generic_file_llseek, | ||
| 22 | .readdir = affs_readdir, | 23 | .readdir = affs_readdir, |
| 23 | .fsync = file_fsync, | 24 | .fsync = file_fsync, |
| 24 | }; | 25 | }; |
diff --git a/fs/affs/file.c b/fs/affs/file.c index 6eac7bdeec94..1377b1240b6e 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
| @@ -46,8 +46,6 @@ const struct inode_operations affs_file_inode_operations = { | |||
| 46 | static int | 46 | static int |
| 47 | affs_file_open(struct inode *inode, struct file *filp) | 47 | affs_file_open(struct inode *inode, struct file *filp) |
| 48 | { | 48 | { |
| 49 | if (atomic_read(&filp->f_count) != 1) | ||
| 50 | return 0; | ||
| 51 | pr_debug("AFFS: open(%lu,%d)\n", | 49 | pr_debug("AFFS: open(%lu,%d)\n", |
| 52 | inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); | 50 | inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); |
| 53 | atomic_inc(&AFFS_I(inode)->i_opencnt); | 51 | atomic_inc(&AFFS_I(inode)->i_opencnt); |
| @@ -57,8 +55,6 @@ affs_file_open(struct inode *inode, struct file *filp) | |||
| 57 | static int | 55 | static int |
| 58 | affs_file_release(struct inode *inode, struct file *filp) | 56 | affs_file_release(struct inode *inode, struct file *filp) |
| 59 | { | 57 | { |
| 60 | if (atomic_read(&filp->f_count) != 0) | ||
| 61 | return 0; | ||
| 62 | pr_debug("AFFS: release(%lu, %d)\n", | 58 | pr_debug("AFFS: release(%lu, %d)\n", |
| 63 | inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); | 59 | inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt)); |
| 64 | 60 | ||
diff --git a/fs/affs/super.c b/fs/affs/super.c index d214837d5e42..3a89094f93d0 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c | |||
| @@ -90,7 +90,7 @@ static void affs_destroy_inode(struct inode *inode) | |||
| 90 | kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); | 90 | kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static void init_once(struct kmem_cache *cachep, void *foo) | 93 | static void init_once(void *foo) |
| 94 | { | 94 | { |
| 95 | struct affs_inode_info *ei = (struct affs_inode_info *) foo; | 95 | struct affs_inode_info *ei = (struct affs_inode_info *) foo; |
| 96 | 96 | ||
| @@ -290,7 +290,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 290 | if (!sbi) | 290 | if (!sbi) |
| 291 | return -ENOMEM; | 291 | return -ENOMEM; |
| 292 | sb->s_fs_info = sbi; | 292 | sb->s_fs_info = sbi; |
| 293 | init_MUTEX(&sbi->s_bmlock); | 293 | mutex_init(&sbi->s_bmlock); |
| 294 | 294 | ||
| 295 | if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, | 295 | if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, |
| 296 | &blocksize,&sbi->s_prefix, | 296 | &blocksize,&sbi->s_prefix, |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 7102824ba847..3cb6920ff30b 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
| @@ -469,8 +469,6 @@ extern bool afs_cm_incoming_call(struct afs_call *); | |||
| 469 | extern const struct inode_operations afs_dir_inode_operations; | 469 | extern const struct inode_operations afs_dir_inode_operations; |
| 470 | extern const struct file_operations afs_dir_file_operations; | 470 | extern const struct file_operations afs_dir_file_operations; |
| 471 | 471 | ||
| 472 | extern int afs_permission(struct inode *, int, struct nameidata *); | ||
| 473 | |||
| 474 | /* | 472 | /* |
| 475 | * file.c | 473 | * file.c |
| 476 | */ | 474 | */ |
| @@ -605,7 +603,7 @@ extern void afs_clear_permits(struct afs_vnode *); | |||
| 605 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); | 603 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); |
| 606 | extern void afs_zap_permits(struct rcu_head *); | 604 | extern void afs_zap_permits(struct rcu_head *); |
| 607 | extern struct key *afs_request_key(struct afs_cell *); | 605 | extern struct key *afs_request_key(struct afs_cell *); |
| 608 | extern int afs_permission(struct inode *, int, struct nameidata *); | 606 | extern int afs_permission(struct inode *, int); |
| 609 | 607 | ||
| 610 | /* | 608 | /* |
| 611 | * server.c | 609 | * server.c |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 2f5503902c37..78db4953a800 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -232,7 +232,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | mntget(newmnt); | 234 | mntget(newmnt); |
| 235 | err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); | 235 | err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts); |
| 236 | switch (err) { | 236 | switch (err) { |
| 237 | case 0: | 237 | case 0: |
| 238 | path_put(&nd->path); | 238 | path_put(&nd->path); |
diff --git a/fs/afs/security.c b/fs/afs/security.c index 3bcbeceba1bb..3ef504370034 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c | |||
| @@ -284,7 +284,7 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, | |||
| 284 | * - AFS ACLs are attached to directories only, and a file is controlled by its | 284 | * - AFS ACLs are attached to directories only, and a file is controlled by its |
| 285 | * parent directory's ACL | 285 | * parent directory's ACL |
| 286 | */ | 286 | */ |
| 287 | int afs_permission(struct inode *inode, int mask, struct nameidata *nd) | 287 | int afs_permission(struct inode *inode, int mask) |
| 288 | { | 288 | { |
| 289 | struct afs_vnode *vnode = AFS_FS_I(inode); | 289 | struct afs_vnode *vnode = AFS_FS_I(inode); |
| 290 | afs_access_t uninitialized_var(access); | 290 | afs_access_t uninitialized_var(access); |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 7e3faeef6818..250d8c4d66e4 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 28 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
| 29 | 29 | ||
| 30 | static void afs_i_init_once(struct kmem_cache *cachep, void *foo); | 30 | static void afs_i_init_once(void *foo); |
| 31 | static int afs_get_sb(struct file_system_type *fs_type, | 31 | static int afs_get_sb(struct file_system_type *fs_type, |
| 32 | int flags, const char *dev_name, | 32 | int flags, const char *dev_name, |
| 33 | void *data, struct vfsmount *mnt); | 33 | void *data, struct vfsmount *mnt); |
| @@ -449,7 +449,7 @@ static void afs_put_super(struct super_block *sb) | |||
| 449 | /* | 449 | /* |
| 450 | * initialise an inode cache slab element prior to any use | 450 | * initialise an inode cache slab element prior to any use |
| 451 | */ | 451 | */ |
| 452 | static void afs_i_init_once(struct kmem_cache *cachep, void *_vnode) | 452 | static void afs_i_init_once(void *_vnode) |
| 453 | { | 453 | { |
| 454 | struct afs_vnode *vnode = _vnode; | 454 | struct afs_vnode *vnode = _vnode; |
| 455 | 455 | ||
diff --git a/fs/afs/write.c b/fs/afs/write.c index 9a849ad3c489..065b4e10681a 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c | |||
| @@ -404,7 +404,7 @@ static int afs_write_back_from_locked_page(struct afs_writeback *wb, | |||
| 404 | page = pages[loop]; | 404 | page = pages[loop]; |
| 405 | if (page->index > wb->last) | 405 | if (page->index > wb->last) |
| 406 | break; | 406 | break; |
| 407 | if (TestSetPageLocked(page)) | 407 | if (!trylock_page(page)) |
| 408 | break; | 408 | break; |
| 409 | if (!PageDirty(page) || | 409 | if (!PageDirty(page) || |
| 410 | page_private(page) != (unsigned long) wb) { | 410 | page_private(page) != (unsigned long) wb) { |
| @@ -512,8 +512,8 @@ static void aio_fput_routine(struct work_struct *data) | |||
| 512 | */ | 512 | */ |
| 513 | static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | 513 | static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) |
| 514 | { | 514 | { |
| 515 | dprintk(KERN_DEBUG "aio_put(%p): f_count=%d\n", | 515 | dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n", |
| 516 | req, atomic_read(&req->ki_filp->f_count)); | 516 | req, atomic_long_read(&req->ki_filp->f_count)); |
| 517 | 517 | ||
| 518 | assert_spin_locked(&ctx->ctx_lock); | 518 | assert_spin_locked(&ctx->ctx_lock); |
| 519 | 519 | ||
| @@ -528,7 +528,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | |||
| 528 | /* Must be done under the lock to serialise against cancellation. | 528 | /* Must be done under the lock to serialise against cancellation. |
| 529 | * Call this aio_fput as it duplicates fput via the fput_work. | 529 | * Call this aio_fput as it duplicates fput via the fput_work. |
| 530 | */ | 530 | */ |
| 531 | if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) { | 531 | if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) { |
| 532 | get_ioctx(ctx); | 532 | get_ioctx(ctx); |
| 533 | spin_lock(&fput_lock); | 533 | spin_lock(&fput_lock); |
| 534 | list_add(&req->ki_list, &fput_head); | 534 | list_add(&req->ki_list, &fput_head); |
| @@ -586,7 +586,6 @@ static void use_mm(struct mm_struct *mm) | |||
| 586 | struct task_struct *tsk = current; | 586 | struct task_struct *tsk = current; |
| 587 | 587 | ||
| 588 | task_lock(tsk); | 588 | task_lock(tsk); |
| 589 | tsk->flags |= PF_BORROWED_MM; | ||
| 590 | active_mm = tsk->active_mm; | 589 | active_mm = tsk->active_mm; |
| 591 | atomic_inc(&mm->mm_count); | 590 | atomic_inc(&mm->mm_count); |
| 592 | tsk->mm = mm; | 591 | tsk->mm = mm; |
| @@ -610,7 +609,6 @@ static void unuse_mm(struct mm_struct *mm) | |||
| 610 | struct task_struct *tsk = current; | 609 | struct task_struct *tsk = current; |
| 611 | 610 | ||
| 612 | task_lock(tsk); | 611 | task_lock(tsk); |
| 613 | tsk->flags &= ~PF_BORROWED_MM; | ||
| 614 | tsk->mm = NULL; | 612 | tsk->mm = NULL; |
| 615 | /* active_mm is still 'mm' */ | 613 | /* active_mm is still 'mm' */ |
| 616 | enter_lazy_tlb(mm, tsk); | 614 | enter_lazy_tlb(mm, tsk); |
| @@ -51,7 +51,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) | |||
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | /* Check for setting the inode time. */ | 53 | /* Check for setting the inode time. */ |
| 54 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { | 54 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { |
| 55 | if (!is_owner_or_cap(inode)) | 55 | if (!is_owner_or_cap(inode)) |
| 56 | goto error; | 56 | goto error; |
| 57 | } | 57 | } |
| @@ -108,6 +108,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
| 108 | struct timespec now; | 108 | struct timespec now; |
| 109 | unsigned int ia_valid = attr->ia_valid; | 109 | unsigned int ia_valid = attr->ia_valid; |
| 110 | 110 | ||
| 111 | if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { | ||
| 112 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
| 113 | return -EPERM; | ||
| 114 | } | ||
| 115 | |||
| 111 | now = current_fs_time(inode->i_sb); | 116 | now = current_fs_time(inode->i_sb); |
| 112 | 117 | ||
| 113 | attr->ia_ctime = now; | 118 | attr->ia_ctime = now; |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index bcfb2dc0a61b..2a41c2a7fc52 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
| @@ -36,6 +36,7 @@ const struct file_operations autofs4_root_operations = { | |||
| 36 | .release = dcache_dir_close, | 36 | .release = dcache_dir_close, |
| 37 | .read = generic_read_dir, | 37 | .read = generic_read_dir, |
| 38 | .readdir = dcache_readdir, | 38 | .readdir = dcache_readdir, |
| 39 | .llseek = dcache_dir_lseek, | ||
| 39 | .ioctl = autofs4_root_ioctl, | 40 | .ioctl = autofs4_root_ioctl, |
| 40 | }; | 41 | }; |
| 41 | 42 | ||
| @@ -44,6 +45,7 @@ const struct file_operations autofs4_dir_operations = { | |||
| 44 | .release = dcache_dir_close, | 45 | .release = dcache_dir_close, |
| 45 | .read = generic_read_dir, | 46 | .read = generic_read_dir, |
| 46 | .readdir = dcache_readdir, | 47 | .readdir = dcache_readdir, |
| 48 | .llseek = dcache_dir_lseek, | ||
| 47 | }; | 49 | }; |
| 48 | 50 | ||
| 49 | const struct inode_operations autofs4_indirect_root_inode_operations = { | 51 | const struct inode_operations autofs4_indirect_root_inode_operations = { |
diff --git a/fs/bad_inode.c b/fs/bad_inode.c index f1c2ea8342f5..5f1538c03b1b 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c | |||
| @@ -243,8 +243,7 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, | |||
| 243 | return -EIO; | 243 | return -EIO; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | static int bad_inode_permission(struct inode *inode, int mask, | 246 | static int bad_inode_permission(struct inode *inode, int mask) |
| 247 | struct nameidata *nd) | ||
| 248 | { | 247 | { |
| 249 | return -EIO; | 248 | return -EIO; |
| 250 | } | 249 | } |
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index e8717de3bab3..740f53672a8a 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
| @@ -66,6 +66,7 @@ static struct kmem_cache *befs_inode_cachep; | |||
| 66 | static const struct file_operations befs_dir_operations = { | 66 | static const struct file_operations befs_dir_operations = { |
| 67 | .read = generic_read_dir, | 67 | .read = generic_read_dir, |
| 68 | .readdir = befs_readdir, | 68 | .readdir = befs_readdir, |
| 69 | .llseek = generic_file_llseek, | ||
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 71 | static const struct inode_operations befs_dir_inode_operations = { | 72 | static const struct inode_operations befs_dir_inode_operations = { |
| @@ -289,7 +290,7 @@ befs_destroy_inode(struct inode *inode) | |||
| 289 | kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); | 290 | kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); |
| 290 | } | 291 | } |
| 291 | 292 | ||
| 292 | static void init_once(struct kmem_cache *cachep, void *foo) | 293 | static void init_once(void *foo) |
| 293 | { | 294 | { |
| 294 | struct befs_inode_info *bi = (struct befs_inode_info *) foo; | 295 | struct befs_inode_info *bi = (struct befs_inode_info *) foo; |
| 295 | 296 | ||
diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h index 70f5d3a8eede..7109e451abf7 100644 --- a/fs/bfs/bfs.h +++ b/fs/bfs/bfs.h | |||
| @@ -16,8 +16,9 @@ struct bfs_sb_info { | |||
| 16 | unsigned long si_freei; | 16 | unsigned long si_freei; |
| 17 | unsigned long si_lf_eblk; | 17 | unsigned long si_lf_eblk; |
| 18 | unsigned long si_lasti; | 18 | unsigned long si_lasti; |
| 19 | unsigned long * si_imap; | 19 | unsigned long *si_imap; |
| 20 | struct buffer_head * si_sbh; /* buffer header w/superblock */ | 20 | struct buffer_head *si_sbh; /* buffer header w/superblock */ |
| 21 | struct mutex bfs_lock; | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | /* | 24 | /* |
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 034950cb3cbe..ed8feb052df9 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c | |||
| @@ -32,16 +32,17 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir) | |||
| 32 | struct inode *dir = f->f_path.dentry->d_inode; | 32 | struct inode *dir = f->f_path.dentry->d_inode; |
| 33 | struct buffer_head *bh; | 33 | struct buffer_head *bh; |
| 34 | struct bfs_dirent *de; | 34 | struct bfs_dirent *de; |
| 35 | struct bfs_sb_info *info = BFS_SB(dir->i_sb); | ||
| 35 | unsigned int offset; | 36 | unsigned int offset; |
| 36 | int block; | 37 | int block; |
| 37 | 38 | ||
| 38 | lock_kernel(); | 39 | mutex_lock(&info->bfs_lock); |
| 39 | 40 | ||
| 40 | if (f->f_pos & (BFS_DIRENT_SIZE - 1)) { | 41 | if (f->f_pos & (BFS_DIRENT_SIZE - 1)) { |
| 41 | printf("Bad f_pos=%08lx for %s:%08lx\n", | 42 | printf("Bad f_pos=%08lx for %s:%08lx\n", |
| 42 | (unsigned long)f->f_pos, | 43 | (unsigned long)f->f_pos, |
| 43 | dir->i_sb->s_id, dir->i_ino); | 44 | dir->i_sb->s_id, dir->i_ino); |
| 44 | unlock_kernel(); | 45 | mutex_unlock(&info->bfs_lock); |
| 45 | return -EBADF; | 46 | return -EBADF; |
| 46 | } | 47 | } |
| 47 | 48 | ||
| @@ -61,7 +62,7 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir) | |||
| 61 | le16_to_cpu(de->ino), | 62 | le16_to_cpu(de->ino), |
| 62 | DT_UNKNOWN) < 0) { | 63 | DT_UNKNOWN) < 0) { |
| 63 | brelse(bh); | 64 | brelse(bh); |
| 64 | unlock_kernel(); | 65 | mutex_unlock(&info->bfs_lock); |
| 65 | return 0; | 66 | return 0; |
| 66 | } | 67 | } |
| 67 | } | 68 | } |
| @@ -71,7 +72,7 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir) | |||
| 71 | brelse(bh); | 72 | brelse(bh); |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | unlock_kernel(); | 75 | mutex_unlock(&info->bfs_lock); |
| 75 | return 0; | 76 | return 0; |
| 76 | } | 77 | } |
| 77 | 78 | ||
| @@ -95,10 +96,10 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 95 | inode = new_inode(s); | 96 | inode = new_inode(s); |
| 96 | if (!inode) | 97 | if (!inode) |
| 97 | return -ENOSPC; | 98 | return -ENOSPC; |
| 98 | lock_kernel(); | 99 | mutex_lock(&info->bfs_lock); |
| 99 | ino = find_first_zero_bit(info->si_imap, info->si_lasti); | 100 | ino = find_first_zero_bit(info->si_imap, info->si_lasti); |
| 100 | if (ino > info->si_lasti) { | 101 | if (ino > info->si_lasti) { |
| 101 | unlock_kernel(); | 102 | mutex_unlock(&info->bfs_lock); |
| 102 | iput(inode); | 103 | iput(inode); |
| 103 | return -ENOSPC; | 104 | return -ENOSPC; |
| 104 | } | 105 | } |
| @@ -124,11 +125,11 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 124 | inode->i_ino); | 125 | inode->i_ino); |
| 125 | if (err) { | 126 | if (err) { |
| 126 | inode_dec_link_count(inode); | 127 | inode_dec_link_count(inode); |
| 128 | mutex_unlock(&info->bfs_lock); | ||
| 127 | iput(inode); | 129 | iput(inode); |
| 128 | unlock_kernel(); | ||
| 129 | return err; | 130 | return err; |
| 130 | } | 131 | } |
| 131 | unlock_kernel(); | 132 | mutex_unlock(&info->bfs_lock); |
| 132 | d_instantiate(dentry, inode); | 133 | d_instantiate(dentry, inode); |
| 133 | return 0; | 134 | return 0; |
| 134 | } | 135 | } |
| @@ -139,22 +140,23 @@ static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 139 | struct inode *inode = NULL; | 140 | struct inode *inode = NULL; |
| 140 | struct buffer_head *bh; | 141 | struct buffer_head *bh; |
| 141 | struct bfs_dirent *de; | 142 | struct bfs_dirent *de; |
| 143 | struct bfs_sb_info *info = BFS_SB(dir->i_sb); | ||
| 142 | 144 | ||
| 143 | if (dentry->d_name.len > BFS_NAMELEN) | 145 | if (dentry->d_name.len > BFS_NAMELEN) |
| 144 | return ERR_PTR(-ENAMETOOLONG); | 146 | return ERR_PTR(-ENAMETOOLONG); |
| 145 | 147 | ||
| 146 | lock_kernel(); | 148 | mutex_lock(&info->bfs_lock); |
| 147 | bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); | 149 | bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); |
| 148 | if (bh) { | 150 | if (bh) { |
| 149 | unsigned long ino = (unsigned long)le16_to_cpu(de->ino); | 151 | unsigned long ino = (unsigned long)le16_to_cpu(de->ino); |
| 150 | brelse(bh); | 152 | brelse(bh); |
| 151 | inode = bfs_iget(dir->i_sb, ino); | 153 | inode = bfs_iget(dir->i_sb, ino); |
| 152 | if (IS_ERR(inode)) { | 154 | if (IS_ERR(inode)) { |
| 153 | unlock_kernel(); | 155 | mutex_unlock(&info->bfs_lock); |
| 154 | return ERR_CAST(inode); | 156 | return ERR_CAST(inode); |
| 155 | } | 157 | } |
| 156 | } | 158 | } |
| 157 | unlock_kernel(); | 159 | mutex_unlock(&info->bfs_lock); |
| 158 | d_add(dentry, inode); | 160 | d_add(dentry, inode); |
| 159 | return NULL; | 161 | return NULL; |
| 160 | } | 162 | } |
| @@ -163,13 +165,14 @@ static int bfs_link(struct dentry *old, struct inode *dir, | |||
| 163 | struct dentry *new) | 165 | struct dentry *new) |
| 164 | { | 166 | { |
| 165 | struct inode *inode = old->d_inode; | 167 | struct inode *inode = old->d_inode; |
| 168 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | ||
| 166 | int err; | 169 | int err; |
| 167 | 170 | ||
| 168 | lock_kernel(); | 171 | mutex_lock(&info->bfs_lock); |
| 169 | err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, | 172 | err = bfs_add_entry(dir, new->d_name.name, new->d_name.len, |
| 170 | inode->i_ino); | 173 | inode->i_ino); |
| 171 | if (err) { | 174 | if (err) { |
| 172 | unlock_kernel(); | 175 | mutex_unlock(&info->bfs_lock); |
| 173 | return err; | 176 | return err; |
| 174 | } | 177 | } |
| 175 | inc_nlink(inode); | 178 | inc_nlink(inode); |
| @@ -177,19 +180,19 @@ static int bfs_link(struct dentry *old, struct inode *dir, | |||
| 177 | mark_inode_dirty(inode); | 180 | mark_inode_dirty(inode); |
| 178 | atomic_inc(&inode->i_count); | 181 | atomic_inc(&inode->i_count); |
| 179 | d_instantiate(new, inode); | 182 | d_instantiate(new, inode); |
| 180 | unlock_kernel(); | 183 | mutex_unlock(&info->bfs_lock); |
| 181 | return 0; | 184 | return 0; |
| 182 | } | 185 | } |
| 183 | 186 | ||
| 184 | static int bfs_unlink(struct inode *dir, struct dentry *dentry) | 187 | static int bfs_unlink(struct inode *dir, struct dentry *dentry) |
| 185 | { | 188 | { |
| 186 | int error = -ENOENT; | 189 | int error = -ENOENT; |
| 187 | struct inode *inode; | 190 | struct inode *inode = dentry->d_inode; |
| 188 | struct buffer_head *bh; | 191 | struct buffer_head *bh; |
| 189 | struct bfs_dirent *de; | 192 | struct bfs_dirent *de; |
| 193 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | ||
| 190 | 194 | ||
| 191 | inode = dentry->d_inode; | 195 | mutex_lock(&info->bfs_lock); |
| 192 | lock_kernel(); | ||
| 193 | bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); | 196 | bh = bfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); |
| 194 | if (!bh || (le16_to_cpu(de->ino) != inode->i_ino)) | 197 | if (!bh || (le16_to_cpu(de->ino) != inode->i_ino)) |
| 195 | goto out_brelse; | 198 | goto out_brelse; |
| @@ -210,7 +213,7 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 210 | 213 | ||
| 211 | out_brelse: | 214 | out_brelse: |
| 212 | brelse(bh); | 215 | brelse(bh); |
| 213 | unlock_kernel(); | 216 | mutex_unlock(&info->bfs_lock); |
| 214 | return error; | 217 | return error; |
| 215 | } | 218 | } |
| 216 | 219 | ||
| @@ -220,6 +223,7 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 220 | struct inode *old_inode, *new_inode; | 223 | struct inode *old_inode, *new_inode; |
| 221 | struct buffer_head *old_bh, *new_bh; | 224 | struct buffer_head *old_bh, *new_bh; |
| 222 | struct bfs_dirent *old_de, *new_de; | 225 | struct bfs_dirent *old_de, *new_de; |
| 226 | struct bfs_sb_info *info; | ||
| 223 | int error = -ENOENT; | 227 | int error = -ENOENT; |
| 224 | 228 | ||
| 225 | old_bh = new_bh = NULL; | 229 | old_bh = new_bh = NULL; |
| @@ -227,7 +231,9 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 227 | if (S_ISDIR(old_inode->i_mode)) | 231 | if (S_ISDIR(old_inode->i_mode)) |
| 228 | return -EINVAL; | 232 | return -EINVAL; |
| 229 | 233 | ||
| 230 | lock_kernel(); | 234 | info = BFS_SB(old_inode->i_sb); |
| 235 | |||
| 236 | mutex_lock(&info->bfs_lock); | ||
| 231 | old_bh = bfs_find_entry(old_dir, | 237 | old_bh = bfs_find_entry(old_dir, |
| 232 | old_dentry->d_name.name, | 238 | old_dentry->d_name.name, |
| 233 | old_dentry->d_name.len, &old_de); | 239 | old_dentry->d_name.len, &old_de); |
| @@ -264,7 +270,7 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 264 | error = 0; | 270 | error = 0; |
| 265 | 271 | ||
| 266 | end_rename: | 272 | end_rename: |
| 267 | unlock_kernel(); | 273 | mutex_unlock(&info->bfs_lock); |
| 268 | brelse(old_bh); | 274 | brelse(old_bh); |
| 269 | brelse(new_bh); | 275 | brelse(new_bh); |
| 270 | return error; | 276 | return error; |
diff --git a/fs/bfs/file.c b/fs/bfs/file.c index b11e63e8fbcd..6a021265f018 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c | |||
| @@ -99,7 +99,7 @@ static int bfs_get_block(struct inode *inode, sector_t block, | |||
| 99 | return -ENOSPC; | 99 | return -ENOSPC; |
| 100 | 100 | ||
| 101 | /* The rest has to be protected against itself. */ | 101 | /* The rest has to be protected against itself. */ |
| 102 | lock_kernel(); | 102 | mutex_lock(&info->bfs_lock); |
| 103 | 103 | ||
| 104 | /* | 104 | /* |
| 105 | * If the last data block for this file is the last allocated | 105 | * If the last data block for this file is the last allocated |
| @@ -151,7 +151,7 @@ static int bfs_get_block(struct inode *inode, sector_t block, | |||
| 151 | mark_buffer_dirty(sbh); | 151 | mark_buffer_dirty(sbh); |
| 152 | map_bh(bh_result, sb, phys); | 152 | map_bh(bh_result, sb, phys); |
| 153 | out: | 153 | out: |
| 154 | unlock_kernel(); | 154 | mutex_unlock(&info->bfs_lock); |
| 155 | return err; | 155 | return err; |
| 156 | } | 156 | } |
| 157 | 157 | ||
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 8db623838b50..0ed57b5ee012 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c | |||
| @@ -104,6 +104,7 @@ static int bfs_write_inode(struct inode *inode, int unused) | |||
| 104 | struct bfs_inode *di; | 104 | struct bfs_inode *di; |
| 105 | struct buffer_head *bh; | 105 | struct buffer_head *bh; |
| 106 | int block, off; | 106 | int block, off; |
| 107 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | ||
| 107 | 108 | ||
| 108 | dprintf("ino=%08x\n", ino); | 109 | dprintf("ino=%08x\n", ino); |
| 109 | 110 | ||
| @@ -112,13 +113,13 @@ static int bfs_write_inode(struct inode *inode, int unused) | |||
| 112 | return -EIO; | 113 | return -EIO; |
| 113 | } | 114 | } |
| 114 | 115 | ||
| 115 | lock_kernel(); | 116 | mutex_lock(&info->bfs_lock); |
| 116 | block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; | 117 | block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; |
| 117 | bh = sb_bread(inode->i_sb, block); | 118 | bh = sb_bread(inode->i_sb, block); |
| 118 | if (!bh) { | 119 | if (!bh) { |
| 119 | printf("Unable to read inode %s:%08x\n", | 120 | printf("Unable to read inode %s:%08x\n", |
| 120 | inode->i_sb->s_id, ino); | 121 | inode->i_sb->s_id, ino); |
| 121 | unlock_kernel(); | 122 | mutex_unlock(&info->bfs_lock); |
| 122 | return -EIO; | 123 | return -EIO; |
| 123 | } | 124 | } |
| 124 | 125 | ||
| @@ -145,7 +146,7 @@ static int bfs_write_inode(struct inode *inode, int unused) | |||
| 145 | 146 | ||
| 146 | mark_buffer_dirty(bh); | 147 | mark_buffer_dirty(bh); |
| 147 | brelse(bh); | 148 | brelse(bh); |
| 148 | unlock_kernel(); | 149 | mutex_unlock(&info->bfs_lock); |
| 149 | return 0; | 150 | return 0; |
| 150 | } | 151 | } |
| 151 | 152 | ||
| @@ -170,7 +171,7 @@ static void bfs_delete_inode(struct inode *inode) | |||
| 170 | 171 | ||
| 171 | inode->i_size = 0; | 172 | inode->i_size = 0; |
| 172 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | 173 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; |
| 173 | lock_kernel(); | 174 | mutex_lock(&info->bfs_lock); |
| 174 | mark_inode_dirty(inode); | 175 | mark_inode_dirty(inode); |
| 175 | 176 | ||
| 176 | block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; | 177 | block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; |
| @@ -178,7 +179,7 @@ static void bfs_delete_inode(struct inode *inode) | |||
| 178 | if (!bh) { | 179 | if (!bh) { |
| 179 | printf("Unable to read inode %s:%08lx\n", | 180 | printf("Unable to read inode %s:%08lx\n", |
| 180 | inode->i_sb->s_id, ino); | 181 | inode->i_sb->s_id, ino); |
| 181 | unlock_kernel(); | 182 | mutex_unlock(&info->bfs_lock); |
| 182 | return; | 183 | return; |
| 183 | } | 184 | } |
| 184 | off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; | 185 | off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; |
| @@ -204,14 +205,16 @@ static void bfs_delete_inode(struct inode *inode) | |||
| 204 | info->si_lf_eblk = bi->i_sblock - 1; | 205 | info->si_lf_eblk = bi->i_sblock - 1; |
| 205 | mark_buffer_dirty(info->si_sbh); | 206 | mark_buffer_dirty(info->si_sbh); |
| 206 | } | 207 | } |
| 207 | unlock_kernel(); | 208 | mutex_unlock(&info->bfs_lock); |
| 208 | clear_inode(inode); | 209 | clear_inode(inode); |
| 209 | } | 210 | } |
| 210 | 211 | ||
| 211 | static void bfs_put_super(struct super_block *s) | 212 | static void bfs_put_super(struct super_block *s) |
| 212 | { | 213 | { |
| 213 | struct bfs_sb_info *info = BFS_SB(s); | 214 | struct bfs_sb_info *info = BFS_SB(s); |
| 215 | |||
| 214 | brelse(info->si_sbh); | 216 | brelse(info->si_sbh); |
| 217 | mutex_destroy(&info->bfs_lock); | ||
| 215 | kfree(info->si_imap); | 218 | kfree(info->si_imap); |
| 216 | kfree(info); | 219 | kfree(info); |
| 217 | s->s_fs_info = NULL; | 220 | s->s_fs_info = NULL; |
| @@ -236,11 +239,13 @@ static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 236 | 239 | ||
| 237 | static void bfs_write_super(struct super_block *s) | 240 | static void bfs_write_super(struct super_block *s) |
| 238 | { | 241 | { |
| 239 | lock_kernel(); | 242 | struct bfs_sb_info *info = BFS_SB(s); |
| 243 | |||
| 244 | mutex_lock(&info->bfs_lock); | ||
| 240 | if (!(s->s_flags & MS_RDONLY)) | 245 | if (!(s->s_flags & MS_RDONLY)) |
| 241 | mark_buffer_dirty(BFS_SB(s)->si_sbh); | 246 | mark_buffer_dirty(info->si_sbh); |
| 242 | s->s_dirt = 0; | 247 | s->s_dirt = 0; |
| 243 | unlock_kernel(); | 248 | mutex_unlock(&info->bfs_lock); |
| 244 | } | 249 | } |
| 245 | 250 | ||
| 246 | static struct kmem_cache *bfs_inode_cachep; | 251 | static struct kmem_cache *bfs_inode_cachep; |
| @@ -259,7 +264,7 @@ static void bfs_destroy_inode(struct inode *inode) | |||
| 259 | kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); | 264 | kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); |
| 260 | } | 265 | } |
| 261 | 266 | ||
| 262 | static void init_once(struct kmem_cache *cachep, void *foo) | 267 | static void init_once(void *foo) |
| 263 | { | 268 | { |
| 264 | struct bfs_inode_info *bi = foo; | 269 | struct bfs_inode_info *bi = foo; |
| 265 | 270 | ||
| @@ -380,7 +385,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 380 | struct bfs_inode *di; | 385 | struct bfs_inode *di; |
| 381 | int block = (i - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; | 386 | int block = (i - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; |
| 382 | int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; | 387 | int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; |
| 383 | unsigned long sblock, eblock; | 388 | unsigned long eblock; |
| 384 | 389 | ||
| 385 | if (!off) { | 390 | if (!off) { |
| 386 | brelse(bh); | 391 | brelse(bh); |
| @@ -399,7 +404,6 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 399 | set_bit(i, info->si_imap); | 404 | set_bit(i, info->si_imap); |
| 400 | info->si_freeb -= BFS_FILEBLOCKS(di); | 405 | info->si_freeb -= BFS_FILEBLOCKS(di); |
| 401 | 406 | ||
| 402 | sblock = le32_to_cpu(di->i_sblock); | ||
| 403 | eblock = le32_to_cpu(di->i_eblock); | 407 | eblock = le32_to_cpu(di->i_eblock); |
| 404 | if (eblock > info->si_lf_eblk) | 408 | if (eblock > info->si_lf_eblk) |
| 405 | info->si_lf_eblk = eblock; | 409 | info->si_lf_eblk = eblock; |
| @@ -410,6 +414,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 410 | s->s_dirt = 1; | 414 | s->s_dirt = 1; |
| 411 | } | 415 | } |
| 412 | dump_imap("read_super", s); | 416 | dump_imap("read_super", s); |
| 417 | mutex_init(&info->bfs_lock); | ||
| 413 | return 0; | 418 | return 0; |
| 414 | 419 | ||
| 415 | out: | 420 | out: |
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index ba4cddb92f1d..204cfd1d7676 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c | |||
| @@ -444,12 +444,6 @@ beyond_if: | |||
| 444 | regs->gp = ex.a_gpvalue; | 444 | regs->gp = ex.a_gpvalue; |
| 445 | #endif | 445 | #endif |
| 446 | start_thread(regs, ex.a_entry, current->mm->start_stack); | 446 | start_thread(regs, ex.a_entry, current->mm->start_stack); |
| 447 | if (unlikely(current->ptrace & PT_PTRACED)) { | ||
| 448 | if (current->ptrace & PT_TRACE_EXEC) | ||
| 449 | ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); | ||
| 450 | else | ||
| 451 | send_sig(SIGTRAP, current, 0); | ||
| 452 | } | ||
| 453 | return 0; | 447 | return 0; |
| 454 | } | 448 | } |
| 455 | 449 | ||
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 639d2d8b5710..655ed8d30a86 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
| @@ -131,6 +131,15 @@ static int padzero(unsigned long elf_bss) | |||
| 131 | #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) | 131 | #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; }) |
| 132 | #endif | 132 | #endif |
| 133 | 133 | ||
| 134 | #ifndef ELF_BASE_PLATFORM | ||
| 135 | /* | ||
| 136 | * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture. | ||
| 137 | * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value | ||
| 138 | * will be copied to the user stack in the same manner as AT_PLATFORM. | ||
| 139 | */ | ||
| 140 | #define ELF_BASE_PLATFORM NULL | ||
| 141 | #endif | ||
| 142 | |||
| 134 | static int | 143 | static int |
| 135 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | 144 | create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, |
| 136 | unsigned long load_addr, unsigned long interp_load_addr) | 145 | unsigned long load_addr, unsigned long interp_load_addr) |
| @@ -142,7 +151,9 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
| 142 | elf_addr_t __user *envp; | 151 | elf_addr_t __user *envp; |
| 143 | elf_addr_t __user *sp; | 152 | elf_addr_t __user *sp; |
| 144 | elf_addr_t __user *u_platform; | 153 | elf_addr_t __user *u_platform; |
| 154 | elf_addr_t __user *u_base_platform; | ||
| 145 | const char *k_platform = ELF_PLATFORM; | 155 | const char *k_platform = ELF_PLATFORM; |
| 156 | const char *k_base_platform = ELF_BASE_PLATFORM; | ||
| 146 | int items; | 157 | int items; |
| 147 | elf_addr_t *elf_info; | 158 | elf_addr_t *elf_info; |
| 148 | int ei_index = 0; | 159 | int ei_index = 0; |
| @@ -172,6 +183,19 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
| 172 | return -EFAULT; | 183 | return -EFAULT; |
| 173 | } | 184 | } |
| 174 | 185 | ||
| 186 | /* | ||
| 187 | * If this architecture has a "base" platform capability | ||
| 188 | * string, copy it to userspace. | ||
| 189 | */ | ||
| 190 | u_base_platform = NULL; | ||
| 191 | if (k_base_platform) { | ||
| 192 | size_t len = strlen(k_base_platform) + 1; | ||
| 193 | |||
| 194 | u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len); | ||
| 195 | if (__copy_to_user(u_base_platform, k_base_platform, len)) | ||
| 196 | return -EFAULT; | ||
| 197 | } | ||
| 198 | |||
| 175 | /* Create the ELF interpreter info */ | 199 | /* Create the ELF interpreter info */ |
| 176 | elf_info = (elf_addr_t *)current->mm->saved_auxv; | 200 | elf_info = (elf_addr_t *)current->mm->saved_auxv; |
| 177 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ | 201 | /* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */ |
| @@ -209,6 +233,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec, | |||
| 209 | NEW_AUX_ENT(AT_PLATFORM, | 233 | NEW_AUX_ENT(AT_PLATFORM, |
| 210 | (elf_addr_t)(unsigned long)u_platform); | 234 | (elf_addr_t)(unsigned long)u_platform); |
| 211 | } | 235 | } |
| 236 | if (k_base_platform) { | ||
| 237 | NEW_AUX_ENT(AT_BASE_PLATFORM, | ||
| 238 | (elf_addr_t)(unsigned long)u_base_platform); | ||
| 239 | } | ||
| 212 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { | 240 | if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) { |
| 213 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); | 241 | NEW_AUX_ENT(AT_EXECFD, bprm->interp_data); |
| 214 | } | 242 | } |
| @@ -975,12 +1003,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 975 | #endif | 1003 | #endif |
| 976 | 1004 | ||
| 977 | start_thread(regs, elf_entry, bprm->p); | 1005 | start_thread(regs, elf_entry, bprm->p); |
| 978 | if (unlikely(current->ptrace & PT_PTRACED)) { | ||
| 979 | if (current->ptrace & PT_TRACE_EXEC) | ||
| 980 | ptrace_notify ((PTRACE_EVENT_EXEC << 8) | SIGTRAP); | ||
| 981 | else | ||
| 982 | send_sig(SIGTRAP, current, 0); | ||
| 983 | } | ||
| 984 | retval = 0; | 1006 | retval = 0; |
| 985 | out: | 1007 | out: |
| 986 | kfree(loc); | 1008 | kfree(loc); |
| @@ -1478,7 +1500,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
| 1478 | const struct user_regset_view *view = task_user_regset_view(dump_task); | 1500 | const struct user_regset_view *view = task_user_regset_view(dump_task); |
| 1479 | struct elf_thread_core_info *t; | 1501 | struct elf_thread_core_info *t; |
| 1480 | struct elf_prpsinfo *psinfo; | 1502 | struct elf_prpsinfo *psinfo; |
| 1481 | struct task_struct *g, *p; | 1503 | struct core_thread *ct; |
| 1482 | unsigned int i; | 1504 | unsigned int i; |
| 1483 | 1505 | ||
| 1484 | info->size = 0; | 1506 | info->size = 0; |
| @@ -1517,31 +1539,26 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
| 1517 | /* | 1539 | /* |
| 1518 | * Allocate a structure for each thread. | 1540 | * Allocate a structure for each thread. |
| 1519 | */ | 1541 | */ |
| 1520 | rcu_read_lock(); | 1542 | for (ct = &dump_task->mm->core_state->dumper; ct; ct = ct->next) { |
| 1521 | do_each_thread(g, p) | 1543 | t = kzalloc(offsetof(struct elf_thread_core_info, |
| 1522 | if (p->mm == dump_task->mm) { | 1544 | notes[info->thread_notes]), |
| 1523 | t = kzalloc(offsetof(struct elf_thread_core_info, | 1545 | GFP_KERNEL); |
| 1524 | notes[info->thread_notes]), | 1546 | if (unlikely(!t)) |
| 1525 | GFP_ATOMIC); | 1547 | return 0; |
| 1526 | if (unlikely(!t)) { | 1548 | |
| 1527 | rcu_read_unlock(); | 1549 | t->task = ct->task; |
| 1528 | return 0; | 1550 | if (ct->task == dump_task || !info->thread) { |
| 1529 | } | 1551 | t->next = info->thread; |
| 1530 | t->task = p; | 1552 | info->thread = t; |
| 1531 | if (p == dump_task || !info->thread) { | 1553 | } else { |
| 1532 | t->next = info->thread; | 1554 | /* |
| 1533 | info->thread = t; | 1555 | * Make sure to keep the original task at |
| 1534 | } else { | 1556 | * the head of the list. |
| 1535 | /* | 1557 | */ |
| 1536 | * Make sure to keep the original task at | 1558 | t->next = info->thread->next; |
| 1537 | * the head of the list. | 1559 | info->thread->next = t; |
| 1538 | */ | ||
| 1539 | t->next = info->thread->next; | ||
| 1540 | info->thread->next = t; | ||
| 1541 | } | ||
| 1542 | } | 1560 | } |
| 1543 | while_each_thread(g, p); | 1561 | } |
| 1544 | rcu_read_unlock(); | ||
| 1545 | 1562 | ||
| 1546 | /* | 1563 | /* |
| 1547 | * Now fill in each thread's information. | 1564 | * Now fill in each thread's information. |
| @@ -1688,7 +1705,6 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
| 1688 | { | 1705 | { |
| 1689 | #define NUM_NOTES 6 | 1706 | #define NUM_NOTES 6 |
| 1690 | struct list_head *t; | 1707 | struct list_head *t; |
| 1691 | struct task_struct *g, *p; | ||
| 1692 | 1708 | ||
| 1693 | info->notes = NULL; | 1709 | info->notes = NULL; |
| 1694 | info->prstatus = NULL; | 1710 | info->prstatus = NULL; |
| @@ -1720,20 +1736,19 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
| 1720 | 1736 | ||
| 1721 | info->thread_status_size = 0; | 1737 | info->thread_status_size = 0; |
| 1722 | if (signr) { | 1738 | if (signr) { |
| 1739 | struct core_thread *ct; | ||
| 1723 | struct elf_thread_status *ets; | 1740 | struct elf_thread_status *ets; |
| 1724 | rcu_read_lock(); | 1741 | |
| 1725 | do_each_thread(g, p) | 1742 | for (ct = current->mm->core_state->dumper.next; |
| 1726 | if (current->mm == p->mm && current != p) { | 1743 | ct; ct = ct->next) { |
| 1727 | ets = kzalloc(sizeof(*ets), GFP_ATOMIC); | 1744 | ets = kzalloc(sizeof(*ets), GFP_KERNEL); |
| 1728 | if (!ets) { | 1745 | if (!ets) |
| 1729 | rcu_read_unlock(); | 1746 | return 0; |
| 1730 | return 0; | 1747 | |
| 1731 | } | 1748 | ets->thread = ct->task; |
| 1732 | ets->thread = p; | 1749 | list_add(&ets->list, &info->thread_list); |
| 1733 | list_add(&ets->list, &info->thread_list); | 1750 | } |
| 1734 | } | 1751 | |
| 1735 | while_each_thread(g, p); | ||
| 1736 | rcu_read_unlock(); | ||
| 1737 | list_for_each(t, &info->thread_list) { | 1752 | list_for_each(t, &info->thread_list) { |
| 1738 | int sz; | 1753 | int sz; |
| 1739 | 1754 | ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index d051a32e6270..80c1f952ef78 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
| @@ -433,13 +433,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, | |||
| 433 | entryaddr = interp_params.entry_addr ?: exec_params.entry_addr; | 433 | entryaddr = interp_params.entry_addr ?: exec_params.entry_addr; |
| 434 | start_thread(regs, entryaddr, current->mm->start_stack); | 434 | start_thread(regs, entryaddr, current->mm->start_stack); |
| 435 | 435 | ||
| 436 | if (unlikely(current->ptrace & PT_PTRACED)) { | ||
| 437 | if (current->ptrace & PT_TRACE_EXEC) | ||
| 438 | ptrace_notify((PTRACE_EVENT_EXEC << 8) | SIGTRAP); | ||
| 439 | else | ||
| 440 | send_sig(SIGTRAP, current, 0); | ||
| 441 | } | ||
| 442 | |||
| 443 | retval = 0; | 436 | retval = 0; |
| 444 | 437 | ||
| 445 | error: | 438 | error: |
| @@ -477,6 +470,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, | |||
| 477 | char __user *u_platform, *p; | 470 | char __user *u_platform, *p; |
| 478 | long hwcap; | 471 | long hwcap; |
| 479 | int loop; | 472 | int loop; |
| 473 | int nr; /* reset for each csp adjustment */ | ||
| 480 | 474 | ||
| 481 | /* we're going to shovel a whole load of stuff onto the stack */ | 475 | /* we're going to shovel a whole load of stuff onto the stack */ |
| 482 | #ifdef CONFIG_MMU | 476 | #ifdef CONFIG_MMU |
| @@ -549,10 +543,7 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, | |||
| 549 | /* force 16 byte _final_ alignment here for generality */ | 543 | /* force 16 byte _final_ alignment here for generality */ |
| 550 | #define DLINFO_ITEMS 13 | 544 | #define DLINFO_ITEMS 13 |
| 551 | 545 | ||
| 552 | nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0); | 546 | nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH; |
| 553 | #ifdef DLINFO_ARCH_ITEMS | ||
| 554 | nitems += DLINFO_ARCH_ITEMS; | ||
| 555 | #endif | ||
| 556 | 547 | ||
| 557 | csp = sp; | 548 | csp = sp; |
| 558 | sp -= nitems * 2 * sizeof(unsigned long); | 549 | sp -= nitems * 2 * sizeof(unsigned long); |
| @@ -564,39 +555,46 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm, | |||
| 564 | sp -= sp & 15UL; | 555 | sp -= sp & 15UL; |
| 565 | 556 | ||
| 566 | /* put the ELF interpreter info on the stack */ | 557 | /* put the ELF interpreter info on the stack */ |
| 567 | #define NEW_AUX_ENT(nr, id, val) \ | 558 | #define NEW_AUX_ENT(id, val) \ |
| 568 | do { \ | 559 | do { \ |
| 569 | struct { unsigned long _id, _val; } __user *ent; \ | 560 | struct { unsigned long _id, _val; } __user *ent; \ |
| 570 | \ | 561 | \ |
| 571 | ent = (void __user *) csp; \ | 562 | ent = (void __user *) csp; \ |
| 572 | __put_user((id), &ent[nr]._id); \ | 563 | __put_user((id), &ent[nr]._id); \ |
| 573 | __put_user((val), &ent[nr]._val); \ | 564 | __put_user((val), &ent[nr]._val); \ |
| 565 | nr++; \ | ||
| 574 | } while (0) | 566 | } while (0) |
| 575 | 567 | ||
| 568 | nr = 0; | ||
| 576 | csp -= 2 * sizeof(unsigned long); | 569 | csp -= 2 * sizeof(unsigned long); |
| 577 | NEW_AUX_ENT(0, AT_NULL, 0); | 570 | NEW_AUX_ENT(AT_NULL, 0); |
| 578 | if (k_platform) { | 571 | if (k_platform) { |
| 572 | nr = 0; | ||
| 579 | csp -= 2 * sizeof(unsigned long); | 573 | csp -= 2 * sizeof(unsigned long); |
| 580 | NEW_AUX_ENT(0, AT_PLATFORM, | 574 | NEW_AUX_ENT(AT_PLATFORM, |
| 581 | (elf_addr_t) (unsigned long) u_platform); | 575 | (elf_addr_t) (unsigned long) u_platform); |
| 582 | } | 576 | } |
| 583 | 577 | ||
| 578 | nr = 0; | ||
| 584 | csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long); | 579 | csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long); |
| 585 | NEW_AUX_ENT( 0, AT_HWCAP, hwcap); | 580 | NEW_AUX_ENT(AT_HWCAP, hwcap); |
| 586 | NEW_AUX_ENT( 1, AT_PAGESZ, PAGE_SIZE); | 581 | NEW_AUX_ENT(AT_PAGESZ, PAGE_SIZE); |
| 587 | NEW_AUX_ENT( 2, AT_CLKTCK, CLOCKS_PER_SEC); | 582 | NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); |
| 588 | NEW_AUX_ENT( 3, AT_PHDR, exec_params->ph_addr); | 583 | NEW_AUX_ENT(AT_PHDR, exec_params->ph_addr); |
| 589 | NEW_AUX_ENT( 4, AT_PHENT, sizeof(struct elf_phdr)); | 584 | NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); |
| 590 | NEW_AUX_ENT( 5, AT_PHNUM, exec_params->hdr.e_phnum); | 585 | NEW_AUX_ENT(AT_PHNUM, exec_params->hdr.e_phnum); |
| 591 | NEW_AUX_ENT( 6, AT_BASE, interp_params->elfhdr_addr); | 586 | NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr); |
| 592 | NEW_AUX_ENT( 7, AT_FLAGS, 0); | 587 | NEW_AUX_ENT(AT_FLAGS, 0); |
| 593 | NEW_AUX_ENT( 8, AT_ENTRY, exec_params->entry_addr); | 588 | NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr); |
| 594 | NEW_AUX_ENT( 9, AT_UID, (elf_addr_t) current->uid); | 589 | NEW_AUX_ENT(AT_UID, (elf_addr_t) current->uid); |
| 595 | NEW_AUX_ENT(10, AT_EUID, (elf_addr_t) current->euid); | 590 | NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid); |
| 596 | NEW_AUX_ENT(11, AT_GID, (elf_addr_t) current->gid); | 591 | NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid); |
| 597 | NEW_AUX_ENT(12, AT_EGID, (elf_addr_t) current->egid); | 592 | NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid); |
| 598 | 593 | ||
| 599 | #ifdef ARCH_DLINFO | 594 | #ifdef ARCH_DLINFO |
| 595 | nr = 0; | ||
| 596 | csp -= AT_VECTOR_SIZE_ARCH * 2 * sizeof(unsigned long); | ||
| 597 | |||
| 600 | /* ARCH_DLINFO must come last so platform specific code can enforce | 598 | /* ARCH_DLINFO must come last so platform specific code can enforce |
| 601 | * special alignment requirements on the AUXV if necessary (eg. PPC). | 599 | * special alignment requirements on the AUXV if necessary (eg. PPC). |
| 602 | */ | 600 | */ |
| @@ -1573,7 +1571,6 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, | |||
| 1573 | struct memelfnote *notes = NULL; | 1571 | struct memelfnote *notes = NULL; |
| 1574 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ | 1572 | struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ |
| 1575 | struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ | 1573 | struct elf_prpsinfo *psinfo = NULL; /* NT_PRPSINFO */ |
| 1576 | struct task_struct *g, *p; | ||
| 1577 | LIST_HEAD(thread_list); | 1574 | LIST_HEAD(thread_list); |
| 1578 | struct list_head *t; | 1575 | struct list_head *t; |
| 1579 | elf_fpregset_t *fpu = NULL; | 1576 | elf_fpregset_t *fpu = NULL; |
| @@ -1622,20 +1619,19 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, | |||
| 1622 | #endif | 1619 | #endif |
| 1623 | 1620 | ||
| 1624 | if (signr) { | 1621 | if (signr) { |
| 1622 | struct core_thread *ct; | ||
| 1625 | struct elf_thread_status *tmp; | 1623 | struct elf_thread_status *tmp; |
| 1626 | rcu_read_lock(); | 1624 | |
| 1627 | do_each_thread(g,p) | 1625 | for (ct = current->mm->core_state->dumper.next; |
| 1628 | if (current->mm == p->mm && current != p) { | 1626 | ct; ct = ct->next) { |
| 1629 | tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC); | 1627 | tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); |
| 1630 | if (!tmp) { | 1628 | if (!tmp) |
| 1631 | rcu_read_unlock(); | 1629 | goto cleanup; |
| 1632 | goto cleanup; | 1630 | |
| 1633 | } | 1631 | tmp->thread = ct->task; |
| 1634 | tmp->thread = p; | 1632 | list_add(&tmp->list, &thread_list); |
| 1635 | list_add(&tmp->list, &thread_list); | 1633 | } |
| 1636 | } | 1634 | |
| 1637 | while_each_thread(g,p); | ||
| 1638 | rcu_read_unlock(); | ||
| 1639 | list_for_each(t, &thread_list) { | 1635 | list_for_each(t, &thread_list) { |
| 1640 | struct elf_thread_status *tmp; | 1636 | struct elf_thread_status *tmp; |
| 1641 | int sz; | 1637 | int sz; |
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 2cb1acda3a82..dfc0197905ca 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
| @@ -914,15 +914,14 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 914 | /* Stash our initial stack pointer into the mm structure */ | 914 | /* Stash our initial stack pointer into the mm structure */ |
| 915 | current->mm->start_stack = (unsigned long )sp; | 915 | current->mm->start_stack = (unsigned long )sp; |
| 916 | 916 | ||
| 917 | 917 | #ifdef FLAT_PLAT_INIT | |
| 918 | FLAT_PLAT_INIT(regs); | ||
| 919 | #endif | ||
| 918 | DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n", | 920 | DBG_FLT("start_thread(regs=0x%x, entry=0x%x, start_stack=0x%x)\n", |
| 919 | (int)regs, (int)start_addr, (int)current->mm->start_stack); | 921 | (int)regs, (int)start_addr, (int)current->mm->start_stack); |
| 920 | 922 | ||
| 921 | start_thread(regs, start_addr, current->mm->start_stack); | 923 | start_thread(regs, start_addr, current->mm->start_stack); |
| 922 | 924 | ||
| 923 | if (current->ptrace & PT_PTRACED) | ||
| 924 | send_sig(SIGTRAP, current, 0); | ||
| 925 | |||
| 926 | return 0; | 925 | return 0; |
| 927 | } | 926 | } |
| 928 | 927 | ||
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 756205314c24..8d7e88e02e0f 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
| @@ -120,8 +120,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 120 | if (bprm->misc_bang) | 120 | if (bprm->misc_bang) |
| 121 | goto _ret; | 121 | goto _ret; |
| 122 | 122 | ||
| 123 | bprm->misc_bang = 1; | ||
| 124 | |||
| 125 | /* to keep locking time low, we copy the interpreter string */ | 123 | /* to keep locking time low, we copy the interpreter string */ |
| 126 | read_lock(&entries_lock); | 124 | read_lock(&entries_lock); |
| 127 | fmt = check_file(bprm); | 125 | fmt = check_file(bprm); |
| @@ -199,6 +197,8 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) | |||
| 199 | if (retval < 0) | 197 | if (retval < 0) |
| 200 | goto _error; | 198 | goto _error; |
| 201 | 199 | ||
| 200 | bprm->misc_bang = 1; | ||
| 201 | |||
| 202 | retval = search_binary_handler (bprm, regs); | 202 | retval = search_binary_handler (bprm, regs); |
| 203 | if (retval < 0) | 203 | if (retval < 0) |
| 204 | goto _error; | 204 | goto _error; |
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index fdc36bfd6a7b..68be580ba289 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c | |||
| @@ -274,8 +274,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) | |||
| 274 | map_hpux_gateway_page(current,current->mm); | 274 | map_hpux_gateway_page(current,current->mm); |
| 275 | 275 | ||
| 276 | start_thread_som(regs, som_entry, bprm->p); | 276 | start_thread_som(regs, som_entry, bprm->p); |
| 277 | if (current->ptrace & PT_PTRACED) | ||
| 278 | send_sig(SIGTRAP, current, 0); | ||
| 279 | return 0; | 277 | return 0; |
| 280 | 278 | ||
| 281 | /* error cleanup */ | 279 | /* error cleanup */ |
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 63e2ee63058d..c3e174b35fe6 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c | |||
| @@ -705,7 +705,6 @@ void __init bio_integrity_init_slab(void) | |||
| 705 | bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, | 705 | bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, |
| 706 | SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 706 | SLAB_HWCACHE_ALIGN|SLAB_PANIC); |
| 707 | } | 707 | } |
| 708 | EXPORT_SYMBOL(bio_integrity_init_slab); | ||
| 709 | 708 | ||
| 710 | static int __init integrity_init(void) | 709 | static int __init integrity_init(void) |
| 711 | { | 710 | { |
| @@ -77,11 +77,8 @@ struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct | |||
| 77 | */ | 77 | */ |
| 78 | 78 | ||
| 79 | bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask); | 79 | bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask); |
| 80 | if (bvl) { | 80 | if (bvl) |
| 81 | struct biovec_slab *bp = bvec_slabs + *idx; | 81 | memset(bvl, 0, bvec_nr_vecs(*idx) * sizeof(struct bio_vec)); |
| 82 | |||
| 83 | memset(bvl, 0, bp->nr_vecs * sizeof(struct bio_vec)); | ||
| 84 | } | ||
| 85 | 82 | ||
| 86 | return bvl; | 83 | return bvl; |
| 87 | } | 84 | } |
| @@ -149,7 +146,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs) | |||
| 149 | goto out; | 146 | goto out; |
| 150 | } | 147 | } |
| 151 | bio->bi_flags |= idx << BIO_POOL_OFFSET; | 148 | bio->bi_flags |= idx << BIO_POOL_OFFSET; |
| 152 | bio->bi_max_vecs = bvec_slabs[idx].nr_vecs; | 149 | bio->bi_max_vecs = bvec_nr_vecs(idx); |
| 153 | } | 150 | } |
| 154 | bio->bi_io_vec = bvl; | 151 | bio->bi_io_vec = bvl; |
| 155 | } | 152 | } |
| @@ -472,20 +469,21 @@ static void bio_free_map_data(struct bio_map_data *bmd) | |||
| 472 | kfree(bmd); | 469 | kfree(bmd); |
| 473 | } | 470 | } |
| 474 | 471 | ||
| 475 | static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count) | 472 | static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count, |
| 473 | gfp_t gfp_mask) | ||
| 476 | { | 474 | { |
| 477 | struct bio_map_data *bmd = kmalloc(sizeof(*bmd), GFP_KERNEL); | 475 | struct bio_map_data *bmd = kmalloc(sizeof(*bmd), gfp_mask); |
| 478 | 476 | ||
| 479 | if (!bmd) | 477 | if (!bmd) |
| 480 | return NULL; | 478 | return NULL; |
| 481 | 479 | ||
| 482 | bmd->iovecs = kmalloc(sizeof(struct bio_vec) * nr_segs, GFP_KERNEL); | 480 | bmd->iovecs = kmalloc(sizeof(struct bio_vec) * nr_segs, gfp_mask); |
| 483 | if (!bmd->iovecs) { | 481 | if (!bmd->iovecs) { |
| 484 | kfree(bmd); | 482 | kfree(bmd); |
| 485 | return NULL; | 483 | return NULL; |
| 486 | } | 484 | } |
| 487 | 485 | ||
| 488 | bmd->sgvecs = kmalloc(sizeof(struct sg_iovec) * iov_count, GFP_KERNEL); | 486 | bmd->sgvecs = kmalloc(sizeof(struct sg_iovec) * iov_count, gfp_mask); |
| 489 | if (bmd->sgvecs) | 487 | if (bmd->sgvecs) |
| 490 | return bmd; | 488 | return bmd; |
| 491 | 489 | ||
| @@ -494,8 +492,8 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count) | |||
| 494 | return NULL; | 492 | return NULL; |
| 495 | } | 493 | } |
| 496 | 494 | ||
| 497 | static int __bio_copy_iov(struct bio *bio, struct sg_iovec *iov, int iov_count, | 495 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, |
| 498 | int uncopy) | 496 | struct sg_iovec *iov, int iov_count, int uncopy) |
| 499 | { | 497 | { |
| 500 | int ret = 0, i; | 498 | int ret = 0, i; |
| 501 | struct bio_vec *bvec; | 499 | struct bio_vec *bvec; |
| @@ -505,7 +503,7 @@ static int __bio_copy_iov(struct bio *bio, struct sg_iovec *iov, int iov_count, | |||
| 505 | 503 | ||
| 506 | __bio_for_each_segment(bvec, bio, i, 0) { | 504 | __bio_for_each_segment(bvec, bio, i, 0) { |
| 507 | char *bv_addr = page_address(bvec->bv_page); | 505 | char *bv_addr = page_address(bvec->bv_page); |
| 508 | unsigned int bv_len = bvec->bv_len; | 506 | unsigned int bv_len = iovecs[i].bv_len; |
| 509 | 507 | ||
| 510 | while (bv_len && iov_idx < iov_count) { | 508 | while (bv_len && iov_idx < iov_count) { |
| 511 | unsigned int bytes; | 509 | unsigned int bytes; |
| @@ -557,7 +555,7 @@ int bio_uncopy_user(struct bio *bio) | |||
| 557 | struct bio_map_data *bmd = bio->bi_private; | 555 | struct bio_map_data *bmd = bio->bi_private; |
| 558 | int ret; | 556 | int ret; |
| 559 | 557 | ||
| 560 | ret = __bio_copy_iov(bio, bmd->sgvecs, bmd->nr_sgvecs, 1); | 558 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, bmd->nr_sgvecs, 1); |
| 561 | 559 | ||
| 562 | bio_free_map_data(bmd); | 560 | bio_free_map_data(bmd); |
| 563 | bio_put(bio); | 561 | bio_put(bio); |
| @@ -599,7 +597,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, struct sg_iovec *iov, | |||
| 599 | len += iov[i].iov_len; | 597 | len += iov[i].iov_len; |
| 600 | } | 598 | } |
| 601 | 599 | ||
| 602 | bmd = bio_alloc_map_data(nr_pages, iov_count); | 600 | bmd = bio_alloc_map_data(nr_pages, iov_count, GFP_KERNEL); |
| 603 | if (!bmd) | 601 | if (!bmd) |
| 604 | return ERR_PTR(-ENOMEM); | 602 | return ERR_PTR(-ENOMEM); |
| 605 | 603 | ||
| @@ -636,7 +634,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, struct sg_iovec *iov, | |||
| 636 | * success | 634 | * success |
| 637 | */ | 635 | */ |
| 638 | if (!write_to_vm) { | 636 | if (!write_to_vm) { |
| 639 | ret = __bio_copy_iov(bio, iov, iov_count, 0); | 637 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0); |
| 640 | if (ret) | 638 | if (ret) |
| 641 | goto cleanup; | 639 | goto cleanup; |
| 642 | } | 640 | } |
| @@ -721,12 +719,8 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, | |||
| 721 | const int local_nr_pages = end - start; | 719 | const int local_nr_pages = end - start; |
| 722 | const int page_limit = cur_page + local_nr_pages; | 720 | const int page_limit = cur_page + local_nr_pages; |
| 723 | 721 | ||
| 724 | down_read(¤t->mm->mmap_sem); | 722 | ret = get_user_pages_fast(uaddr, local_nr_pages, |
| 725 | ret = get_user_pages(current, current->mm, uaddr, | 723 | write_to_vm, &pages[cur_page]); |
| 726 | local_nr_pages, | ||
| 727 | write_to_vm, 0, &pages[cur_page], NULL); | ||
| 728 | up_read(¤t->mm->mmap_sem); | ||
| 729 | |||
| 730 | if (ret < local_nr_pages) { | 724 | if (ret < local_nr_pages) { |
| 731 | ret = -EFAULT; | 725 | ret = -EFAULT; |
| 732 | goto out_unmap; | 726 | goto out_unmap; |
| @@ -949,19 +943,22 @@ static void bio_copy_kern_endio(struct bio *bio, int err) | |||
| 949 | { | 943 | { |
| 950 | struct bio_vec *bvec; | 944 | struct bio_vec *bvec; |
| 951 | const int read = bio_data_dir(bio) == READ; | 945 | const int read = bio_data_dir(bio) == READ; |
| 952 | char *p = bio->bi_private; | 946 | struct bio_map_data *bmd = bio->bi_private; |
| 953 | int i; | 947 | int i; |
| 948 | char *p = bmd->sgvecs[0].iov_base; | ||
| 954 | 949 | ||
| 955 | __bio_for_each_segment(bvec, bio, i, 0) { | 950 | __bio_for_each_segment(bvec, bio, i, 0) { |
| 956 | char *addr = page_address(bvec->bv_page); | 951 | char *addr = page_address(bvec->bv_page); |
| 952 | int len = bmd->iovecs[i].bv_len; | ||
| 957 | 953 | ||
| 958 | if (read && !err) | 954 | if (read && !err) |
| 959 | memcpy(p, addr, bvec->bv_len); | 955 | memcpy(p, addr, len); |
| 960 | 956 | ||
| 961 | __free_page(bvec->bv_page); | 957 | __free_page(bvec->bv_page); |
| 962 | p += bvec->bv_len; | 958 | p += len; |
| 963 | } | 959 | } |
| 964 | 960 | ||
| 961 | bio_free_map_data(bmd); | ||
| 965 | bio_put(bio); | 962 | bio_put(bio); |
| 966 | } | 963 | } |
| 967 | 964 | ||
| @@ -985,11 +982,21 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, | |||
| 985 | const int nr_pages = end - start; | 982 | const int nr_pages = end - start; |
| 986 | struct bio *bio; | 983 | struct bio *bio; |
| 987 | struct bio_vec *bvec; | 984 | struct bio_vec *bvec; |
| 985 | struct bio_map_data *bmd; | ||
| 988 | int i, ret; | 986 | int i, ret; |
| 987 | struct sg_iovec iov; | ||
| 989 | 988 | ||
| 989 | iov.iov_base = data; | ||
| 990 | iov.iov_len = len; | ||
| 991 | |||
| 992 | bmd = bio_alloc_map_data(nr_pages, 1, gfp_mask); | ||
| 993 | if (!bmd) | ||
| 994 | return ERR_PTR(-ENOMEM); | ||
| 995 | |||
| 996 | ret = -ENOMEM; | ||
| 990 | bio = bio_alloc(gfp_mask, nr_pages); | 997 | bio = bio_alloc(gfp_mask, nr_pages); |
| 991 | if (!bio) | 998 | if (!bio) |
| 992 | return ERR_PTR(-ENOMEM); | 999 | goto out_bmd; |
| 993 | 1000 | ||
| 994 | while (len) { | 1001 | while (len) { |
| 995 | struct page *page; | 1002 | struct page *page; |
| @@ -1023,14 +1030,18 @@ struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, | |||
| 1023 | } | 1030 | } |
| 1024 | } | 1031 | } |
| 1025 | 1032 | ||
| 1026 | bio->bi_private = data; | 1033 | bio->bi_private = bmd; |
| 1027 | bio->bi_end_io = bio_copy_kern_endio; | 1034 | bio->bi_end_io = bio_copy_kern_endio; |
| 1035 | |||
| 1036 | bio_set_map_data(bmd, bio, &iov, 1); | ||
| 1028 | return bio; | 1037 | return bio; |
| 1029 | cleanup: | 1038 | cleanup: |
| 1030 | bio_for_each_segment(bvec, bio, i) | 1039 | bio_for_each_segment(bvec, bio, i) |
| 1031 | __free_page(bvec->bv_page); | 1040 | __free_page(bvec->bv_page); |
| 1032 | 1041 | ||
| 1033 | bio_put(bio); | 1042 | bio_put(bio); |
| 1043 | out_bmd: | ||
| 1044 | bio_free_map_data(bmd); | ||
| 1034 | 1045 | ||
| 1035 | return ERR_PTR(ret); | 1046 | return ERR_PTR(ret); |
| 1036 | } | 1047 | } |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 10d8a0aa871a..aff54219e049 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -271,7 +271,7 @@ static void bdev_destroy_inode(struct inode *inode) | |||
| 271 | kmem_cache_free(bdev_cachep, bdi); | 271 | kmem_cache_free(bdev_cachep, bdi); |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | static void init_once(struct kmem_cache * cachep, void *foo) | 274 | static void init_once(void *foo) |
| 275 | { | 275 | { |
| 276 | struct bdev_inode *ei = (struct bdev_inode *) foo; | 276 | struct bdev_inode *ei = (struct bdev_inode *) foo; |
| 277 | struct block_device *bdev = &ei->bdev; | 277 | struct block_device *bdev = &ei->bdev; |
| @@ -941,8 +941,10 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part) | |||
| 941 | * hooks: /n/, see "layering violations". | 941 | * hooks: /n/, see "layering violations". |
| 942 | */ | 942 | */ |
| 943 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); | 943 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); |
| 944 | if (ret != 0) | 944 | if (ret != 0) { |
| 945 | bdput(bdev); | ||
| 945 | return ret; | 946 | return ret; |
| 947 | } | ||
| 946 | 948 | ||
| 947 | ret = -ENXIO; | 949 | ret = -ENXIO; |
| 948 | file->f_mapping = bdev->bd_inode->i_mapping; | 950 | file->f_mapping = bdev->bd_inode->i_mapping; |
| @@ -1234,6 +1236,7 @@ fail: | |||
| 1234 | bdev = ERR_PTR(error); | 1236 | bdev = ERR_PTR(error); |
| 1235 | goto out; | 1237 | goto out; |
| 1236 | } | 1238 | } |
| 1239 | EXPORT_SYMBOL(lookup_bdev); | ||
| 1237 | 1240 | ||
| 1238 | /** | 1241 | /** |
| 1239 | * open_bdev_excl - open a block device by name and set it up for use | 1242 | * open_bdev_excl - open a block device by name and set it up for use |
diff --git a/fs/buffer.c b/fs/buffer.c index d48caee12e2a..ac78d4c19b3b 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -580,7 +580,7 @@ EXPORT_SYMBOL(mark_buffer_async_write); | |||
| 580 | /* | 580 | /* |
| 581 | * The buffer's backing address_space's private_lock must be held | 581 | * The buffer's backing address_space's private_lock must be held |
| 582 | */ | 582 | */ |
| 583 | static inline void __remove_assoc_queue(struct buffer_head *bh) | 583 | static void __remove_assoc_queue(struct buffer_head *bh) |
| 584 | { | 584 | { |
| 585 | list_del_init(&bh->b_assoc_buffers); | 585 | list_del_init(&bh->b_assoc_buffers); |
| 586 | WARN_ON(!bh->b_assoc_map); | 586 | WARN_ON(!bh->b_assoc_map); |
| @@ -706,7 +706,7 @@ static int __set_page_dirty(struct page *page, | |||
| 706 | if (TestSetPageDirty(page)) | 706 | if (TestSetPageDirty(page)) |
| 707 | return 0; | 707 | return 0; |
| 708 | 708 | ||
| 709 | write_lock_irq(&mapping->tree_lock); | 709 | spin_lock_irq(&mapping->tree_lock); |
| 710 | if (page->mapping) { /* Race with truncate? */ | 710 | if (page->mapping) { /* Race with truncate? */ |
| 711 | WARN_ON_ONCE(warn && !PageUptodate(page)); | 711 | WARN_ON_ONCE(warn && !PageUptodate(page)); |
| 712 | 712 | ||
| @@ -719,7 +719,7 @@ static int __set_page_dirty(struct page *page, | |||
| 719 | radix_tree_tag_set(&mapping->page_tree, | 719 | radix_tree_tag_set(&mapping->page_tree, |
| 720 | page_index(page), PAGECACHE_TAG_DIRTY); | 720 | page_index(page), PAGECACHE_TAG_DIRTY); |
| 721 | } | 721 | } |
| 722 | write_unlock_irq(&mapping->tree_lock); | 722 | spin_unlock_irq(&mapping->tree_lock); |
| 723 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | 723 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); |
| 724 | 724 | ||
| 725 | return 1; | 725 | return 1; |
| @@ -1214,8 +1214,7 @@ void __brelse(struct buffer_head * buf) | |||
| 1214 | put_bh(buf); | 1214 | put_bh(buf); |
| 1215 | return; | 1215 | return; |
| 1216 | } | 1216 | } |
| 1217 | printk(KERN_ERR "VFS: brelse: Trying to free free buffer\n"); | 1217 | WARN(1, KERN_ERR "VFS: brelse: Trying to free free buffer\n"); |
| 1218 | WARN_ON(1); | ||
| 1219 | } | 1218 | } |
| 1220 | 1219 | ||
| 1221 | /* | 1220 | /* |
| @@ -1721,7 +1720,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, | |||
| 1721 | */ | 1720 | */ |
| 1722 | if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { | 1721 | if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { |
| 1723 | lock_buffer(bh); | 1722 | lock_buffer(bh); |
| 1724 | } else if (test_set_buffer_locked(bh)) { | 1723 | } else if (!trylock_buffer(bh)) { |
| 1725 | redirty_page_for_writepage(wbc, page); | 1724 | redirty_page_for_writepage(wbc, page); |
| 1726 | continue; | 1725 | continue; |
| 1727 | } | 1726 | } |
| @@ -2097,6 +2096,52 @@ int generic_write_end(struct file *file, struct address_space *mapping, | |||
| 2097 | EXPORT_SYMBOL(generic_write_end); | 2096 | EXPORT_SYMBOL(generic_write_end); |
| 2098 | 2097 | ||
| 2099 | /* | 2098 | /* |
| 2099 | * block_is_partially_uptodate checks whether buffers within a page are | ||
| 2100 | * uptodate or not. | ||
| 2101 | * | ||
| 2102 | * Returns true if all buffers which correspond to a file portion | ||
| 2103 | * we want to read are uptodate. | ||
| 2104 | */ | ||
| 2105 | int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc, | ||
| 2106 | unsigned long from) | ||
| 2107 | { | ||
| 2108 | struct inode *inode = page->mapping->host; | ||
| 2109 | unsigned block_start, block_end, blocksize; | ||
| 2110 | unsigned to; | ||
| 2111 | struct buffer_head *bh, *head; | ||
| 2112 | int ret = 1; | ||
| 2113 | |||
| 2114 | if (!page_has_buffers(page)) | ||
| 2115 | return 0; | ||
| 2116 | |||
| 2117 | blocksize = 1 << inode->i_blkbits; | ||
| 2118 | to = min_t(unsigned, PAGE_CACHE_SIZE - from, desc->count); | ||
| 2119 | to = from + to; | ||
| 2120 | if (from < blocksize && to > PAGE_CACHE_SIZE - blocksize) | ||
| 2121 | return 0; | ||
| 2122 | |||
| 2123 | head = page_buffers(page); | ||
| 2124 | bh = head; | ||
| 2125 | block_start = 0; | ||
| 2126 | do { | ||
| 2127 | block_end = block_start + blocksize; | ||
| 2128 | if (block_end > from && block_start < to) { | ||
| 2129 | if (!buffer_uptodate(bh)) { | ||
| 2130 | ret = 0; | ||
| 2131 | break; | ||
| 2132 | } | ||
| 2133 | if (block_end >= to) | ||
| 2134 | break; | ||
| 2135 | } | ||
| 2136 | block_start = block_end; | ||
| 2137 | bh = bh->b_this_page; | ||
| 2138 | } while (bh != head); | ||
| 2139 | |||
| 2140 | return ret; | ||
| 2141 | } | ||
| 2142 | EXPORT_SYMBOL(block_is_partially_uptodate); | ||
| 2143 | |||
| 2144 | /* | ||
| 2100 | * Generic "read page" function for block devices that have the normal | 2145 | * Generic "read page" function for block devices that have the normal |
| 2101 | * get_block functionality. This is most of the block device filesystems. | 2146 | * get_block functionality. This is most of the block device filesystems. |
| 2102 | * Reads the page asynchronously --- the unlock_buffer() and | 2147 | * Reads the page asynchronously --- the unlock_buffer() and |
| @@ -2881,14 +2926,17 @@ int submit_bh(int rw, struct buffer_head * bh) | |||
| 2881 | BUG_ON(!buffer_mapped(bh)); | 2926 | BUG_ON(!buffer_mapped(bh)); |
| 2882 | BUG_ON(!bh->b_end_io); | 2927 | BUG_ON(!bh->b_end_io); |
| 2883 | 2928 | ||
| 2884 | if (buffer_ordered(bh) && (rw == WRITE)) | 2929 | /* |
| 2885 | rw = WRITE_BARRIER; | 2930 | * Mask in barrier bit for a write (could be either a WRITE or a |
| 2931 | * WRITE_SYNC | ||
| 2932 | */ | ||
| 2933 | if (buffer_ordered(bh) && (rw & WRITE)) | ||
| 2934 | rw |= WRITE_BARRIER; | ||
| 2886 | 2935 | ||
| 2887 | /* | 2936 | /* |
| 2888 | * Only clear out a write error when rewriting, should this | 2937 | * Only clear out a write error when rewriting |
| 2889 | * include WRITE_SYNC as well? | ||
| 2890 | */ | 2938 | */ |
| 2891 | if (test_set_buffer_req(bh) && (rw == WRITE || rw == WRITE_BARRIER)) | 2939 | if (test_set_buffer_req(bh) && (rw & WRITE)) |
| 2892 | clear_buffer_write_io_error(bh); | 2940 | clear_buffer_write_io_error(bh); |
| 2893 | 2941 | ||
| 2894 | /* | 2942 | /* |
| @@ -2955,7 +3003,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) | |||
| 2955 | 3003 | ||
| 2956 | if (rw == SWRITE || rw == SWRITE_SYNC) | 3004 | if (rw == SWRITE || rw == SWRITE_SYNC) |
| 2957 | lock_buffer(bh); | 3005 | lock_buffer(bh); |
| 2958 | else if (test_set_buffer_locked(bh)) | 3006 | else if (!trylock_buffer(bh)) |
| 2959 | continue; | 3007 | continue; |
| 2960 | 3008 | ||
| 2961 | if (rw == WRITE || rw == SWRITE || rw == SWRITE_SYNC) { | 3009 | if (rw == WRITE || rw == SWRITE || rw == SWRITE_SYNC) { |
| @@ -3272,7 +3320,7 @@ int bh_submit_read(struct buffer_head *bh) | |||
| 3272 | EXPORT_SYMBOL(bh_submit_read); | 3320 | EXPORT_SYMBOL(bh_submit_read); |
| 3273 | 3321 | ||
| 3274 | static void | 3322 | static void |
| 3275 | init_buffer_head(struct kmem_cache *cachep, void *data) | 3323 | init_buffer_head(void *data) |
| 3276 | { | 3324 | { |
| 3277 | struct buffer_head *bh = data; | 3325 | struct buffer_head *bh = data; |
| 3278 | 3326 | ||
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 1f3465201fdf..06e521a945c3 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,3 +1,19 @@ | |||
| 1 | Version 1.54 | ||
| 2 | ------------ | ||
| 3 | Fix premature write failure on congested networks (we would give up | ||
| 4 | on EAGAIN from the socket too quickly on large writes). | ||
| 5 | Cifs_mkdir and cifs_create now respect the setgid bit on parent dir. | ||
| 6 | Fix endian problems in acl (mode from/to cifs acl) on bigendian | ||
| 7 | architectures. Fix problems with preserving timestamps on copying open | ||
| 8 | files (e.g. "cp -a") to Windows servers. For mkdir and create honor setgid bit | ||
| 9 | on parent directory when server supports Unix Extensions but not POSIX | ||
| 10 | create. Update cifs.upcall version to handle new Kerberos sec flags | ||
| 11 | (this requires update of cifs.upcall program from Samba). Fix memory leak | ||
| 12 | on dns_upcall (resolving DFS referralls). Fix plain text password | ||
| 13 | authentication (requires setting SecurityFlags to 0x30030 to enable | ||
| 14 | lanman and plain text though). Fix writes to be at correct offset when | ||
| 15 | file is open with O_APPEND and file is on a directio (forcediretio) mount. | ||
| 16 | |||
| 1 | Version 1.53 | 17 | Version 1.53 |
| 2 | ------------ | 18 | ------------ |
| 3 | DFS support added (Microsoft Distributed File System client support needed | 19 | DFS support added (Microsoft Distributed File System client support needed |
diff --git a/fs/cifs/README b/fs/cifs/README index 2bd6fe556f88..bd2343d4c6a6 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -542,10 +542,20 @@ SecurityFlags Flags which control security negotiation and | |||
| 542 | hashing mechanisms (as "must use") on the other hand | 542 | hashing mechanisms (as "must use") on the other hand |
| 543 | does not make much sense. Default flags are | 543 | does not make much sense. Default flags are |
| 544 | 0x07007 | 544 | 0x07007 |
| 545 | (NTLM, NTLMv2 and packet signing allowed). Maximum | 545 | (NTLM, NTLMv2 and packet signing allowed). The maximum |
| 546 | allowable flags if you want to allow mounts to servers | 546 | allowable flags if you want to allow mounts to servers |
| 547 | using weaker password hashes is 0x37037 (lanman, | 547 | using weaker password hashes is 0x37037 (lanman, |
| 548 | plaintext, ntlm, ntlmv2, signing allowed): | 548 | plaintext, ntlm, ntlmv2, signing allowed). Some |
| 549 | SecurityFlags require the corresponding menuconfig | ||
| 550 | options to be enabled (lanman and plaintext require | ||
| 551 | CONFIG_CIFS_WEAK_PW_HASH for example). Enabling | ||
| 552 | plaintext authentication currently requires also | ||
| 553 | enabling lanman authentication in the security flags | ||
| 554 | because the cifs module only supports sending | ||
| 555 | laintext passwords using the older lanman dialect | ||
| 556 | form of the session setup SMB. (e.g. for authentication | ||
| 557 | using plain text passwords, set the SecurityFlags | ||
| 558 | to 0x30030): | ||
| 549 | 559 | ||
| 550 | may use packet signing 0x00001 | 560 | may use packet signing 0x00001 |
| 551 | must use packet signing 0x01001 | 561 | must use packet signing 0x01001 |
| @@ -642,8 +652,30 @@ The statistics for the number of total SMBs and oplock breaks are different in | |||
| 642 | that they represent all for that share, not just those for which the server | 652 | that they represent all for that share, not just those for which the server |
| 643 | returned success. | 653 | returned success. |
| 644 | 654 | ||
| 645 | Also note that "cat /proc/fs/cifs/DebugData" will display information about | 655 | Also note that "cat /proc/fs/cifs/DebugData" will display information about |
| 646 | the active sessions and the shares that are mounted. | 656 | the active sessions and the shares that are mounted. |
| 647 | Enabling Kerberos (extended security) works when CONFIG_CIFS_EXPERIMENTAL is | 657 | |
| 648 | on but requires a user space helper (from the Samba project). NTLM and NTLMv2 and | 658 | Enabling Kerberos (extended security) works but requires version 1.2 or later |
| 649 | LANMAN support do not require this helper. | 659 | of the helper program cifs.upcall to be present and to be configured in the |
| 660 | /etc/request-key.conf file. The cifs.upcall helper program is from the Samba | ||
| 661 | project(http://www.samba.org). NTLM and NTLMv2 and LANMAN support do not | ||
| 662 | require this helper. Note that NTLMv2 security (which does not require the | ||
| 663 | cifs.upcall helper program), instead of using Kerberos, is sufficient for | ||
| 664 | some use cases. | ||
| 665 | |||
| 666 | Enabling DFS support (used to access shares transparently in an MS-DFS | ||
| 667 | global name space) requires that CONFIG_CIFS_EXPERIMENTAL be enabled. In | ||
| 668 | addition, DFS support for target shares which are specified as UNC | ||
| 669 | names which begin with host names (rather than IP addresses) requires | ||
| 670 | a user space helper (such as cifs.upcall) to be present in order to | ||
| 671 | translate host names to ip address, and the user space helper must also | ||
| 672 | be configured in the file /etc/request-key.conf | ||
| 673 | |||
| 674 | To use cifs Kerberos and DFS support, the Linux keyutils package should be | ||
| 675 | installed and something like the following lines should be added to the | ||
| 676 | /etc/request-key.conf file: | ||
| 677 | |||
| 678 | create cifs.spnego * * /usr/local/sbin/cifs.upcall %k | ||
| 679 | create dns_resolver * * /usr/local/sbin/cifs.upcall %k | ||
| 680 | |||
| 681 | |||
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index f58e41d3ba48..1b09f1670061 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
| @@ -400,7 +400,7 @@ asn1_oid_decode(struct asn1_ctx *ctx, | |||
| 400 | size = eoc - ctx->pointer + 1; | 400 | size = eoc - ctx->pointer + 1; |
| 401 | 401 | ||
| 402 | /* first subid actually encodes first two subids */ | 402 | /* first subid actually encodes first two subids */ |
| 403 | if (size < 2 || size > ULONG_MAX/sizeof(unsigned long)) | 403 | if (size < 2 || size > UINT_MAX/sizeof(unsigned long)) |
| 404 | return 0; | 404 | return 0; |
| 405 | 405 | ||
| 406 | *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); | 406 | *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); |
| @@ -476,6 +476,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 476 | unsigned int cls, con, tag, oidlen, rc; | 476 | unsigned int cls, con, tag, oidlen, rc; |
| 477 | bool use_ntlmssp = false; | 477 | bool use_ntlmssp = false; |
| 478 | bool use_kerberos = false; | 478 | bool use_kerberos = false; |
| 479 | bool use_mskerberos = false; | ||
| 479 | 480 | ||
| 480 | *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/ | 481 | *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/ |
| 481 | 482 | ||
| @@ -483,6 +484,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 483 | 484 | ||
| 484 | asn1_open(&ctx, security_blob, length); | 485 | asn1_open(&ctx, security_blob, length); |
| 485 | 486 | ||
| 487 | /* GSSAPI header */ | ||
| 486 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 488 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 487 | cFYI(1, ("Error decoding negTokenInit header")); | 489 | cFYI(1, ("Error decoding negTokenInit header")); |
| 488 | return 0; | 490 | return 0; |
| @@ -490,156 +492,149 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
| 490 | || (tag != ASN1_EOC)) { | 492 | || (tag != ASN1_EOC)) { |
| 491 | cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); | 493 | cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); |
| 492 | return 0; | 494 | return 0; |
| 493 | } else { | 495 | } |
| 494 | /* remember to free obj->oid */ | ||
| 495 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); | ||
| 496 | if (rc) { | ||
| 497 | if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) { | ||
| 498 | rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); | ||
| 499 | if (rc) { | ||
| 500 | rc = compare_oid(oid, oidlen, | ||
| 501 | SPNEGO_OID, | ||
| 502 | SPNEGO_OID_LEN); | ||
| 503 | kfree(oid); | ||
| 504 | } | ||
| 505 | } else | ||
| 506 | rc = 0; | ||
| 507 | } | ||
| 508 | 496 | ||
| 509 | if (!rc) { | 497 | /* Check for SPNEGO OID -- remember to free obj->oid */ |
| 510 | cFYI(1, ("Error decoding negTokenInit header")); | 498 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); |
| 511 | return 0; | 499 | if (rc) { |
| 512 | } | 500 | if ((tag == ASN1_OJI) && (con == ASN1_PRI) && |
| 501 | (cls == ASN1_UNI)) { | ||
| 502 | rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); | ||
| 503 | if (rc) { | ||
| 504 | rc = compare_oid(oid, oidlen, SPNEGO_OID, | ||
| 505 | SPNEGO_OID_LEN); | ||
| 506 | kfree(oid); | ||
| 507 | } | ||
| 508 | } else | ||
| 509 | rc = 0; | ||
| 510 | } | ||
| 513 | 511 | ||
| 514 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 512 | /* SPNEGO OID not present or garbled -- bail out */ |
| 515 | cFYI(1, ("Error decoding negTokenInit")); | 513 | if (!rc) { |
| 516 | return 0; | 514 | cFYI(1, ("Error decoding negTokenInit header")); |
| 517 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) | 515 | return 0; |
| 518 | || (tag != ASN1_EOC)) { | 516 | } |
| 519 | cFYI(1, | ||
| 520 | ("cls = %d con = %d tag = %d end = %p (%d) exit 0", | ||
| 521 | cls, con, tag, end, *end)); | ||
| 522 | return 0; | ||
| 523 | } | ||
| 524 | 517 | ||
| 525 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 518 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 526 | cFYI(1, ("Error decoding negTokenInit")); | 519 | cFYI(1, ("Error decoding negTokenInit")); |
| 527 | return 0; | 520 | return 0; |
| 528 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | 521 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) |
| 529 | || (tag != ASN1_SEQ)) { | 522 | || (tag != ASN1_EOC)) { |
| 530 | cFYI(1, | 523 | cFYI(1, |
| 531 | ("cls = %d con = %d tag = %d end = %p (%d) exit 1", | 524 | ("cls = %d con = %d tag = %d end = %p (%d) exit 0", |
| 532 | cls, con, tag, end, *end)); | 525 | cls, con, tag, end, *end)); |
| 533 | return 0; | 526 | return 0; |
| 534 | } | 527 | } |
| 535 | 528 | ||
| 536 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 529 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 537 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); | 530 | cFYI(1, ("Error decoding negTokenInit")); |
| 538 | return 0; | 531 | return 0; |
| 539 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) | 532 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) |
| 540 | || (tag != ASN1_EOC)) { | 533 | || (tag != ASN1_SEQ)) { |
| 541 | cFYI(1, | 534 | cFYI(1, |
| 542 | ("cls = %d con = %d tag = %d end = %p (%d) exit 0", | 535 | ("cls = %d con = %d tag = %d end = %p (%d) exit 1", |
| 543 | cls, con, tag, end, *end)); | 536 | cls, con, tag, end, *end)); |
| 544 | return 0; | 537 | return 0; |
| 545 | } | 538 | } |
| 546 | 539 | ||
| 547 | if (asn1_header_decode | 540 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 548 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { | 541 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
| 549 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); | 542 | return 0; |
| 550 | return 0; | 543 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON) |
| 551 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | 544 | || (tag != ASN1_EOC)) { |
| 552 | || (tag != ASN1_SEQ)) { | 545 | cFYI(1, |
| 553 | cFYI(1, | 546 | ("cls = %d con = %d tag = %d end = %p (%d) exit 0", |
| 554 | ("cls = %d con = %d tag = %d end = %p (%d) exit 1", | 547 | cls, con, tag, end, *end)); |
| 555 | cls, con, tag, end, *end)); | 548 | return 0; |
| 556 | return 0; | 549 | } |
| 557 | } | ||
| 558 | 550 | ||
| 559 | while (!asn1_eoc_decode(&ctx, sequence_end)) { | 551 | if (asn1_header_decode |
| 560 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); | 552 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { |
| 561 | if (!rc) { | 553 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
| 562 | cFYI(1, | 554 | return 0; |
| 563 | ("Error decoding negTokenInit hdr exit2")); | 555 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) |
| 564 | return 0; | 556 | || (tag != ASN1_SEQ)) { |
| 565 | } | 557 | cFYI(1, |
| 566 | if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { | 558 | ("cls = %d con = %d tag = %d end = %p (%d) exit 1", |
| 567 | if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) { | 559 | cls, con, tag, end, *end)); |
| 568 | 560 | return 0; | |
| 569 | cFYI(1, | 561 | } |
| 570 | ("OID len = %d oid = 0x%lx 0x%lx " | ||
| 571 | "0x%lx 0x%lx", | ||
| 572 | oidlen, *oid, *(oid + 1), | ||
| 573 | *(oid + 2), *(oid + 3))); | ||
| 574 | |||
| 575 | if (compare_oid(oid, oidlen, | ||
| 576 | MSKRB5_OID, | ||
| 577 | MSKRB5_OID_LEN)) | ||
| 578 | use_kerberos = true; | ||
| 579 | else if (compare_oid(oid, oidlen, | ||
| 580 | KRB5_OID, | ||
| 581 | KRB5_OID_LEN)) | ||
| 582 | use_kerberos = true; | ||
| 583 | else if (compare_oid(oid, oidlen, | ||
| 584 | NTLMSSP_OID, | ||
| 585 | NTLMSSP_OID_LEN)) | ||
| 586 | use_ntlmssp = true; | ||
| 587 | |||
| 588 | kfree(oid); | ||
| 589 | } | ||
| 590 | } else { | ||
| 591 | cFYI(1, ("Should be an oid what is going on?")); | ||
| 592 | } | ||
| 593 | } | ||
| 594 | 562 | ||
| 595 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 563 | while (!asn1_eoc_decode(&ctx, sequence_end)) { |
| 596 | cFYI(1, | 564 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); |
| 597 | ("Error decoding last part negTokenInit exit3")); | 565 | if (!rc) { |
| 598 | return 0; | ||
| 599 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { | ||
| 600 | /* tag = 3 indicating mechListMIC */ | ||
| 601 | cFYI(1, | 566 | cFYI(1, |
| 602 | ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", | 567 | ("Error decoding negTokenInit hdr exit2")); |
| 603 | cls, con, tag, end, *end)); | ||
| 604 | return 0; | 568 | return 0; |
| 605 | } | 569 | } |
| 606 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 570 | if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { |
| 607 | cFYI(1, | 571 | if (asn1_oid_decode(&ctx, end, &oid, &oidlen)) { |
| 608 | ("Error decoding last part negTokenInit exit5")); | 572 | |
| 609 | return 0; | 573 | cFYI(1, ("OID len = %d oid = 0x%lx 0x%lx " |
| 610 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) | 574 | "0x%lx 0x%lx", oidlen, *oid, |
| 611 | || (tag != ASN1_SEQ)) { | 575 | *(oid + 1), *(oid + 2), *(oid + 3))); |
| 612 | cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)", | 576 | |
| 613 | cls, con, tag, end, *end)); | 577 | if (compare_oid(oid, oidlen, MSKRB5_OID, |
| 578 | MSKRB5_OID_LEN) && | ||
| 579 | !use_kerberos) | ||
| 580 | use_mskerberos = true; | ||
| 581 | else if (compare_oid(oid, oidlen, KRB5_OID, | ||
| 582 | KRB5_OID_LEN) && | ||
| 583 | !use_mskerberos) | ||
| 584 | use_kerberos = true; | ||
| 585 | else if (compare_oid(oid, oidlen, NTLMSSP_OID, | ||
| 586 | NTLMSSP_OID_LEN)) | ||
| 587 | use_ntlmssp = true; | ||
| 588 | |||
| 589 | kfree(oid); | ||
| 590 | } | ||
| 591 | } else { | ||
| 592 | cFYI(1, ("Should be an oid what is going on?")); | ||
| 614 | } | 593 | } |
| 594 | } | ||
| 615 | 595 | ||
| 616 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 596 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 617 | cFYI(1, | 597 | cFYI(1, ("Error decoding last part negTokenInit exit3")); |
| 618 | ("Error decoding last part negTokenInit exit 7")); | 598 | return 0; |
| 619 | return 0; | 599 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { |
| 620 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { | 600 | /* tag = 3 indicating mechListMIC */ |
| 621 | cFYI(1, | 601 | cFYI(1, ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", |
| 622 | ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", | 602 | cls, con, tag, end, *end)); |
| 623 | cls, con, tag, end, *end)); | 603 | return 0; |
| 624 | return 0; | 604 | } |
| 625 | } | 605 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 626 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 606 | cFYI(1, ("Error decoding last part negTokenInit exit5")); |
| 627 | cFYI(1, | 607 | return 0; |
| 628 | ("Error decoding last part negTokenInit exit9")); | 608 | } else if ((cls != ASN1_UNI) || (con != ASN1_CON) |
| 629 | return 0; | 609 | || (tag != ASN1_SEQ)) { |
| 630 | } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) | 610 | cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)", |
| 631 | || (tag != ASN1_GENSTR)) { | 611 | cls, con, tag, end, *end)); |
| 632 | cFYI(1, | 612 | } |
| 633 | ("Exit10 cls = %d con = %d tag = %d end = %p (%d)", | 613 | |
| 634 | cls, con, tag, end, *end)); | 614 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
| 635 | return 0; | 615 | cFYI(1, ("Error decoding last part negTokenInit exit 7")); |
| 636 | } | 616 | return 0; |
| 637 | cFYI(1, ("Need to call asn1_octets_decode() function for %s", | 617 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { |
| 638 | ctx.pointer)); /* is this UTF-8 or ASCII? */ | 618 | cFYI(1, ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", |
| 619 | cls, con, tag, end, *end)); | ||
| 620 | return 0; | ||
| 621 | } | ||
| 622 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | ||
| 623 | cFYI(1, ("Error decoding last part negTokenInit exit9")); | ||
| 624 | return 0; | ||
| 625 | } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) | ||
| 626 | || (tag != ASN1_GENSTR)) { | ||
| 627 | cFYI(1, ("Exit10 cls = %d con = %d tag = %d end = %p (%d)", | ||
| 628 | cls, con, tag, end, *end)); | ||
| 629 | return 0; | ||
| 639 | } | 630 | } |
| 631 | cFYI(1, ("Need to call asn1_octets_decode() function for %s", | ||
| 632 | ctx.pointer)); /* is this UTF-8 or ASCII? */ | ||
| 640 | 633 | ||
| 641 | if (use_kerberos) | 634 | if (use_kerberos) |
| 642 | *secType = Kerberos; | 635 | *secType = Kerberos; |
| 636 | else if (use_mskerberos) | ||
| 637 | *secType = MSKerberos; | ||
| 643 | else if (use_ntlmssp) | 638 | else if (use_ntlmssp) |
| 644 | *secType = NTLMSSP; | 639 | *secType = NTLMSSP; |
| 645 | 640 | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index cc950f69e51e..69a12aae91d3 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
| @@ -79,27 +79,25 @@ void cifs_dump_mids(struct TCP_Server_Info *server) | |||
| 79 | spin_lock(&GlobalMid_Lock); | 79 | spin_lock(&GlobalMid_Lock); |
| 80 | list_for_each(tmp, &server->pending_mid_q) { | 80 | list_for_each(tmp, &server->pending_mid_q) { |
| 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | 81 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); |
| 82 | if (mid_entry) { | 82 | cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", |
| 83 | cERROR(1, ("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", | 83 | mid_entry->midState, |
| 84 | mid_entry->midState, | 84 | (int)mid_entry->command, |
| 85 | (int)mid_entry->command, | 85 | mid_entry->pid, |
| 86 | mid_entry->pid, | 86 | mid_entry->tsk, |
| 87 | mid_entry->tsk, | 87 | mid_entry->mid)); |
| 88 | mid_entry->mid)); | ||
| 89 | #ifdef CONFIG_CIFS_STATS2 | 88 | #ifdef CONFIG_CIFS_STATS2 |
| 90 | cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld", | 89 | cERROR(1, ("IsLarge: %d buf: %p time rcv: %ld now: %ld", |
| 91 | mid_entry->largeBuf, | 90 | mid_entry->largeBuf, |
| 92 | mid_entry->resp_buf, | 91 | mid_entry->resp_buf, |
| 93 | mid_entry->when_received, | 92 | mid_entry->when_received, |
| 94 | jiffies)); | 93 | jiffies)); |
| 95 | #endif /* STATS2 */ | 94 | #endif /* STATS2 */ |
| 96 | cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp, | 95 | cERROR(1, ("IsMult: %d IsEnd: %d", mid_entry->multiRsp, |
| 97 | mid_entry->multiEnd)); | 96 | mid_entry->multiEnd)); |
| 98 | if (mid_entry->resp_buf) { | 97 | if (mid_entry->resp_buf) { |
| 99 | cifs_dump_detail(mid_entry->resp_buf); | 98 | cifs_dump_detail(mid_entry->resp_buf); |
| 100 | cifs_dump_mem("existing buf: ", | 99 | cifs_dump_mem("existing buf: ", |
| 101 | mid_entry->resp_buf, 62); | 100 | mid_entry->resp_buf, 62); |
| 102 | } | ||
| 103 | } | 101 | } |
| 104 | } | 102 | } |
| 105 | spin_unlock(&GlobalMid_Lock); | 103 | spin_unlock(&GlobalMid_Lock); |
| @@ -107,9 +105,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server) | |||
| 107 | #endif /* CONFIG_CIFS_DEBUG2 */ | 105 | #endif /* CONFIG_CIFS_DEBUG2 */ |
| 108 | 106 | ||
| 109 | #ifdef CONFIG_PROC_FS | 107 | #ifdef CONFIG_PROC_FS |
| 110 | static int | 108 | static int cifs_debug_data_proc_show(struct seq_file *m, void *v) |
| 111 | cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | ||
| 112 | int count, int *eof, void *data) | ||
| 113 | { | 109 | { |
| 114 | struct list_head *tmp; | 110 | struct list_head *tmp; |
| 115 | struct list_head *tmp1; | 111 | struct list_head *tmp1; |
| @@ -117,23 +113,13 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 117 | struct cifsSesInfo *ses; | 113 | struct cifsSesInfo *ses; |
| 118 | struct cifsTconInfo *tcon; | 114 | struct cifsTconInfo *tcon; |
| 119 | int i; | 115 | int i; |
| 120 | int length = 0; | ||
| 121 | char *original_buf = buf; | ||
| 122 | |||
| 123 | *beginBuffer = buf + offset; | ||
| 124 | 116 | ||
| 125 | length = | 117 | seq_puts(m, |
| 126 | sprintf(buf, | ||
| 127 | "Display Internal CIFS Data Structures for Debugging\n" | 118 | "Display Internal CIFS Data Structures for Debugging\n" |
| 128 | "---------------------------------------------------\n"); | 119 | "---------------------------------------------------\n"); |
| 129 | buf += length; | 120 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); |
| 130 | length = sprintf(buf, "CIFS Version %s\n", CIFS_VERSION); | 121 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); |
| 131 | buf += length; | 122 | seq_printf(m, "Servers:"); |
| 132 | length = sprintf(buf, | ||
| 133 | "Active VFS Requests: %d\n", GlobalTotalActiveXid); | ||
| 134 | buf += length; | ||
| 135 | length = sprintf(buf, "Servers:"); | ||
| 136 | buf += length; | ||
| 137 | 123 | ||
| 138 | i = 0; | 124 | i = 0; |
| 139 | read_lock(&GlobalSMBSeslock); | 125 | read_lock(&GlobalSMBSeslock); |
| @@ -142,11 +128,10 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 142 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | 128 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); |
| 143 | if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) || | 129 | if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) || |
| 144 | (ses->serverNOS == NULL)) { | 130 | (ses->serverNOS == NULL)) { |
| 145 | buf += sprintf(buf, "\nentry for %s not fully " | 131 | seq_printf(m, "\nentry for %s not fully " |
| 146 | "displayed\n\t", ses->serverName); | 132 | "displayed\n\t", ses->serverName); |
| 147 | } else { | 133 | } else { |
| 148 | length = | 134 | seq_printf(m, |
| 149 | sprintf(buf, | ||
| 150 | "\n%d) Name: %s Domain: %s Mounts: %d OS:" | 135 | "\n%d) Name: %s Domain: %s Mounts: %d OS:" |
| 151 | " %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB" | 136 | " %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB" |
| 152 | " session status: %d\t", | 137 | " session status: %d\t", |
| @@ -154,10 +139,9 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 154 | atomic_read(&ses->inUse), | 139 | atomic_read(&ses->inUse), |
| 155 | ses->serverOS, ses->serverNOS, | 140 | ses->serverOS, ses->serverNOS, |
| 156 | ses->capabilities, ses->status); | 141 | ses->capabilities, ses->status); |
| 157 | buf += length; | ||
| 158 | } | 142 | } |
| 159 | if (ses->server) { | 143 | if (ses->server) { |
| 160 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To " | 144 | seq_printf(m, "TCP status: %d\n\tLocal Users To " |
| 161 | "Server: %d SecMode: 0x%x Req On Wire: %d", | 145 | "Server: %d SecMode: 0x%x Req On Wire: %d", |
| 162 | ses->server->tcpStatus, | 146 | ses->server->tcpStatus, |
| 163 | atomic_read(&ses->server->socketUseCount), | 147 | atomic_read(&ses->server->socketUseCount), |
| @@ -165,41 +149,34 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 165 | atomic_read(&ses->server->inFlight)); | 149 | atomic_read(&ses->server->inFlight)); |
| 166 | 150 | ||
| 167 | #ifdef CONFIG_CIFS_STATS2 | 151 | #ifdef CONFIG_CIFS_STATS2 |
| 168 | buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d", | 152 | seq_printf(m, " In Send: %d In MaxReq Wait: %d", |
| 169 | atomic_read(&ses->server->inSend), | 153 | atomic_read(&ses->server->inSend), |
| 170 | atomic_read(&ses->server->num_waiters)); | 154 | atomic_read(&ses->server->num_waiters)); |
| 171 | #endif | 155 | #endif |
| 172 | 156 | ||
| 173 | length = sprintf(buf, "\nMIDs:\n"); | 157 | seq_puts(m, "\nMIDs:\n"); |
| 174 | buf += length; | ||
| 175 | 158 | ||
| 176 | spin_lock(&GlobalMid_Lock); | 159 | spin_lock(&GlobalMid_Lock); |
| 177 | list_for_each(tmp1, &ses->server->pending_mid_q) { | 160 | list_for_each(tmp1, &ses->server->pending_mid_q) { |
| 178 | mid_entry = list_entry(tmp1, struct | 161 | mid_entry = list_entry(tmp1, struct |
| 179 | mid_q_entry, | 162 | mid_q_entry, |
| 180 | qhead); | 163 | qhead); |
| 181 | if (mid_entry) { | 164 | seq_printf(m, "State: %d com: %d pid:" |
| 182 | length = sprintf(buf, | 165 | " %d tsk: %p mid %d\n", |
| 183 | "State: %d com: %d pid:" | 166 | mid_entry->midState, |
| 184 | " %d tsk: %p mid %d\n", | 167 | (int)mid_entry->command, |
| 185 | mid_entry->midState, | 168 | mid_entry->pid, |
| 186 | (int)mid_entry->command, | 169 | mid_entry->tsk, |
| 187 | mid_entry->pid, | 170 | mid_entry->mid); |
| 188 | mid_entry->tsk, | ||
| 189 | mid_entry->mid); | ||
| 190 | buf += length; | ||
| 191 | } | ||
| 192 | } | 171 | } |
| 193 | spin_unlock(&GlobalMid_Lock); | 172 | spin_unlock(&GlobalMid_Lock); |
| 194 | } | 173 | } |
| 195 | 174 | ||
| 196 | } | 175 | } |
| 197 | read_unlock(&GlobalSMBSeslock); | 176 | read_unlock(&GlobalSMBSeslock); |
| 198 | sprintf(buf, "\n"); | 177 | seq_putc(m, '\n'); |
| 199 | buf++; | ||
| 200 | 178 | ||
| 201 | length = sprintf(buf, "Shares:"); | 179 | seq_puts(m, "Shares:"); |
| 202 | buf += length; | ||
| 203 | 180 | ||
| 204 | i = 0; | 181 | i = 0; |
| 205 | read_lock(&GlobalSMBSeslock); | 182 | read_lock(&GlobalSMBSeslock); |
| @@ -208,62 +185,52 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 208 | i++; | 185 | i++; |
| 209 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 186 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
| 210 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | 187 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); |
| 211 | length = sprintf(buf, "\n%d) %s Uses: %d ", i, | 188 | seq_printf(m, "\n%d) %s Uses: %d ", i, |
| 212 | tcon->treeName, atomic_read(&tcon->useCount)); | 189 | tcon->treeName, atomic_read(&tcon->useCount)); |
| 213 | buf += length; | ||
| 214 | if (tcon->nativeFileSystem) { | 190 | if (tcon->nativeFileSystem) { |
| 215 | length = sprintf(buf, "Type: %s ", | 191 | seq_printf(m, "Type: %s ", |
| 216 | tcon->nativeFileSystem); | 192 | tcon->nativeFileSystem); |
| 217 | buf += length; | ||
| 218 | } | 193 | } |
| 219 | length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x" | 194 | seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" |
| 220 | "\nPathComponentMax: %d Status: %d", | 195 | "\nPathComponentMax: %d Status: %d", |
| 221 | le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), | 196 | le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), |
| 222 | le32_to_cpu(tcon->fsAttrInfo.Attributes), | 197 | le32_to_cpu(tcon->fsAttrInfo.Attributes), |
| 223 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), | 198 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), |
| 224 | tcon->tidStatus); | 199 | tcon->tidStatus); |
| 225 | buf += length; | ||
| 226 | if (dev_type == FILE_DEVICE_DISK) | 200 | if (dev_type == FILE_DEVICE_DISK) |
| 227 | length = sprintf(buf, " type: DISK "); | 201 | seq_puts(m, " type: DISK "); |
| 228 | else if (dev_type == FILE_DEVICE_CD_ROM) | 202 | else if (dev_type == FILE_DEVICE_CD_ROM) |
| 229 | length = sprintf(buf, " type: CDROM "); | 203 | seq_puts(m, " type: CDROM "); |
| 230 | else | 204 | else |
| 231 | length = | 205 | seq_printf(m, " type: %d ", dev_type); |
| 232 | sprintf(buf, " type: %d ", dev_type); | 206 | |
| 233 | buf += length; | 207 | if (tcon->tidStatus == CifsNeedReconnect) |
| 234 | if (tcon->tidStatus == CifsNeedReconnect) { | 208 | seq_puts(m, "\tDISCONNECTED "); |
| 235 | buf += sprintf(buf, "\tDISCONNECTED "); | ||
| 236 | length += 14; | ||
| 237 | } | ||
| 238 | } | 209 | } |
| 239 | read_unlock(&GlobalSMBSeslock); | 210 | read_unlock(&GlobalSMBSeslock); |
| 240 | 211 | ||
| 241 | length = sprintf(buf, "\n"); | 212 | seq_putc(m, '\n'); |
| 242 | buf += length; | ||
| 243 | 213 | ||
| 244 | /* BB add code to dump additional info such as TCP session info now */ | 214 | /* BB add code to dump additional info such as TCP session info now */ |
| 245 | /* Now calculate total size of returned data */ | 215 | return 0; |
| 246 | length = buf - original_buf; | 216 | } |
| 247 | |||
| 248 | if (offset + count >= length) | ||
| 249 | *eof = 1; | ||
| 250 | if (length < offset) { | ||
| 251 | *eof = 1; | ||
| 252 | return 0; | ||
| 253 | } else { | ||
| 254 | length = length - offset; | ||
| 255 | } | ||
| 256 | if (length > count) | ||
| 257 | length = count; | ||
| 258 | 217 | ||
| 259 | return length; | 218 | static int cifs_debug_data_proc_open(struct inode *inode, struct file *file) |
| 219 | { | ||
| 220 | return single_open(file, cifs_debug_data_proc_show, NULL); | ||
| 260 | } | 221 | } |
| 261 | 222 | ||
| 262 | #ifdef CONFIG_CIFS_STATS | 223 | static const struct file_operations cifs_debug_data_proc_fops = { |
| 224 | .owner = THIS_MODULE, | ||
| 225 | .open = cifs_debug_data_proc_open, | ||
| 226 | .read = seq_read, | ||
| 227 | .llseek = seq_lseek, | ||
| 228 | .release = single_release, | ||
| 229 | }; | ||
| 263 | 230 | ||
| 264 | static int | 231 | #ifdef CONFIG_CIFS_STATS |
| 265 | cifs_stats_write(struct file *file, const char __user *buffer, | 232 | static ssize_t cifs_stats_proc_write(struct file *file, |
| 266 | unsigned long count, void *data) | 233 | const char __user *buffer, size_t count, loff_t *ppos) |
| 267 | { | 234 | { |
| 268 | char c; | 235 | char c; |
| 269 | int rc; | 236 | int rc; |
| @@ -307,236 +274,132 @@ cifs_stats_write(struct file *file, const char __user *buffer, | |||
| 307 | return count; | 274 | return count; |
| 308 | } | 275 | } |
| 309 | 276 | ||
| 310 | static int | 277 | static int cifs_stats_proc_show(struct seq_file *m, void *v) |
| 311 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | ||
| 312 | int count, int *eof, void *data) | ||
| 313 | { | 278 | { |
| 314 | int item_length, i, length; | 279 | int i; |
| 315 | struct list_head *tmp; | 280 | struct list_head *tmp; |
| 316 | struct cifsTconInfo *tcon; | 281 | struct cifsTconInfo *tcon; |
| 317 | 282 | ||
| 318 | *beginBuffer = buf + offset; | 283 | seq_printf(m, |
| 319 | |||
| 320 | length = sprintf(buf, | ||
| 321 | "Resources in use\nCIFS Session: %d\n", | 284 | "Resources in use\nCIFS Session: %d\n", |
| 322 | sesInfoAllocCount.counter); | 285 | sesInfoAllocCount.counter); |
| 323 | buf += length; | 286 | seq_printf(m, "Share (unique mount targets): %d\n", |
| 324 | item_length = | ||
| 325 | sprintf(buf, "Share (unique mount targets): %d\n", | ||
| 326 | tconInfoAllocCount.counter); | 287 | tconInfoAllocCount.counter); |
| 327 | length += item_length; | 288 | seq_printf(m, "SMB Request/Response Buffer: %d Pool size: %d\n", |
| 328 | buf += item_length; | ||
| 329 | item_length = | ||
| 330 | sprintf(buf, "SMB Request/Response Buffer: %d Pool size: %d\n", | ||
| 331 | bufAllocCount.counter, | 289 | bufAllocCount.counter, |
| 332 | cifs_min_rcv + tcpSesAllocCount.counter); | 290 | cifs_min_rcv + tcpSesAllocCount.counter); |
| 333 | length += item_length; | 291 | seq_printf(m, "SMB Small Req/Resp Buffer: %d Pool size: %d\n", |
| 334 | buf += item_length; | ||
| 335 | item_length = | ||
| 336 | sprintf(buf, "SMB Small Req/Resp Buffer: %d Pool size: %d\n", | ||
| 337 | smBufAllocCount.counter, cifs_min_small); | 292 | smBufAllocCount.counter, cifs_min_small); |
| 338 | length += item_length; | ||
| 339 | buf += item_length; | ||
| 340 | #ifdef CONFIG_CIFS_STATS2 | 293 | #ifdef CONFIG_CIFS_STATS2 |
| 341 | item_length = sprintf(buf, "Total Large %d Small %d Allocations\n", | 294 | seq_printf(m, "Total Large %d Small %d Allocations\n", |
| 342 | atomic_read(&totBufAllocCount), | 295 | atomic_read(&totBufAllocCount), |
| 343 | atomic_read(&totSmBufAllocCount)); | 296 | atomic_read(&totSmBufAllocCount)); |
| 344 | length += item_length; | ||
| 345 | buf += item_length; | ||
| 346 | #endif /* CONFIG_CIFS_STATS2 */ | 297 | #endif /* CONFIG_CIFS_STATS2 */ |
| 347 | 298 | ||
| 348 | item_length = | 299 | seq_printf(m, "Operations (MIDs): %d\n", midCount.counter); |
| 349 | sprintf(buf, "Operations (MIDs): %d\n", | 300 | seq_printf(m, |
| 350 | midCount.counter); | ||
| 351 | length += item_length; | ||
| 352 | buf += item_length; | ||
| 353 | item_length = sprintf(buf, | ||
| 354 | "\n%d session %d share reconnects\n", | 301 | "\n%d session %d share reconnects\n", |
| 355 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); | 302 | tcpSesReconnectCount.counter, tconInfoReconnectCount.counter); |
| 356 | length += item_length; | ||
| 357 | buf += item_length; | ||
| 358 | 303 | ||
| 359 | item_length = sprintf(buf, | 304 | seq_printf(m, |
| 360 | "Total vfs operations: %d maximum at one time: %d\n", | 305 | "Total vfs operations: %d maximum at one time: %d\n", |
| 361 | GlobalCurrentXid, GlobalMaxActiveXid); | 306 | GlobalCurrentXid, GlobalMaxActiveXid); |
| 362 | length += item_length; | ||
| 363 | buf += item_length; | ||
| 364 | 307 | ||
| 365 | i = 0; | 308 | i = 0; |
| 366 | read_lock(&GlobalSMBSeslock); | 309 | read_lock(&GlobalSMBSeslock); |
| 367 | list_for_each(tmp, &GlobalTreeConnectionList) { | 310 | list_for_each(tmp, &GlobalTreeConnectionList) { |
| 368 | i++; | 311 | i++; |
| 369 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 312 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
| 370 | item_length = sprintf(buf, "\n%d) %s", i, tcon->treeName); | 313 | seq_printf(m, "\n%d) %s", i, tcon->treeName); |
| 371 | buf += item_length; | 314 | if (tcon->tidStatus == CifsNeedReconnect) |
| 372 | length += item_length; | 315 | seq_puts(m, "\tDISCONNECTED "); |
| 373 | if (tcon->tidStatus == CifsNeedReconnect) { | 316 | seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", |
| 374 | buf += sprintf(buf, "\tDISCONNECTED "); | ||
| 375 | length += 14; | ||
| 376 | } | ||
| 377 | item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d", | ||
| 378 | atomic_read(&tcon->num_smbs_sent), | 317 | atomic_read(&tcon->num_smbs_sent), |
| 379 | atomic_read(&tcon->num_oplock_brks)); | 318 | atomic_read(&tcon->num_oplock_brks)); |
| 380 | buf += item_length; | 319 | seq_printf(m, "\nReads: %d Bytes: %lld", |
| 381 | length += item_length; | ||
| 382 | item_length = sprintf(buf, "\nReads: %d Bytes: %lld", | ||
| 383 | atomic_read(&tcon->num_reads), | 320 | atomic_read(&tcon->num_reads), |
| 384 | (long long)(tcon->bytes_read)); | 321 | (long long)(tcon->bytes_read)); |
| 385 | buf += item_length; | 322 | seq_printf(m, "\nWrites: %d Bytes: %lld", |
| 386 | length += item_length; | ||
| 387 | item_length = sprintf(buf, "\nWrites: %d Bytes: %lld", | ||
| 388 | atomic_read(&tcon->num_writes), | 323 | atomic_read(&tcon->num_writes), |
| 389 | (long long)(tcon->bytes_written)); | 324 | (long long)(tcon->bytes_written)); |
| 390 | buf += item_length; | 325 | seq_printf(m, |
| 391 | length += item_length; | ||
| 392 | item_length = sprintf(buf, | ||
| 393 | "\nLocks: %d HardLinks: %d Symlinks: %d", | 326 | "\nLocks: %d HardLinks: %d Symlinks: %d", |
| 394 | atomic_read(&tcon->num_locks), | 327 | atomic_read(&tcon->num_locks), |
| 395 | atomic_read(&tcon->num_hardlinks), | 328 | atomic_read(&tcon->num_hardlinks), |
| 396 | atomic_read(&tcon->num_symlinks)); | 329 | atomic_read(&tcon->num_symlinks)); |
| 397 | buf += item_length; | ||
| 398 | length += item_length; | ||
| 399 | 330 | ||
| 400 | item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d", | 331 | seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d", |
| 401 | atomic_read(&tcon->num_opens), | 332 | atomic_read(&tcon->num_opens), |
| 402 | atomic_read(&tcon->num_closes), | 333 | atomic_read(&tcon->num_closes), |
| 403 | atomic_read(&tcon->num_deletes)); | 334 | atomic_read(&tcon->num_deletes)); |
| 404 | buf += item_length; | 335 | seq_printf(m, "\nMkdirs: %d Rmdirs: %d", |
| 405 | length += item_length; | ||
| 406 | item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d", | ||
| 407 | atomic_read(&tcon->num_mkdirs), | 336 | atomic_read(&tcon->num_mkdirs), |
| 408 | atomic_read(&tcon->num_rmdirs)); | 337 | atomic_read(&tcon->num_rmdirs)); |
| 409 | buf += item_length; | 338 | seq_printf(m, "\nRenames: %d T2 Renames %d", |
| 410 | length += item_length; | ||
| 411 | item_length = sprintf(buf, "\nRenames: %d T2 Renames %d", | ||
| 412 | atomic_read(&tcon->num_renames), | 339 | atomic_read(&tcon->num_renames), |
| 413 | atomic_read(&tcon->num_t2renames)); | 340 | atomic_read(&tcon->num_t2renames)); |
| 414 | buf += item_length; | 341 | seq_printf(m, "\nFindFirst: %d FNext %d FClose %d", |
| 415 | length += item_length; | ||
| 416 | item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d", | ||
| 417 | atomic_read(&tcon->num_ffirst), | 342 | atomic_read(&tcon->num_ffirst), |
| 418 | atomic_read(&tcon->num_fnext), | 343 | atomic_read(&tcon->num_fnext), |
| 419 | atomic_read(&tcon->num_fclose)); | 344 | atomic_read(&tcon->num_fclose)); |
| 420 | buf += item_length; | ||
| 421 | length += item_length; | ||
| 422 | } | 345 | } |
| 423 | read_unlock(&GlobalSMBSeslock); | 346 | read_unlock(&GlobalSMBSeslock); |
| 424 | 347 | ||
| 425 | buf += sprintf(buf, "\n"); | 348 | seq_putc(m, '\n'); |
| 426 | length++; | 349 | return 0; |
| 427 | 350 | } | |
| 428 | if (offset + count >= length) | ||
| 429 | *eof = 1; | ||
| 430 | if (length < offset) { | ||
| 431 | *eof = 1; | ||
| 432 | return 0; | ||
| 433 | } else { | ||
| 434 | length = length - offset; | ||
| 435 | } | ||
| 436 | if (length > count) | ||
| 437 | length = count; | ||
| 438 | 351 | ||
| 439 | return length; | 352 | static int cifs_stats_proc_open(struct inode *inode, struct file *file) |
| 353 | { | ||
| 354 | return single_open(file, cifs_stats_proc_show, NULL); | ||
| 440 | } | 355 | } |
| 356 | |||
| 357 | static const struct file_operations cifs_stats_proc_fops = { | ||
| 358 | .owner = THIS_MODULE, | ||
| 359 | .open = cifs_stats_proc_open, | ||
| 360 | .read = seq_read, | ||
| 361 | .llseek = seq_lseek, | ||
| 362 | .release = single_release, | ||
| 363 | .write = cifs_stats_proc_write, | ||
| 364 | }; | ||
| 441 | #endif /* STATS */ | 365 | #endif /* STATS */ |
| 442 | 366 | ||
| 443 | static struct proc_dir_entry *proc_fs_cifs; | 367 | static struct proc_dir_entry *proc_fs_cifs; |
| 444 | read_proc_t cifs_txanchor_read; | 368 | static const struct file_operations cifsFYI_proc_fops; |
| 445 | static read_proc_t cifsFYI_read; | 369 | static const struct file_operations cifs_oplock_proc_fops; |
| 446 | static write_proc_t cifsFYI_write; | 370 | static const struct file_operations cifs_lookup_cache_proc_fops; |
| 447 | static read_proc_t oplockEnabled_read; | 371 | static const struct file_operations traceSMB_proc_fops; |
| 448 | static write_proc_t oplockEnabled_write; | 372 | static const struct file_operations cifs_multiuser_mount_proc_fops; |
| 449 | static read_proc_t lookupFlag_read; | 373 | static const struct file_operations cifs_security_flags_proc_fops; |
| 450 | static write_proc_t lookupFlag_write; | 374 | static const struct file_operations cifs_experimental_proc_fops; |
| 451 | static read_proc_t traceSMB_read; | 375 | static const struct file_operations cifs_linux_ext_proc_fops; |
| 452 | static write_proc_t traceSMB_write; | ||
| 453 | static read_proc_t multiuser_mount_read; | ||
| 454 | static write_proc_t multiuser_mount_write; | ||
| 455 | static read_proc_t security_flags_read; | ||
| 456 | static write_proc_t security_flags_write; | ||
| 457 | /* static read_proc_t ntlmv2_enabled_read; | ||
| 458 | static write_proc_t ntlmv2_enabled_write; | ||
| 459 | static read_proc_t packet_signing_enabled_read; | ||
| 460 | static write_proc_t packet_signing_enabled_write;*/ | ||
| 461 | static read_proc_t experimEnabled_read; | ||
| 462 | static write_proc_t experimEnabled_write; | ||
| 463 | static read_proc_t linuxExtensionsEnabled_read; | ||
| 464 | static write_proc_t linuxExtensionsEnabled_write; | ||
| 465 | 376 | ||
| 466 | void | 377 | void |
| 467 | cifs_proc_init(void) | 378 | cifs_proc_init(void) |
| 468 | { | 379 | { |
| 469 | struct proc_dir_entry *pde; | ||
| 470 | |||
| 471 | proc_fs_cifs = proc_mkdir("fs/cifs", NULL); | 380 | proc_fs_cifs = proc_mkdir("fs/cifs", NULL); |
| 472 | if (proc_fs_cifs == NULL) | 381 | if (proc_fs_cifs == NULL) |
| 473 | return; | 382 | return; |
| 474 | 383 | ||
| 475 | proc_fs_cifs->owner = THIS_MODULE; | 384 | proc_fs_cifs->owner = THIS_MODULE; |
| 476 | create_proc_read_entry("DebugData", 0, proc_fs_cifs, | 385 | proc_create("DebugData", 0, proc_fs_cifs, &cifs_debug_data_proc_fops); |
| 477 | cifs_debug_data_read, NULL); | ||
| 478 | 386 | ||
| 479 | #ifdef CONFIG_CIFS_STATS | 387 | #ifdef CONFIG_CIFS_STATS |
| 480 | pde = create_proc_read_entry("Stats", 0, proc_fs_cifs, | 388 | proc_create("Stats", 0, proc_fs_cifs, &cifs_stats_proc_fops); |
| 481 | cifs_stats_read, NULL); | ||
| 482 | if (pde) | ||
| 483 | pde->write_proc = cifs_stats_write; | ||
| 484 | #endif /* STATS */ | 389 | #endif /* STATS */ |
| 485 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, | 390 | proc_create("cifsFYI", 0, proc_fs_cifs, &cifsFYI_proc_fops); |
| 486 | cifsFYI_read, NULL); | 391 | proc_create("traceSMB", 0, proc_fs_cifs, &traceSMB_proc_fops); |
| 487 | if (pde) | 392 | proc_create("OplockEnabled", 0, proc_fs_cifs, &cifs_oplock_proc_fops); |
| 488 | pde->write_proc = cifsFYI_write; | 393 | proc_create("Experimental", 0, proc_fs_cifs, |
| 489 | 394 | &cifs_experimental_proc_fops); | |
| 490 | pde = | 395 | proc_create("LinuxExtensionsEnabled", 0, proc_fs_cifs, |
| 491 | create_proc_read_entry("traceSMB", 0, proc_fs_cifs, | 396 | &cifs_linux_ext_proc_fops); |
| 492 | traceSMB_read, NULL); | 397 | proc_create("MultiuserMount", 0, proc_fs_cifs, |
| 493 | if (pde) | 398 | &cifs_multiuser_mount_proc_fops); |
| 494 | pde->write_proc = traceSMB_write; | 399 | proc_create("SecurityFlags", 0, proc_fs_cifs, |
| 495 | 400 | &cifs_security_flags_proc_fops); | |
| 496 | pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, | 401 | proc_create("LookupCacheEnabled", 0, proc_fs_cifs, |
| 497 | oplockEnabled_read, NULL); | 402 | &cifs_lookup_cache_proc_fops); |
| 498 | if (pde) | ||
| 499 | pde->write_proc = oplockEnabled_write; | ||
| 500 | |||
| 501 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, | ||
| 502 | experimEnabled_read, NULL); | ||
| 503 | if (pde) | ||
| 504 | pde->write_proc = experimEnabled_write; | ||
| 505 | |||
| 506 | pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, | ||
| 507 | linuxExtensionsEnabled_read, NULL); | ||
| 508 | if (pde) | ||
| 509 | pde->write_proc = linuxExtensionsEnabled_write; | ||
| 510 | |||
| 511 | pde = | ||
| 512 | create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, | ||
| 513 | multiuser_mount_read, NULL); | ||
| 514 | if (pde) | ||
| 515 | pde->write_proc = multiuser_mount_write; | ||
| 516 | |||
| 517 | pde = | ||
| 518 | create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, | ||
| 519 | security_flags_read, NULL); | ||
| 520 | if (pde) | ||
| 521 | pde->write_proc = security_flags_write; | ||
| 522 | |||
| 523 | pde = | ||
| 524 | create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, | ||
| 525 | lookupFlag_read, NULL); | ||
| 526 | if (pde) | ||
| 527 | pde->write_proc = lookupFlag_write; | ||
| 528 | |||
| 529 | /* pde = | ||
| 530 | create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, | ||
| 531 | ntlmv2_enabled_read, NULL); | ||
| 532 | if (pde) | ||
| 533 | pde->write_proc = ntlmv2_enabled_write; | ||
| 534 | |||
| 535 | pde = | ||
| 536 | create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, | ||
| 537 | packet_signing_enabled_read, NULL); | ||
| 538 | if (pde) | ||
| 539 | pde->write_proc = packet_signing_enabled_write;*/ | ||
| 540 | } | 403 | } |
| 541 | 404 | ||
| 542 | void | 405 | void |
| @@ -553,39 +416,26 @@ cifs_proc_clean(void) | |||
| 553 | #endif | 416 | #endif |
| 554 | remove_proc_entry("MultiuserMount", proc_fs_cifs); | 417 | remove_proc_entry("MultiuserMount", proc_fs_cifs); |
| 555 | remove_proc_entry("OplockEnabled", proc_fs_cifs); | 418 | remove_proc_entry("OplockEnabled", proc_fs_cifs); |
| 556 | /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ | ||
| 557 | remove_proc_entry("SecurityFlags", proc_fs_cifs); | 419 | remove_proc_entry("SecurityFlags", proc_fs_cifs); |
| 558 | /* remove_proc_entry("PacketSigningEnabled", proc_fs_cifs); */ | ||
| 559 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); | 420 | remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs); |
| 560 | remove_proc_entry("Experimental", proc_fs_cifs); | 421 | remove_proc_entry("Experimental", proc_fs_cifs); |
| 561 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); | 422 | remove_proc_entry("LookupCacheEnabled", proc_fs_cifs); |
| 562 | remove_proc_entry("fs/cifs", NULL); | 423 | remove_proc_entry("fs/cifs", NULL); |
| 563 | } | 424 | } |
| 564 | 425 | ||
| 565 | static int | 426 | static int cifsFYI_proc_show(struct seq_file *m, void *v) |
| 566 | cifsFYI_read(char *page, char **start, off_t off, int count, | ||
| 567 | int *eof, void *data) | ||
| 568 | { | 427 | { |
| 569 | int len; | 428 | seq_printf(m, "%d\n", cifsFYI); |
| 570 | 429 | return 0; | |
| 571 | len = sprintf(page, "%d\n", cifsFYI); | 430 | } |
| 572 | |||
| 573 | len -= off; | ||
| 574 | *start = page + off; | ||
| 575 | |||
| 576 | if (len > count) | ||
| 577 | len = count; | ||
| 578 | else | ||
| 579 | *eof = 1; | ||
| 580 | |||
| 581 | if (len < 0) | ||
| 582 | len = 0; | ||
| 583 | 431 | ||
| 584 | return len; | 432 | static int cifsFYI_proc_open(struct inode *inode, struct file *file) |
| 433 | { | ||
| 434 | return single_open(file, cifsFYI_proc_show, NULL); | ||
| 585 | } | 435 | } |
| 586 | static int | 436 | |
| 587 | cifsFYI_write(struct file *file, const char __user *buffer, | 437 | static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer, |
| 588 | unsigned long count, void *data) | 438 | size_t count, loff_t *ppos) |
| 589 | { | 439 | { |
| 590 | char c; | 440 | char c; |
| 591 | int rc; | 441 | int rc; |
| @@ -603,30 +453,28 @@ cifsFYI_write(struct file *file, const char __user *buffer, | |||
| 603 | return count; | 453 | return count; |
| 604 | } | 454 | } |
| 605 | 455 | ||
| 606 | static int | 456 | static const struct file_operations cifsFYI_proc_fops = { |
| 607 | oplockEnabled_read(char *page, char **start, off_t off, | 457 | .owner = THIS_MODULE, |
| 608 | int count, int *eof, void *data) | 458 | .open = cifsFYI_proc_open, |
| 609 | { | 459 | .read = seq_read, |
| 610 | int len; | 460 | .llseek = seq_lseek, |
| 611 | 461 | .release = single_release, | |
| 612 | len = sprintf(page, "%d\n", oplockEnabled); | 462 | .write = cifsFYI_proc_write, |
| 613 | 463 | }; | |
| 614 | len -= off; | ||
| 615 | *start = page + off; | ||
| 616 | 464 | ||
| 617 | if (len > count) | 465 | static int cifs_oplock_proc_show(struct seq_file *m, void *v) |
| 618 | len = count; | 466 | { |
| 619 | else | 467 | seq_printf(m, "%d\n", oplockEnabled); |
| 620 | *eof = 1; | 468 | return 0; |
| 621 | 469 | } | |
| 622 | if (len < 0) | ||
| 623 | len = 0; | ||
| 624 | 470 | ||
| 625 | return len; | 471 | static int cifs_oplock_proc_open(struct inode *inode, struct file *file) |
| 472 | { | ||
| 473 | return single_open(file, cifs_oplock_proc_show, NULL); | ||
| 626 | } | 474 | } |
| 627 | static int | 475 | |
| 628 | oplockEnabled_write(struct file *file, const char __user *buffer, | 476 | static ssize_t cifs_oplock_proc_write(struct file *file, |
| 629 | unsigned long count, void *data) | 477 | const char __user *buffer, size_t count, loff_t *ppos) |
| 630 | { | 478 | { |
| 631 | char c; | 479 | char c; |
| 632 | int rc; | 480 | int rc; |
| @@ -642,30 +490,28 @@ oplockEnabled_write(struct file *file, const char __user *buffer, | |||
| 642 | return count; | 490 | return count; |
| 643 | } | 491 | } |
| 644 | 492 | ||
| 645 | static int | 493 | static const struct file_operations cifs_oplock_proc_fops = { |
| 646 | experimEnabled_read(char *page, char **start, off_t off, | 494 | .owner = THIS_MODULE, |
| 647 | int count, int *eof, void *data) | 495 | .open = cifs_oplock_proc_open, |
| 648 | { | 496 | .read = seq_read, |
| 649 | int len; | 497 | .llseek = seq_lseek, |
| 650 | 498 | .release = single_release, | |
| 651 | len = sprintf(page, "%d\n", experimEnabled); | 499 | .write = cifs_oplock_proc_write, |
| 500 | }; | ||
| 652 | 501 | ||
| 653 | len -= off; | 502 | static int cifs_experimental_proc_show(struct seq_file *m, void *v) |
| 654 | *start = page + off; | 503 | { |
| 655 | 504 | seq_printf(m, "%d\n", experimEnabled); | |
| 656 | if (len > count) | 505 | return 0; |
| 657 | len = count; | 506 | } |
| 658 | else | ||
| 659 | *eof = 1; | ||
| 660 | |||
| 661 | if (len < 0) | ||
| 662 | len = 0; | ||
| 663 | 507 | ||
| 664 | return len; | 508 | static int cifs_experimental_proc_open(struct inode *inode, struct file *file) |
| 509 | { | ||
| 510 | return single_open(file, cifs_experimental_proc_show, NULL); | ||
| 665 | } | 511 | } |
| 666 | static int | 512 | |
| 667 | experimEnabled_write(struct file *file, const char __user *buffer, | 513 | static ssize_t cifs_experimental_proc_write(struct file *file, |
| 668 | unsigned long count, void *data) | 514 | const char __user *buffer, size_t count, loff_t *ppos) |
| 669 | { | 515 | { |
| 670 | char c; | 516 | char c; |
| 671 | int rc; | 517 | int rc; |
| @@ -683,29 +529,28 @@ experimEnabled_write(struct file *file, const char __user *buffer, | |||
| 683 | return count; | 529 | return count; |
| 684 | } | 530 | } |
| 685 | 531 | ||
| 686 | static int | 532 | static const struct file_operations cifs_experimental_proc_fops = { |
| 687 | linuxExtensionsEnabled_read(char *page, char **start, off_t off, | 533 | .owner = THIS_MODULE, |
| 688 | int count, int *eof, void *data) | 534 | .open = cifs_experimental_proc_open, |
| 689 | { | 535 | .read = seq_read, |
| 690 | int len; | 536 | .llseek = seq_lseek, |
| 691 | 537 | .release = single_release, | |
| 692 | len = sprintf(page, "%d\n", linuxExtEnabled); | 538 | .write = cifs_experimental_proc_write, |
| 693 | len -= off; | 539 | }; |
| 694 | *start = page + off; | ||
| 695 | 540 | ||
| 696 | if (len > count) | 541 | static int cifs_linux_ext_proc_show(struct seq_file *m, void *v) |
| 697 | len = count; | 542 | { |
| 698 | else | 543 | seq_printf(m, "%d\n", linuxExtEnabled); |
| 699 | *eof = 1; | 544 | return 0; |
| 700 | 545 | } | |
| 701 | if (len < 0) | ||
| 702 | len = 0; | ||
| 703 | 546 | ||
| 704 | return len; | 547 | static int cifs_linux_ext_proc_open(struct inode *inode, struct file *file) |
| 548 | { | ||
| 549 | return single_open(file, cifs_linux_ext_proc_show, NULL); | ||
| 705 | } | 550 | } |
| 706 | static int | 551 | |
| 707 | linuxExtensionsEnabled_write(struct file *file, const char __user *buffer, | 552 | static ssize_t cifs_linux_ext_proc_write(struct file *file, |
| 708 | unsigned long count, void *data) | 553 | const char __user *buffer, size_t count, loff_t *ppos) |
| 709 | { | 554 | { |
| 710 | char c; | 555 | char c; |
| 711 | int rc; | 556 | int rc; |
| @@ -721,31 +566,28 @@ linuxExtensionsEnabled_write(struct file *file, const char __user *buffer, | |||
| 721 | return count; | 566 | return count; |
| 722 | } | 567 | } |
| 723 | 568 | ||
| 569 | static const struct file_operations cifs_linux_ext_proc_fops = { | ||
| 570 | .owner = THIS_MODULE, | ||
| 571 | .open = cifs_linux_ext_proc_open, | ||
| 572 | .read = seq_read, | ||
| 573 | .llseek = seq_lseek, | ||
| 574 | .release = single_release, | ||
| 575 | .write = cifs_linux_ext_proc_write, | ||
| 576 | }; | ||
| 724 | 577 | ||
| 725 | static int | 578 | static int cifs_lookup_cache_proc_show(struct seq_file *m, void *v) |
| 726 | lookupFlag_read(char *page, char **start, off_t off, | ||
| 727 | int count, int *eof, void *data) | ||
| 728 | { | 579 | { |
| 729 | int len; | 580 | seq_printf(m, "%d\n", lookupCacheEnabled); |
| 730 | 581 | return 0; | |
| 731 | len = sprintf(page, "%d\n", lookupCacheEnabled); | 582 | } |
| 732 | |||
| 733 | len -= off; | ||
| 734 | *start = page + off; | ||
| 735 | |||
| 736 | if (len > count) | ||
| 737 | len = count; | ||
| 738 | else | ||
| 739 | *eof = 1; | ||
| 740 | |||
| 741 | if (len < 0) | ||
| 742 | len = 0; | ||
| 743 | 583 | ||
| 744 | return len; | 584 | static int cifs_lookup_cache_proc_open(struct inode *inode, struct file *file) |
| 585 | { | ||
| 586 | return single_open(file, cifs_lookup_cache_proc_show, NULL); | ||
| 745 | } | 587 | } |
| 746 | static int | 588 | |
| 747 | lookupFlag_write(struct file *file, const char __user *buffer, | 589 | static ssize_t cifs_lookup_cache_proc_write(struct file *file, |
| 748 | unsigned long count, void *data) | 590 | const char __user *buffer, size_t count, loff_t *ppos) |
| 749 | { | 591 | { |
| 750 | char c; | 592 | char c; |
| 751 | int rc; | 593 | int rc; |
| @@ -760,30 +602,29 @@ lookupFlag_write(struct file *file, const char __user *buffer, | |||
| 760 | 602 | ||
| 761 | return count; | 603 | return count; |
| 762 | } | 604 | } |
| 763 | static int | ||
| 764 | traceSMB_read(char *page, char **start, off_t off, int count, | ||
| 765 | int *eof, void *data) | ||
| 766 | { | ||
| 767 | int len; | ||
| 768 | |||
| 769 | len = sprintf(page, "%d\n", traceSMB); | ||
| 770 | |||
| 771 | len -= off; | ||
| 772 | *start = page + off; | ||
| 773 | 605 | ||
| 774 | if (len > count) | 606 | static const struct file_operations cifs_lookup_cache_proc_fops = { |
| 775 | len = count; | 607 | .owner = THIS_MODULE, |
| 776 | else | 608 | .open = cifs_lookup_cache_proc_open, |
| 777 | *eof = 1; | 609 | .read = seq_read, |
| 610 | .llseek = seq_lseek, | ||
| 611 | .release = single_release, | ||
| 612 | .write = cifs_lookup_cache_proc_write, | ||
| 613 | }; | ||
| 778 | 614 | ||
| 779 | if (len < 0) | 615 | static int traceSMB_proc_show(struct seq_file *m, void *v) |
| 780 | len = 0; | 616 | { |
| 617 | seq_printf(m, "%d\n", traceSMB); | ||
| 618 | return 0; | ||
| 619 | } | ||
| 781 | 620 | ||
| 782 | return len; | 621 | static int traceSMB_proc_open(struct inode *inode, struct file *file) |
| 622 | { | ||
| 623 | return single_open(file, traceSMB_proc_show, NULL); | ||
| 783 | } | 624 | } |
| 784 | static int | 625 | |
| 785 | traceSMB_write(struct file *file, const char __user *buffer, | 626 | static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer, |
| 786 | unsigned long count, void *data) | 627 | size_t count, loff_t *ppos) |
| 787 | { | 628 | { |
| 788 | char c; | 629 | char c; |
| 789 | int rc; | 630 | int rc; |
| @@ -799,30 +640,28 @@ traceSMB_write(struct file *file, const char __user *buffer, | |||
| 799 | return count; | 640 | return count; |
| 800 | } | 641 | } |
| 801 | 642 | ||
| 802 | static int | 643 | static const struct file_operations traceSMB_proc_fops = { |
| 803 | multiuser_mount_read(char *page, char **start, off_t off, | 644 | .owner = THIS_MODULE, |
| 804 | int count, int *eof, void *data) | 645 | .open = traceSMB_proc_open, |
| 805 | { | 646 | .read = seq_read, |
| 806 | int len; | 647 | .llseek = seq_lseek, |
| 807 | 648 | .release = single_release, | |
| 808 | len = sprintf(page, "%d\n", multiuser_mount); | 649 | .write = traceSMB_proc_write, |
| 809 | 650 | }; | |
| 810 | len -= off; | ||
| 811 | *start = page + off; | ||
| 812 | 651 | ||
| 813 | if (len > count) | 652 | static int cifs_multiuser_mount_proc_show(struct seq_file *m, void *v) |
| 814 | len = count; | 653 | { |
| 815 | else | 654 | seq_printf(m, "%d\n", multiuser_mount); |
| 816 | *eof = 1; | 655 | return 0; |
| 817 | 656 | } | |
| 818 | if (len < 0) | ||
| 819 | len = 0; | ||
| 820 | 657 | ||
| 821 | return len; | 658 | static int cifs_multiuser_mount_proc_open(struct inode *inode, struct file *fh) |
| 659 | { | ||
| 660 | return single_open(fh, cifs_multiuser_mount_proc_show, NULL); | ||
| 822 | } | 661 | } |
| 823 | static int | 662 | |
| 824 | multiuser_mount_write(struct file *file, const char __user *buffer, | 663 | static ssize_t cifs_multiuser_mount_proc_write(struct file *file, |
| 825 | unsigned long count, void *data) | 664 | const char __user *buffer, size_t count, loff_t *ppos) |
| 826 | { | 665 | { |
| 827 | char c; | 666 | char c; |
| 828 | int rc; | 667 | int rc; |
| @@ -838,30 +677,28 @@ multiuser_mount_write(struct file *file, const char __user *buffer, | |||
| 838 | return count; | 677 | return count; |
| 839 | } | 678 | } |
| 840 | 679 | ||
| 841 | static int | 680 | static const struct file_operations cifs_multiuser_mount_proc_fops = { |
| 842 | security_flags_read(char *page, char **start, off_t off, | 681 | .owner = THIS_MODULE, |
| 843 | int count, int *eof, void *data) | 682 | .open = cifs_multiuser_mount_proc_open, |
| 844 | { | 683 | .read = seq_read, |
| 845 | int len; | 684 | .llseek = seq_lseek, |
| 846 | 685 | .release = single_release, | |
| 847 | len = sprintf(page, "0x%x\n", extended_security); | 686 | .write = cifs_multiuser_mount_proc_write, |
| 848 | 687 | }; | |
| 849 | len -= off; | ||
| 850 | *start = page + off; | ||
| 851 | 688 | ||
| 852 | if (len > count) | 689 | static int cifs_security_flags_proc_show(struct seq_file *m, void *v) |
| 853 | len = count; | 690 | { |
| 854 | else | 691 | seq_printf(m, "0x%x\n", extended_security); |
| 855 | *eof = 1; | 692 | return 0; |
| 856 | 693 | } | |
| 857 | if (len < 0) | ||
| 858 | len = 0; | ||
| 859 | 694 | ||
| 860 | return len; | 695 | static int cifs_security_flags_proc_open(struct inode *inode, struct file *file) |
| 696 | { | ||
| 697 | return single_open(file, cifs_security_flags_proc_show, NULL); | ||
| 861 | } | 698 | } |
| 862 | static int | 699 | |
| 863 | security_flags_write(struct file *file, const char __user *buffer, | 700 | static ssize_t cifs_security_flags_proc_write(struct file *file, |
| 864 | unsigned long count, void *data) | 701 | const char __user *buffer, size_t count, loff_t *ppos) |
| 865 | { | 702 | { |
| 866 | unsigned int flags; | 703 | unsigned int flags; |
| 867 | char flags_string[12]; | 704 | char flags_string[12]; |
| @@ -917,6 +754,15 @@ security_flags_write(struct file *file, const char __user *buffer, | |||
| 917 | /* BB should we turn on MAY flags for other MUST options? */ | 754 | /* BB should we turn on MAY flags for other MUST options? */ |
| 918 | return count; | 755 | return count; |
| 919 | } | 756 | } |
| 757 | |||
| 758 | static const struct file_operations cifs_security_flags_proc_fops = { | ||
| 759 | .owner = THIS_MODULE, | ||
| 760 | .open = cifs_security_flags_proc_open, | ||
| 761 | .read = seq_read, | ||
| 762 | .llseek = seq_lseek, | ||
| 763 | .release = single_release, | ||
| 764 | .write = cifs_security_flags_proc_write, | ||
| 765 | }; | ||
| 920 | #else | 766 | #else |
| 921 | inline void cifs_proc_init(void) | 767 | inline void cifs_proc_init(void) |
| 922 | { | 768 | { |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index d82374c9e329..d2c8eef84f3c 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -226,7 +226,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 226 | int err; | 226 | int err; |
| 227 | 227 | ||
| 228 | mntget(newmnt); | 228 | mntget(newmnt); |
| 229 | err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); | 229 | err = do_add_mount(newmnt, &nd->path, nd->path.mnt->mnt_flags, mntlist); |
| 230 | switch (err) { | 230 | switch (err) { |
| 231 | case 0: | 231 | case 0: |
| 232 | path_put(&nd->path); | 232 | path_put(&nd->path); |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 7013aaff6aed..117ef4bba68e 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
| @@ -66,8 +66,8 @@ struct key_type cifs_spnego_key_type = { | |||
| 66 | .describe = user_describe, | 66 | .describe = user_describe, |
| 67 | }; | 67 | }; |
| 68 | 68 | ||
| 69 | #define MAX_VER_STR_LEN 9 /* length of longest version string e.g. | 69 | #define MAX_VER_STR_LEN 8 /* length of longest version string e.g. |
| 70 | strlen(";ver=0xFF") */ | 70 | strlen("ver=0xFF") */ |
| 71 | #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg | 71 | #define MAX_MECH_STR_LEN 13 /* length of longest security mechanism name, eg |
| 72 | in future could have strlen(";sec=ntlmsspi") */ | 72 | in future could have strlen(";sec=ntlmsspi") */ |
| 73 | #define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ | 73 | #define MAX_IPV6_ADDR_LEN 42 /* eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ |
| @@ -81,11 +81,15 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
| 81 | struct key *spnego_key; | 81 | struct key *spnego_key; |
| 82 | const char *hostname = server->hostname; | 82 | const char *hostname = server->hostname; |
| 83 | 83 | ||
| 84 | /* BB: come up with better scheme for determining length */ | 84 | /* length of fields (with semicolons): ver=0xyz ip4=ipaddress |
| 85 | /* length of fields (with semicolons): ver=0xyz ipv4= ipaddress host= | 85 | host=hostname sec=mechanism uid=0xFF user=username */ |
| 86 | hostname sec=mechanism uid=0x uid */ | 86 | desc_len = MAX_VER_STR_LEN + |
| 87 | desc_len = MAX_VER_STR_LEN + 5 + MAX_IPV6_ADDR_LEN + 1 + 6 + | 87 | 6 /* len of "host=" */ + strlen(hostname) + |
| 88 | strlen(hostname) + MAX_MECH_STR_LEN + 8 + (sizeof(uid_t) * 2); | 88 | 5 /* len of ";ipv4=" */ + MAX_IPV6_ADDR_LEN + |
| 89 | MAX_MECH_STR_LEN + | ||
| 90 | 7 /* len of ";uid=0x" */ + (sizeof(uid_t) * 2) + | ||
| 91 | 6 /* len of ";user=" */ + strlen(sesInfo->userName) + 1; | ||
| 92 | |||
| 89 | spnego_key = ERR_PTR(-ENOMEM); | 93 | spnego_key = ERR_PTR(-ENOMEM); |
| 90 | description = kzalloc(desc_len, GFP_KERNEL); | 94 | description = kzalloc(desc_len, GFP_KERNEL); |
| 91 | if (description == NULL) | 95 | if (description == NULL) |
| @@ -110,9 +114,11 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
| 110 | 114 | ||
| 111 | dp = description + strlen(description); | 115 | dp = description + strlen(description); |
| 112 | 116 | ||
| 113 | /* for now, only sec=krb5 is valid */ | 117 | /* for now, only sec=krb5 and sec=mskrb5 are valid */ |
| 114 | if (server->secType == Kerberos) | 118 | if (server->secType == Kerberos) |
| 115 | sprintf(dp, ";sec=krb5"); | 119 | sprintf(dp, ";sec=krb5"); |
| 120 | else if (server->secType == MSKerberos) | ||
| 121 | sprintf(dp, ";sec=mskrb5"); | ||
| 116 | else | 122 | else |
| 117 | goto out; | 123 | goto out; |
| 118 | 124 | ||
diff --git a/fs/cifs/cifs_spnego.h b/fs/cifs/cifs_spnego.h index 05a34b17a1ab..e4041ec4d712 100644 --- a/fs/cifs/cifs_spnego.h +++ b/fs/cifs/cifs_spnego.h | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #ifndef _CIFS_SPNEGO_H | 23 | #ifndef _CIFS_SPNEGO_H |
| 24 | #define _CIFS_SPNEGO_H | 24 | #define _CIFS_SPNEGO_H |
| 25 | 25 | ||
| 26 | #define CIFS_SPNEGO_UPCALL_VERSION 1 | 26 | #define CIFS_SPNEGO_UPCALL_VERSION 2 |
| 27 | 27 | ||
| 28 | /* | 28 | /* |
| 29 | * The version field should always be set to CIFS_SPNEGO_UPCALL_VERSION. | 29 | * The version field should always be set to CIFS_SPNEGO_UPCALL_VERSION. |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 0e9fc2ba90ee..57ecdc83c26f 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
| @@ -56,7 +56,7 @@ int match_sid(struct cifs_sid *ctsid) | |||
| 56 | struct cifs_sid *cwsid; | 56 | struct cifs_sid *cwsid; |
| 57 | 57 | ||
| 58 | if (!ctsid) | 58 | if (!ctsid) |
| 59 | return (-1); | 59 | return -1; |
| 60 | 60 | ||
| 61 | for (i = 0; i < NUM_WK_SIDS; ++i) { | 61 | for (i = 0; i < NUM_WK_SIDS; ++i) { |
| 62 | cwsid = &(wksidarr[i].cifssid); | 62 | cwsid = &(wksidarr[i].cifssid); |
| @@ -87,11 +87,11 @@ int match_sid(struct cifs_sid *ctsid) | |||
| 87 | } | 87 | } |
| 88 | 88 | ||
| 89 | cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname)); | 89 | cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname)); |
| 90 | return (0); /* sids compare/match */ | 90 | return 0; /* sids compare/match */ |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | cFYI(1, ("No matching sid")); | 93 | cFYI(1, ("No matching sid")); |
| 94 | return (-1); | 94 | return -1; |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are | 97 | /* if the two SIDs (roughly equivalent to a UUID for a user or group) are |
| @@ -102,16 +102,16 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
| 102 | int num_subauth, num_sat, num_saw; | 102 | int num_subauth, num_sat, num_saw; |
| 103 | 103 | ||
| 104 | if ((!ctsid) || (!cwsid)) | 104 | if ((!ctsid) || (!cwsid)) |
| 105 | return (0); | 105 | return 0; |
| 106 | 106 | ||
| 107 | /* compare the revision */ | 107 | /* compare the revision */ |
| 108 | if (ctsid->revision != cwsid->revision) | 108 | if (ctsid->revision != cwsid->revision) |
| 109 | return (0); | 109 | return 0; |
| 110 | 110 | ||
| 111 | /* compare all of the six auth values */ | 111 | /* compare all of the six auth values */ |
| 112 | for (i = 0; i < 6; ++i) { | 112 | for (i = 0; i < 6; ++i) { |
| 113 | if (ctsid->authority[i] != cwsid->authority[i]) | 113 | if (ctsid->authority[i] != cwsid->authority[i]) |
| 114 | return (0); | 114 | return 0; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /* compare all of the subauth values if any */ | 117 | /* compare all of the subauth values if any */ |
| @@ -121,11 +121,11 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) | |||
| 121 | if (num_subauth) { | 121 | if (num_subauth) { |
| 122 | for (i = 0; i < num_subauth; ++i) { | 122 | for (i = 0; i < num_subauth; ++i) { |
| 123 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) | 123 | if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) |
| 124 | return (0); | 124 | return 0; |
| 125 | } | 125 | } |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | return (1); /* sids compare/match */ | 128 | return 1; /* sids compare/match */ |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | 131 | ||
| @@ -169,8 +169,7 @@ static void copy_sec_desc(const struct cifs_ntsd *pntsd, | |||
| 169 | for (i = 0; i < 6; i++) | 169 | for (i = 0; i < 6; i++) |
| 170 | ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i]; | 170 | ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i]; |
| 171 | for (i = 0; i < 5; i++) | 171 | for (i = 0; i < 5; i++) |
| 172 | ngroup_sid_ptr->sub_auth[i] = | 172 | ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i]; |
| 173 | cpu_to_le32(group_sid_ptr->sub_auth[i]); | ||
| 174 | 173 | ||
| 175 | return; | 174 | return; |
| 176 | } | 175 | } |
| @@ -285,7 +284,7 @@ static __u16 fill_ace_for_sid(struct cifs_ace *pntace, | |||
| 285 | size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4); | 284 | size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4); |
| 286 | pntace->size = cpu_to_le16(size); | 285 | pntace->size = cpu_to_le16(size); |
| 287 | 286 | ||
| 288 | return (size); | 287 | return size; |
| 289 | } | 288 | } |
| 290 | 289 | ||
| 291 | 290 | ||
| @@ -426,7 +425,7 @@ static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, | |||
| 426 | pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); | 425 | pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); |
| 427 | pndacl->num_aces = cpu_to_le32(3); | 426 | pndacl->num_aces = cpu_to_le32(3); |
| 428 | 427 | ||
| 429 | return (0); | 428 | return 0; |
| 430 | } | 429 | } |
| 431 | 430 | ||
| 432 | 431 | ||
| @@ -510,7 +509,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
| 510 | sizeof(struct cifs_sid)); */ | 509 | sizeof(struct cifs_sid)); */ |
| 511 | 510 | ||
| 512 | 511 | ||
| 513 | return (0); | 512 | return 0; |
| 514 | } | 513 | } |
| 515 | 514 | ||
| 516 | 515 | ||
| @@ -527,7 +526,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
| 527 | struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ | 526 | struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ |
| 528 | 527 | ||
| 529 | if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL)) | 528 | if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL)) |
| 530 | return (-EIO); | 529 | return -EIO; |
| 531 | 530 | ||
| 532 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 531 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
| 533 | le32_to_cpu(pntsd->osidoffset)); | 532 | le32_to_cpu(pntsd->osidoffset)); |
| @@ -550,7 +549,7 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, | |||
| 550 | /* copy security descriptor control portion and owner and group sid */ | 549 | /* copy security descriptor control portion and owner and group sid */ |
| 551 | copy_sec_desc(pntsd, pnntsd, sidsoffset); | 550 | copy_sec_desc(pntsd, pnntsd, sidsoffset); |
| 552 | 551 | ||
| 553 | return (rc); | 552 | return rc; |
| 554 | } | 553 | } |
| 555 | 554 | ||
| 556 | 555 | ||
| @@ -629,11 +628,11 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
| 629 | cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode)); | 628 | cFYI(DBG2, ("set ACL for %s from mode 0x%x", path, inode->i_mode)); |
| 630 | 629 | ||
| 631 | if (!inode) | 630 | if (!inode) |
| 632 | return (rc); | 631 | return rc; |
| 633 | 632 | ||
| 634 | sb = inode->i_sb; | 633 | sb = inode->i_sb; |
| 635 | if (sb == NULL) | 634 | if (sb == NULL) |
| 636 | return (rc); | 635 | return rc; |
| 637 | 636 | ||
| 638 | cifs_sb = CIFS_SB(sb); | 637 | cifs_sb = CIFS_SB(sb); |
| 639 | xid = GetXid(); | 638 | xid = GetXid(); |
| @@ -652,7 +651,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
| 652 | if (rc != 0) { | 651 | if (rc != 0) { |
| 653 | cERROR(1, ("Unable to open file to set ACL")); | 652 | cERROR(1, ("Unable to open file to set ACL")); |
| 654 | FreeXid(xid); | 653 | FreeXid(xid); |
| 655 | return (rc); | 654 | return rc; |
| 656 | } | 655 | } |
| 657 | } | 656 | } |
| 658 | 657 | ||
| @@ -665,7 +664,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
| 665 | 664 | ||
| 666 | FreeXid(xid); | 665 | FreeXid(xid); |
| 667 | 666 | ||
| 668 | return (rc); | 667 | return rc; |
| 669 | } | 668 | } |
| 670 | 669 | ||
| 671 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 670 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
| @@ -715,7 +714,7 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
| 715 | if (!pnntsd) { | 714 | if (!pnntsd) { |
| 716 | cERROR(1, ("Unable to allocate security descriptor")); | 715 | cERROR(1, ("Unable to allocate security descriptor")); |
| 717 | kfree(pntsd); | 716 | kfree(pntsd); |
| 718 | return (-ENOMEM); | 717 | return -ENOMEM; |
| 719 | } | 718 | } |
| 720 | 719 | ||
| 721 | rc = build_sec_desc(pntsd, pnntsd, inode, nmode); | 720 | rc = build_sec_desc(pntsd, pnntsd, inode, nmode); |
| @@ -732,6 +731,6 @@ int mode_to_acl(struct inode *inode, const char *path, __u64 nmode) | |||
| 732 | kfree(pntsd); | 731 | kfree(pntsd); |
| 733 | } | 732 | } |
| 734 | 733 | ||
| 735 | return (rc); | 734 | return rc; |
| 736 | } | 735 | } |
| 737 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 736 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 4ff8939c6cc7..bd5f13d38450 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -294,6 +294,7 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key) | |||
| 294 | 294 | ||
| 295 | if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) | 295 | if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) |
| 296 | if (extended_security & CIFSSEC_MAY_PLNTXT) { | 296 | if (extended_security & CIFSSEC_MAY_PLNTXT) { |
| 297 | memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE); | ||
| 297 | memcpy(lnm_session_key, password_with_pad, | 298 | memcpy(lnm_session_key, password_with_pad, |
| 298 | CIFS_ENCPWD_SIZE); | 299 | CIFS_ENCPWD_SIZE); |
| 299 | return; | 300 | return; |
| @@ -310,9 +311,8 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key) | |||
| 310 | utf8 and other multibyte codepages each need their own strupper | 311 | utf8 and other multibyte codepages each need their own strupper |
| 311 | function since a byte at a time will ont work. */ | 312 | function since a byte at a time will ont work. */ |
| 312 | 313 | ||
| 313 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) { | 314 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) |
| 314 | password_with_pad[i] = toupper(password_with_pad[i]); | 315 | password_with_pad[i] = toupper(password_with_pad[i]); |
| 315 | } | ||
| 316 | 316 | ||
| 317 | SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); | 317 | SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); |
| 318 | /* clear password before we return/free memory */ | 318 | /* clear password before we return/free memory */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 22857c639df5..25ecbd5b0404 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -175,6 +175,8 @@ out_no_root: | |||
| 175 | if (inode) | 175 | if (inode) |
| 176 | iput(inode); | 176 | iput(inode); |
| 177 | 177 | ||
| 178 | cifs_umount(sb, cifs_sb); | ||
| 179 | |||
| 178 | out_mount_failed: | 180 | out_mount_failed: |
| 179 | if (cifs_sb) { | 181 | if (cifs_sb) { |
| 180 | #ifdef CONFIG_CIFS_DFS_UPCALL | 182 | #ifdef CONFIG_CIFS_DFS_UPCALL |
| @@ -267,7 +269,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 267 | return 0; | 269 | return 0; |
| 268 | } | 270 | } |
| 269 | 271 | ||
| 270 | static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd) | 272 | static int cifs_permission(struct inode *inode, int mask) |
| 271 | { | 273 | { |
| 272 | struct cifs_sb_info *cifs_sb; | 274 | struct cifs_sb_info *cifs_sb; |
| 273 | 275 | ||
| @@ -766,7 +768,7 @@ const struct file_operations cifs_dir_ops = { | |||
| 766 | }; | 768 | }; |
| 767 | 769 | ||
| 768 | static void | 770 | static void |
| 769 | cifs_init_once(struct kmem_cache *cachep, void *inode) | 771 | cifs_init_once(void *inode) |
| 770 | { | 772 | { |
| 771 | struct cifsInodeInfo *cifsi = inode; | 773 | struct cifsInodeInfo *cifsi = inode; |
| 772 | 774 | ||
| @@ -930,36 +932,34 @@ static int cifs_oplock_thread(void *dummyarg) | |||
| 930 | schedule_timeout(39*HZ); | 932 | schedule_timeout(39*HZ); |
| 931 | } else { | 933 | } else { |
| 932 | oplock_item = list_entry(GlobalOplock_Q.next, | 934 | oplock_item = list_entry(GlobalOplock_Q.next, |
| 933 | struct oplock_q_entry, qhead); | 935 | struct oplock_q_entry, qhead); |
| 934 | if (oplock_item) { | 936 | cFYI(1, ("found oplock item to write out")); |
| 935 | cFYI(1, ("found oplock item to write out")); | 937 | pTcon = oplock_item->tcon; |
| 936 | pTcon = oplock_item->tcon; | 938 | inode = oplock_item->pinode; |
| 937 | inode = oplock_item->pinode; | 939 | netfid = oplock_item->netfid; |
| 938 | netfid = oplock_item->netfid; | 940 | spin_unlock(&GlobalMid_Lock); |
| 939 | spin_unlock(&GlobalMid_Lock); | 941 | DeleteOplockQEntry(oplock_item); |
| 940 | DeleteOplockQEntry(oplock_item); | 942 | /* can not grab inode sem here since it would |
| 941 | /* can not grab inode sem here since it would | ||
| 942 | deadlock when oplock received on delete | 943 | deadlock when oplock received on delete |
| 943 | since vfs_unlink holds the i_mutex across | 944 | since vfs_unlink holds the i_mutex across |
| 944 | the call */ | 945 | the call */ |
| 945 | /* mutex_lock(&inode->i_mutex);*/ | 946 | /* mutex_lock(&inode->i_mutex);*/ |
| 946 | if (S_ISREG(inode->i_mode)) { | 947 | if (S_ISREG(inode->i_mode)) { |
| 947 | rc = | 948 | rc = filemap_fdatawrite(inode->i_mapping); |
| 948 | filemap_fdatawrite(inode->i_mapping); | 949 | if (CIFS_I(inode)->clientCanCacheRead == 0) { |
| 949 | if (CIFS_I(inode)->clientCanCacheRead | 950 | waitrc = filemap_fdatawait( |
| 950 | == 0) { | 951 | inode->i_mapping); |
| 951 | waitrc = filemap_fdatawait(inode->i_mapping); | 952 | invalidate_remote_inode(inode); |
| 952 | invalidate_remote_inode(inode); | 953 | } |
| 953 | } | 954 | if (rc == 0) |
| 954 | if (rc == 0) | 955 | rc = waitrc; |
| 955 | rc = waitrc; | 956 | } else |
| 956 | } else | 957 | rc = 0; |
| 957 | rc = 0; | 958 | /* mutex_unlock(&inode->i_mutex);*/ |
| 958 | /* mutex_unlock(&inode->i_mutex);*/ | 959 | if (rc) |
| 959 | if (rc) | 960 | CIFS_I(inode)->write_behind_rc = rc; |
| 960 | CIFS_I(inode)->write_behind_rc = rc; | 961 | cFYI(1, ("Oplock flush inode %p rc %d", |
| 961 | cFYI(1, ("Oplock flush inode %p rc %d", | 962 | inode, rc)); |
| 962 | inode, rc)); | ||
| 963 | 963 | ||
| 964 | /* releasing stale oplock after recent reconnect | 964 | /* releasing stale oplock after recent reconnect |
| 965 | of smb session using a now incorrect file | 965 | of smb session using a now incorrect file |
| @@ -967,15 +967,13 @@ static int cifs_oplock_thread(void *dummyarg) | |||
| 967 | not bother sending an oplock release if session | 967 | not bother sending an oplock release if session |
| 968 | to server still is disconnected since oplock | 968 | to server still is disconnected since oplock |
| 969 | already released by the server in that case */ | 969 | already released by the server in that case */ |
| 970 | if (pTcon->tidStatus != CifsNeedReconnect) { | 970 | if (pTcon->tidStatus != CifsNeedReconnect) { |
| 971 | rc = CIFSSMBLock(0, pTcon, netfid, | 971 | rc = CIFSSMBLock(0, pTcon, netfid, |
| 972 | 0 /* len */ , 0 /* offset */, 0, | 972 | 0 /* len */ , 0 /* offset */, 0, |
| 973 | 0, LOCKING_ANDX_OPLOCK_RELEASE, | 973 | 0, LOCKING_ANDX_OPLOCK_RELEASE, |
| 974 | false /* wait flag */); | 974 | false /* wait flag */); |
| 975 | cFYI(1, ("Oplock release rc = %d", rc)); | 975 | cFYI(1, ("Oplock release rc = %d", rc)); |
| 976 | } | 976 | } |
| 977 | } else | ||
| 978 | spin_unlock(&GlobalMid_Lock); | ||
| 979 | set_current_state(TASK_INTERRUPTIBLE); | 977 | set_current_state(TASK_INTERRUPTIBLE); |
| 980 | schedule_timeout(1); /* yield in case q were corrupt */ | 978 | schedule_timeout(1); /* yield in case q were corrupt */ |
| 981 | } | 979 | } |
| @@ -1001,8 +999,7 @@ static int cifs_dnotify_thread(void *dummyarg) | |||
| 1001 | list_for_each(tmp, &GlobalSMBSessionList) { | 999 | list_for_each(tmp, &GlobalSMBSessionList) { |
| 1002 | ses = list_entry(tmp, struct cifsSesInfo, | 1000 | ses = list_entry(tmp, struct cifsSesInfo, |
| 1003 | cifsSessionList); | 1001 | cifsSessionList); |
| 1004 | if (ses && ses->server && | 1002 | if (ses->server && atomic_read(&ses->server->inFlight)) |
| 1005 | atomic_read(&ses->server->inFlight)) | ||
| 1006 | wake_up_all(&ses->server->response_q); | 1003 | wake_up_all(&ses->server->response_q); |
| 1007 | } | 1004 | } |
| 1008 | read_unlock(&GlobalSMBSeslock); | 1005 | read_unlock(&GlobalSMBSeslock); |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 25a6cbd15529..135c965c4137 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
| 101 | extern const struct export_operations cifs_export_ops; | 101 | extern const struct export_operations cifs_export_ops; |
| 102 | #endif /* EXPERIMENTAL */ | 102 | #endif /* EXPERIMENTAL */ |
| 103 | 103 | ||
| 104 | #define CIFS_VERSION "1.53" | 104 | #define CIFS_VERSION "1.54" |
| 105 | #endif /* _CIFSFS_H */ | 105 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9cfcf326ead3..8dfd6f24d488 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | #define MAX_SES_INFO 2 | 27 | #define MAX_SES_INFO 2 |
| 28 | #define MAX_TCON_INFO 4 | 28 | #define MAX_TCON_INFO 4 |
| 29 | 29 | ||
| 30 | #define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 | 30 | #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) |
| 31 | #define MAX_SERVER_SIZE 15 | 31 | #define MAX_SERVER_SIZE 15 |
| 32 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ | 32 | #define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */ |
| 33 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null | 33 | #define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null |
| @@ -80,7 +80,8 @@ enum securityEnum { | |||
| 80 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 80 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
| 81 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ | 81 | RawNTLMSSP, /* NTLMSSP without SPNEGO */ |
| 82 | NTLMSSP, /* NTLMSSP via SPNEGO */ | 82 | NTLMSSP, /* NTLMSSP via SPNEGO */ |
| 83 | Kerberos /* Kerberos via SPNEGO */ | 83 | Kerberos, /* Kerberos via SPNEGO */ |
| 84 | MSKerberos, /* MS Kerberos via SPNEGO */ | ||
| 84 | }; | 85 | }; |
| 85 | 86 | ||
| 86 | enum protocolEnum { | 87 | enum protocolEnum { |
| @@ -537,8 +538,8 @@ require use of the stronger protocol */ | |||
| 537 | #endif /* WEAK_PW_HASH */ | 538 | #endif /* WEAK_PW_HASH */ |
| 538 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ | 539 | #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ |
| 539 | 540 | ||
| 540 | #define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | 541 | #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2) |
| 541 | #define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2 | 542 | #define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) |
| 542 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) | 543 | #define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) |
| 543 | /* | 544 | /* |
| 544 | ***************************************************************** | 545 | ***************************************************************** |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 0f327c224da3..d2a073edd1b8 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | #else | 31 | #else |
| 32 | #define CIFS_PROT 0 | 32 | #define CIFS_PROT 0 |
| 33 | #endif | 33 | #endif |
| 34 | #define POSIX_PROT CIFS_PROT+1 | 34 | #define POSIX_PROT (CIFS_PROT+1) |
| 35 | #define BAD_PROT 0xFFFF | 35 | #define BAD_PROT 0xFFFF |
| 36 | 36 | ||
| 37 | /* SMB command codes */ | 37 | /* SMB command codes */ |
| @@ -262,7 +262,7 @@ | |||
| 262 | */ | 262 | */ |
| 263 | #define CIFS_NO_HANDLE 0xFFFF | 263 | #define CIFS_NO_HANDLE 0xFFFF |
| 264 | 264 | ||
| 265 | #define NO_CHANGE_64 cpu_to_le64(0xFFFFFFFFFFFFFFFFULL) | 265 | #define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL |
| 266 | #define NO_CHANGE_32 0xFFFFFFFFUL | 266 | #define NO_CHANGE_32 0xFFFFFFFFUL |
| 267 | 267 | ||
| 268 | /* IPC$ in ASCII */ | 268 | /* IPC$ in ASCII */ |
| @@ -341,7 +341,7 @@ | |||
| 341 | #define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */ | 341 | #define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */ |
| 342 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 | 342 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 |
| 343 | #define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete | 343 | #define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete |
| 344 | "open for recovery" flag - should | 344 | "open for recovery" flag should |
| 345 | be zero in any case */ | 345 | be zero in any case */ |
| 346 | #define CREATE_OPEN_FOR_RECOVERY 0x00000400 | 346 | #define CREATE_OPEN_FOR_RECOVERY 0x00000400 |
| 347 | #define CREATE_RANDOM_ACCESS 0x00000800 | 347 | #define CREATE_RANDOM_ACCESS 0x00000800 |
| @@ -414,8 +414,8 @@ struct smb_hdr { | |||
| 414 | __u8 WordCount; | 414 | __u8 WordCount; |
| 415 | } __attribute__((packed)); | 415 | } __attribute__((packed)); |
| 416 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | 416 | /* given a pointer to an smb_hdr retrieve the value of byte count */ |
| 417 | #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) | 417 | #define BCC(smb_var) (*(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) |
| 418 | #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) | 418 | #define BCC_LE(smb_var) (*(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) |
| 419 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ | 419 | /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ |
| 420 | #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2) | 420 | #define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2) |
| 421 | 421 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b9f5e935f821..a729d083e6f4 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -172,12 +172,13 @@ extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon); | |||
| 172 | extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 172 | extern int CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |
| 173 | struct kstatfs *FSData); | 173 | struct kstatfs *FSData); |
| 174 | 174 | ||
| 175 | extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, | 175 | extern int CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, |
| 176 | const char *fileName, const FILE_BASIC_INFO *data, | 176 | const char *fileName, const FILE_BASIC_INFO *data, |
| 177 | const struct nls_table *nls_codepage, | 177 | const struct nls_table *nls_codepage, |
| 178 | int remap_special_chars); | 178 | int remap_special_chars); |
| 179 | extern int CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | 179 | extern int CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, |
| 180 | const FILE_BASIC_INFO *data, __u16 fid); | 180 | const FILE_BASIC_INFO *data, __u16 fid, |
| 181 | __u32 pid_of_opener); | ||
| 181 | #if 0 | 182 | #if 0 |
| 182 | extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, | 183 | extern int CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, |
| 183 | char *fileName, __u16 dos_attributes, | 184 | char *fileName, __u16 dos_attributes, |
| @@ -191,9 +192,20 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, | |||
| 191 | extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, | 192 | extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, |
| 192 | __u64 size, __u16 fileHandle, __u32 opener_pid, | 193 | __u64 size, __u16 fileHandle, __u32 opener_pid, |
| 193 | bool AllocSizeFlag); | 194 | bool AllocSizeFlag); |
| 194 | extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, | 195 | |
| 195 | char *full_path, __u64 mode, __u64 uid, | 196 | struct cifs_unix_set_info_args { |
| 196 | __u64 gid, dev_t dev, | 197 | __u64 ctime; |
| 198 | __u64 atime; | ||
| 199 | __u64 mtime; | ||
| 200 | __u64 mode; | ||
| 201 | __u64 uid; | ||
| 202 | __u64 gid; | ||
| 203 | dev_t device; | ||
| 204 | }; | ||
| 205 | |||
| 206 | extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon, | ||
| 207 | char *fileName, | ||
| 208 | const struct cifs_unix_set_info_args *args, | ||
| 197 | const struct nls_table *nls_codepage, | 209 | const struct nls_table *nls_codepage, |
| 198 | int remap_special_chars); | 210 | int remap_special_chars); |
| 199 | 211 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4511b708f0f3..994de7c90474 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -128,8 +128,7 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) | |||
| 128 | write_lock(&GlobalSMBSeslock); | 128 | write_lock(&GlobalSMBSeslock); |
| 129 | list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { | 129 | list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { |
| 130 | open_file = list_entry(tmp, struct cifsFileInfo, tlist); | 130 | open_file = list_entry(tmp, struct cifsFileInfo, tlist); |
| 131 | if (open_file) | 131 | open_file->invalidHandle = true; |
| 132 | open_file->invalidHandle = true; | ||
| 133 | } | 132 | } |
| 134 | write_unlock(&GlobalSMBSeslock); | 133 | write_unlock(&GlobalSMBSeslock); |
| 135 | /* BB Add call to invalidate_inodes(sb) for all superblocks mounted | 134 | /* BB Add call to invalidate_inodes(sb) for all superblocks mounted |
| @@ -686,11 +685,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 686 | SecurityBlob, | 685 | SecurityBlob, |
| 687 | count - 16, | 686 | count - 16, |
| 688 | &server->secType); | 687 | &server->secType); |
| 689 | if (rc == 1) { | 688 | if (rc == 1) |
| 690 | rc = 0; | 689 | rc = 0; |
| 691 | } else { | 690 | else |
| 692 | rc = -EINVAL; | 691 | rc = -EINVAL; |
| 693 | } | ||
| 694 | } | 692 | } |
| 695 | } else | 693 | } else |
| 696 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | 694 | server->capabilities &= ~CAP_EXTENDED_SECURITY; |
| @@ -3914,7 +3912,10 @@ parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, | |||
| 3914 | bool is_unicode; | 3912 | bool is_unicode; |
| 3915 | struct dfs_referral_level_3 *ref; | 3913 | struct dfs_referral_level_3 *ref; |
| 3916 | 3914 | ||
| 3917 | is_unicode = pSMBr->hdr.Flags2 & SMBFLG2_UNICODE; | 3915 | if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) |
| 3916 | is_unicode = true; | ||
| 3917 | else | ||
| 3918 | is_unicode = false; | ||
| 3918 | *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); | 3919 | *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals); |
| 3919 | 3920 | ||
| 3920 | if (*num_of_nodes < 1) { | 3921 | if (*num_of_nodes < 1) { |
| @@ -4814,8 +4815,8 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, | |||
| 4814 | time and resort to the original setpathinfo level which takes the ancient | 4815 | time and resort to the original setpathinfo level which takes the ancient |
| 4815 | DOS time format with 2 second granularity */ | 4816 | DOS time format with 2 second granularity */ |
| 4816 | int | 4817 | int |
| 4817 | CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | 4818 | CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon, |
| 4818 | const FILE_BASIC_INFO *data, __u16 fid) | 4819 | const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener) |
| 4819 | { | 4820 | { |
| 4820 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | 4821 | struct smb_com_transaction2_sfi_req *pSMB = NULL; |
| 4821 | char *data_offset; | 4822 | char *data_offset; |
| @@ -4828,11 +4829,8 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | |||
| 4828 | if (rc) | 4829 | if (rc) |
| 4829 | return rc; | 4830 | return rc; |
| 4830 | 4831 | ||
| 4831 | /* At this point there is no need to override the current pid | 4832 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); |
| 4832 | with the pid of the opener, but that could change if we someday | 4833 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); |
| 4833 | use an existing handle (rather than opening one on the fly) */ | ||
| 4834 | /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | ||
| 4835 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/ | ||
| 4836 | 4834 | ||
| 4837 | params = 6; | 4835 | params = 6; |
| 4838 | pSMB->MaxSetupCount = 0; | 4836 | pSMB->MaxSetupCount = 0; |
| @@ -4880,9 +4878,9 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, | |||
| 4880 | 4878 | ||
| 4881 | 4879 | ||
| 4882 | int | 4880 | int |
| 4883 | CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName, | 4881 | CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon, |
| 4884 | const FILE_BASIC_INFO *data, | 4882 | const char *fileName, const FILE_BASIC_INFO *data, |
| 4885 | const struct nls_table *nls_codepage, int remap) | 4883 | const struct nls_table *nls_codepage, int remap) |
| 4886 | { | 4884 | { |
| 4887 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 4885 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
| 4888 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 4886 | TRANSACTION2_SPI_RSP *pSMBr = NULL; |
| @@ -5011,10 +5009,9 @@ SetAttrLgcyRetry: | |||
| 5011 | #endif /* temporarily unneeded SetAttr legacy function */ | 5009 | #endif /* temporarily unneeded SetAttr legacy function */ |
| 5012 | 5010 | ||
| 5013 | int | 5011 | int |
| 5014 | CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, | 5012 | CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, |
| 5015 | char *fileName, __u64 mode, __u64 uid, __u64 gid, | 5013 | const struct cifs_unix_set_info_args *args, |
| 5016 | dev_t device, const struct nls_table *nls_codepage, | 5014 | const struct nls_table *nls_codepage, int remap) |
| 5017 | int remap) | ||
| 5018 | { | 5015 | { |
| 5019 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 5016 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
| 5020 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 5017 | TRANSACTION2_SPI_RSP *pSMBr = NULL; |
| @@ -5023,6 +5020,7 @@ CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, | |||
| 5023 | int bytes_returned = 0; | 5020 | int bytes_returned = 0; |
| 5024 | FILE_UNIX_BASIC_INFO *data_offset; | 5021 | FILE_UNIX_BASIC_INFO *data_offset; |
| 5025 | __u16 params, param_offset, offset, count, byte_count; | 5022 | __u16 params, param_offset, offset, count, byte_count; |
| 5023 | __u64 mode = args->mode; | ||
| 5026 | 5024 | ||
| 5027 | cFYI(1, ("In SetUID/GID/Mode")); | 5025 | cFYI(1, ("In SetUID/GID/Mode")); |
| 5028 | setPermsRetry: | 5026 | setPermsRetry: |
| @@ -5078,16 +5076,16 @@ setPermsRetry: | |||
| 5078 | set file size and do not want to truncate file size to zero | 5076 | set file size and do not want to truncate file size to zero |
| 5079 | accidently as happened on one Samba server beta by putting | 5077 | accidently as happened on one Samba server beta by putting |
| 5080 | zero instead of -1 here */ | 5078 | zero instead of -1 here */ |
| 5081 | data_offset->EndOfFile = NO_CHANGE_64; | 5079 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); |
| 5082 | data_offset->NumOfBytes = NO_CHANGE_64; | 5080 | data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); |
| 5083 | data_offset->LastStatusChange = NO_CHANGE_64; | 5081 | data_offset->LastStatusChange = cpu_to_le64(args->ctime); |
| 5084 | data_offset->LastAccessTime = NO_CHANGE_64; | 5082 | data_offset->LastAccessTime = cpu_to_le64(args->atime); |
| 5085 | data_offset->LastModificationTime = NO_CHANGE_64; | 5083 | data_offset->LastModificationTime = cpu_to_le64(args->mtime); |
| 5086 | data_offset->Uid = cpu_to_le64(uid); | 5084 | data_offset->Uid = cpu_to_le64(args->uid); |
| 5087 | data_offset->Gid = cpu_to_le64(gid); | 5085 | data_offset->Gid = cpu_to_le64(args->gid); |
| 5088 | /* better to leave device as zero when it is */ | 5086 | /* better to leave device as zero when it is */ |
| 5089 | data_offset->DevMajor = cpu_to_le64(MAJOR(device)); | 5087 | data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); |
| 5090 | data_offset->DevMinor = cpu_to_le64(MINOR(device)); | 5088 | data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); |
| 5091 | data_offset->Permissions = cpu_to_le64(mode); | 5089 | data_offset->Permissions = cpu_to_le64(mode); |
| 5092 | 5090 | ||
| 5093 | if (S_ISREG(mode)) | 5091 | if (S_ISREG(mode)) |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e8fa46c7cff2..4c13bcdb92a5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -151,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 151 | } | 151 | } |
| 152 | list_for_each(tmp, &GlobalTreeConnectionList) { | 152 | list_for_each(tmp, &GlobalTreeConnectionList) { |
| 153 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 153 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
| 154 | if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) | 154 | if ((tcon->ses) && (tcon->ses->server == server)) |
| 155 | tcon->tidStatus = CifsNeedReconnect; | 155 | tcon->tidStatus = CifsNeedReconnect; |
| 156 | } | 156 | } |
| 157 | read_unlock(&GlobalSMBSeslock); | 157 | read_unlock(&GlobalSMBSeslock); |
| @@ -173,14 +173,12 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 173 | mid_entry = list_entry(tmp, struct | 173 | mid_entry = list_entry(tmp, struct |
| 174 | mid_q_entry, | 174 | mid_q_entry, |
| 175 | qhead); | 175 | qhead); |
| 176 | if (mid_entry) { | 176 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { |
| 177 | if (mid_entry->midState == MID_REQUEST_SUBMITTED) { | ||
| 178 | /* Mark other intransit requests as needing | 177 | /* Mark other intransit requests as needing |
| 179 | retry so we do not immediately mark the | 178 | retry so we do not immediately mark the |
| 180 | session bad again (ie after we reconnect | 179 | session bad again (ie after we reconnect |
| 181 | below) as they timeout too */ | 180 | below) as they timeout too */ |
| 182 | mid_entry->midState = MID_RETRY_NEEDED; | 181 | mid_entry->midState = MID_RETRY_NEEDED; |
| 183 | } | ||
| 184 | } | 182 | } |
| 185 | } | 183 | } |
| 186 | spin_unlock(&GlobalMid_Lock); | 184 | spin_unlock(&GlobalMid_Lock); |
| @@ -351,11 +349,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 351 | 349 | ||
| 352 | current->flags |= PF_MEMALLOC; | 350 | current->flags |= PF_MEMALLOC; |
| 353 | cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); | 351 | cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current))); |
| 354 | write_lock(&GlobalSMBSeslock); | 352 | |
| 355 | atomic_inc(&tcpSesAllocCount); | 353 | length = atomic_inc_return(&tcpSesAllocCount); |
| 356 | length = tcpSesAllocCount.counter; | 354 | if (length > 1) |
| 357 | write_unlock(&GlobalSMBSeslock); | ||
| 358 | if (length > 1) | ||
| 359 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, | 355 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, |
| 360 | GFP_KERNEL); | 356 | GFP_KERNEL); |
| 361 | 357 | ||
| @@ -455,7 +451,7 @@ incomplete_rcv: | |||
| 455 | /* Note that FC 1001 length is big endian on the wire, | 451 | /* Note that FC 1001 length is big endian on the wire, |
| 456 | but we convert it here so it is always manipulated | 452 | but we convert it here so it is always manipulated |
| 457 | as host byte order */ | 453 | as host byte order */ |
| 458 | pdu_length = ntohl(smb_buffer->smb_buf_length); | 454 | pdu_length = be32_to_cpu((__force __be32)smb_buffer->smb_buf_length); |
| 459 | smb_buffer->smb_buf_length = pdu_length; | 455 | smb_buffer->smb_buf_length = pdu_length; |
| 460 | 456 | ||
| 461 | cFYI(1, ("rfc1002 length 0x%x", pdu_length+4)); | 457 | cFYI(1, ("rfc1002 length 0x%x", pdu_length+4)); |
| @@ -745,14 +741,11 @@ multi_t2_fnd: | |||
| 745 | coming home not much else we can do but free the memory */ | 741 | coming home not much else we can do but free the memory */ |
| 746 | } | 742 | } |
| 747 | 743 | ||
| 748 | write_lock(&GlobalSMBSeslock); | ||
| 749 | atomic_dec(&tcpSesAllocCount); | ||
| 750 | length = tcpSesAllocCount.counter; | ||
| 751 | |||
| 752 | /* last chance to mark ses pointers invalid | 744 | /* last chance to mark ses pointers invalid |
| 753 | if there are any pointing to this (e.g | 745 | if there are any pointing to this (e.g |
| 754 | if a crazy root user tried to kill cifsd | 746 | if a crazy root user tried to kill cifsd |
| 755 | kernel thread explicitly this might happen) */ | 747 | kernel thread explicitly this might happen) */ |
| 748 | write_lock(&GlobalSMBSeslock); | ||
| 756 | list_for_each(tmp, &GlobalSMBSessionList) { | 749 | list_for_each(tmp, &GlobalSMBSessionList) { |
| 757 | ses = list_entry(tmp, struct cifsSesInfo, | 750 | ses = list_entry(tmp, struct cifsSesInfo, |
| 758 | cifsSessionList); | 751 | cifsSessionList); |
| @@ -763,6 +756,8 @@ multi_t2_fnd: | |||
| 763 | 756 | ||
| 764 | kfree(server->hostname); | 757 | kfree(server->hostname); |
| 765 | kfree(server); | 758 | kfree(server); |
| 759 | |||
| 760 | length = atomic_dec_return(&tcpSesAllocCount); | ||
| 766 | if (length > 0) | 761 | if (length > 0) |
| 767 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, | 762 | mempool_resize(cifs_req_poolp, length + cifs_min_rcv, |
| 768 | GFP_KERNEL); | 763 | GFP_KERNEL); |
| @@ -1461,6 +1456,39 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | |||
| 1461 | return rc; | 1456 | return rc; |
| 1462 | } | 1457 | } |
| 1463 | 1458 | ||
| 1459 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 1460 | static struct lock_class_key cifs_key[2]; | ||
| 1461 | static struct lock_class_key cifs_slock_key[2]; | ||
| 1462 | |||
| 1463 | static inline void | ||
| 1464 | cifs_reclassify_socket4(struct socket *sock) | ||
| 1465 | { | ||
| 1466 | struct sock *sk = sock->sk; | ||
| 1467 | BUG_ON(sock_owned_by_user(sk)); | ||
| 1468 | sock_lock_init_class_and_name(sk, "slock-AF_INET-CIFS", | ||
| 1469 | &cifs_slock_key[0], "sk_lock-AF_INET-CIFS", &cifs_key[0]); | ||
| 1470 | } | ||
| 1471 | |||
| 1472 | static inline void | ||
| 1473 | cifs_reclassify_socket6(struct socket *sock) | ||
| 1474 | { | ||
| 1475 | struct sock *sk = sock->sk; | ||
| 1476 | BUG_ON(sock_owned_by_user(sk)); | ||
| 1477 | sock_lock_init_class_and_name(sk, "slock-AF_INET6-CIFS", | ||
| 1478 | &cifs_slock_key[1], "sk_lock-AF_INET6-CIFS", &cifs_key[1]); | ||
| 1479 | } | ||
| 1480 | #else | ||
| 1481 | static inline void | ||
| 1482 | cifs_reclassify_socket4(struct socket *sock) | ||
| 1483 | { | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | static inline void | ||
| 1487 | cifs_reclassify_socket6(struct socket *sock) | ||
| 1488 | { | ||
| 1489 | } | ||
| 1490 | #endif | ||
| 1491 | |||
| 1464 | /* See RFC1001 section 14 on representation of Netbios names */ | 1492 | /* See RFC1001 section 14 on representation of Netbios names */ |
| 1465 | static void rfc1002mangle(char *target, char *source, unsigned int length) | 1493 | static void rfc1002mangle(char *target, char *source, unsigned int length) |
| 1466 | { | 1494 | { |
| @@ -1495,6 +1523,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
| 1495 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | 1523 | /* BB other socket options to set KEEPALIVE, NODELAY? */ |
| 1496 | cFYI(1, ("Socket created")); | 1524 | cFYI(1, ("Socket created")); |
| 1497 | (*csocket)->sk->sk_allocation = GFP_NOFS; | 1525 | (*csocket)->sk->sk_allocation = GFP_NOFS; |
| 1526 | cifs_reclassify_socket4(*csocket); | ||
| 1498 | } | 1527 | } |
| 1499 | } | 1528 | } |
| 1500 | 1529 | ||
| @@ -1627,6 +1656,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) | |||
| 1627 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | 1656 | /* BB other socket options to set KEEPALIVE, NODELAY? */ |
| 1628 | cFYI(1, ("ipv6 Socket created")); | 1657 | cFYI(1, ("ipv6 Socket created")); |
| 1629 | (*csocket)->sk->sk_allocation = GFP_NOFS; | 1658 | (*csocket)->sk->sk_allocation = GFP_NOFS; |
| 1659 | cifs_reclassify_socket6(*csocket); | ||
| 1630 | } | 1660 | } |
| 1631 | } | 1661 | } |
| 1632 | 1662 | ||
| @@ -3568,19 +3598,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3568 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | 3598 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; |
| 3569 | bool ntlmv2_flag = false; | 3599 | bool ntlmv2_flag = false; |
| 3570 | int first_time = 0; | 3600 | int first_time = 0; |
| 3601 | struct TCP_Server_Info *server = pSesInfo->server; | ||
| 3571 | 3602 | ||
| 3572 | /* what if server changes its buffer size after dropping the session? */ | 3603 | /* what if server changes its buffer size after dropping the session? */ |
| 3573 | if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { | 3604 | if (server->maxBuf == 0) /* no need to send on reconnect */ { |
| 3574 | rc = CIFSSMBNegotiate(xid, pSesInfo); | 3605 | rc = CIFSSMBNegotiate(xid, pSesInfo); |
| 3575 | if (rc == -EAGAIN) /* retry only once on 1st time connection */ { | 3606 | if (rc == -EAGAIN) { |
| 3607 | /* retry only once on 1st time connection */ | ||
| 3576 | rc = CIFSSMBNegotiate(xid, pSesInfo); | 3608 | rc = CIFSSMBNegotiate(xid, pSesInfo); |
| 3577 | if (rc == -EAGAIN) | 3609 | if (rc == -EAGAIN) |
| 3578 | rc = -EHOSTDOWN; | 3610 | rc = -EHOSTDOWN; |
| 3579 | } | 3611 | } |
| 3580 | if (rc == 0) { | 3612 | if (rc == 0) { |
| 3581 | spin_lock(&GlobalMid_Lock); | 3613 | spin_lock(&GlobalMid_Lock); |
| 3582 | if (pSesInfo->server->tcpStatus != CifsExiting) | 3614 | if (server->tcpStatus != CifsExiting) |
| 3583 | pSesInfo->server->tcpStatus = CifsGood; | 3615 | server->tcpStatus = CifsGood; |
| 3584 | else | 3616 | else |
| 3585 | rc = -EHOSTDOWN; | 3617 | rc = -EHOSTDOWN; |
| 3586 | spin_unlock(&GlobalMid_Lock); | 3618 | spin_unlock(&GlobalMid_Lock); |
| @@ -3588,97 +3620,90 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3588 | } | 3620 | } |
| 3589 | first_time = 1; | 3621 | first_time = 1; |
| 3590 | } | 3622 | } |
| 3591 | if (!rc) { | 3623 | |
| 3592 | pSesInfo->flags = 0; | 3624 | if (rc) |
| 3593 | pSesInfo->capabilities = pSesInfo->server->capabilities; | 3625 | goto ss_err_exit; |
| 3594 | if (linuxExtEnabled == 0) | 3626 | |
| 3595 | pSesInfo->capabilities &= (~CAP_UNIX); | 3627 | pSesInfo->flags = 0; |
| 3628 | pSesInfo->capabilities = server->capabilities; | ||
| 3629 | if (linuxExtEnabled == 0) | ||
| 3630 | pSesInfo->capabilities &= (~CAP_UNIX); | ||
| 3596 | /* pSesInfo->sequence_number = 0;*/ | 3631 | /* pSesInfo->sequence_number = 0;*/ |
| 3597 | cFYI(1, | 3632 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
| 3598 | ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 3633 | server->secMode, server->capabilities, server->timeAdj)); |
| 3599 | pSesInfo->server->secMode, | 3634 | |
| 3600 | pSesInfo->server->capabilities, | 3635 | if (experimEnabled < 2) |
| 3601 | pSesInfo->server->timeAdj)); | 3636 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); |
| 3602 | if (experimEnabled < 2) | 3637 | else if (extended_security |
| 3603 | rc = CIFS_SessSetup(xid, pSesInfo, | 3638 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) |
| 3604 | first_time, nls_info); | 3639 | && (server->secType == NTLMSSP)) { |
| 3605 | else if (extended_security | 3640 | rc = -EOPNOTSUPP; |
| 3606 | && (pSesInfo->capabilities | 3641 | } else if (extended_security |
| 3607 | & CAP_EXTENDED_SECURITY) | 3642 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) |
| 3608 | && (pSesInfo->server->secType == NTLMSSP)) { | 3643 | && (server->secType == RawNTLMSSP)) { |
| 3609 | rc = -EOPNOTSUPP; | 3644 | cFYI(1, ("NTLMSSP sesssetup")); |
| 3610 | } else if (extended_security | 3645 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag, |
| 3611 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | 3646 | nls_info); |
| 3612 | && (pSesInfo->server->secType == RawNTLMSSP)) { | 3647 | if (!rc) { |
| 3613 | cFYI(1, ("NTLMSSP sesssetup")); | 3648 | if (ntlmv2_flag) { |
| 3614 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, | 3649 | char *v2_response; |
| 3615 | pSesInfo, | 3650 | cFYI(1, ("more secure NTLM ver2 hash")); |
| 3616 | &ntlmv2_flag, | 3651 | if (CalcNTLMv2_partial_mac_key(pSesInfo, |
| 3617 | nls_info); | 3652 | nls_info)) { |
| 3618 | if (!rc) { | 3653 | rc = -ENOMEM; |
| 3619 | if (ntlmv2_flag) { | 3654 | goto ss_err_exit; |
| 3620 | char *v2_response; | 3655 | } else |
| 3621 | cFYI(1, ("more secure NTLM ver2 hash")); | 3656 | v2_response = kmalloc(16 + 64 /* blob*/, |
| 3622 | if (CalcNTLMv2_partial_mac_key(pSesInfo, | 3657 | GFP_KERNEL); |
| 3623 | nls_info)) { | 3658 | if (v2_response) { |
| 3624 | rc = -ENOMEM; | 3659 | CalcNTLMv2_response(pSesInfo, |
| 3625 | goto ss_err_exit; | 3660 | v2_response); |
| 3626 | } else | 3661 | /* if (first_time) |
| 3627 | v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); | 3662 | cifs_calculate_ntlmv2_mac_key */ |
| 3628 | if (v2_response) { | 3663 | kfree(v2_response); |
| 3629 | CalcNTLMv2_response(pSesInfo, | ||
| 3630 | v2_response); | ||
| 3631 | /* if (first_time) | ||
| 3632 | cifs_calculate_ntlmv2_mac_key( | ||
| 3633 | pSesInfo->server->mac_signing_key, | ||
| 3634 | response, ntlm_session_key,*/ | ||
| 3635 | kfree(v2_response); | ||
| 3636 | /* BB Put dummy sig in SessSetup PDU? */ | 3664 | /* BB Put dummy sig in SessSetup PDU? */ |
| 3637 | } else { | ||
| 3638 | rc = -ENOMEM; | ||
| 3639 | goto ss_err_exit; | ||
| 3640 | } | ||
| 3641 | |||
| 3642 | } else { | 3665 | } else { |
| 3643 | SMBNTencrypt(pSesInfo->password, | 3666 | rc = -ENOMEM; |
| 3644 | pSesInfo->server->cryptKey, | 3667 | goto ss_err_exit; |
| 3645 | ntlm_session_key); | ||
| 3646 | |||
| 3647 | if (first_time) | ||
| 3648 | cifs_calculate_mac_key( | ||
| 3649 | &pSesInfo->server->mac_signing_key, | ||
| 3650 | ntlm_session_key, | ||
| 3651 | pSesInfo->password); | ||
| 3652 | } | 3668 | } |
| 3669 | |||
| 3670 | } else { | ||
| 3671 | SMBNTencrypt(pSesInfo->password, | ||
| 3672 | server->cryptKey, | ||
| 3673 | ntlm_session_key); | ||
| 3674 | |||
| 3675 | if (first_time) | ||
| 3676 | cifs_calculate_mac_key( | ||
| 3677 | &server->mac_signing_key, | ||
| 3678 | ntlm_session_key, | ||
| 3679 | pSesInfo->password); | ||
| 3680 | } | ||
| 3653 | /* for better security the weaker lanman hash not sent | 3681 | /* for better security the weaker lanman hash not sent |
| 3654 | in AuthSessSetup so we no longer calculate it */ | 3682 | in AuthSessSetup so we no longer calculate it */ |
| 3655 | 3683 | ||
| 3656 | rc = CIFSNTLMSSPAuthSessSetup(xid, | 3684 | rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo, |
| 3657 | pSesInfo, | 3685 | ntlm_session_key, |
| 3658 | ntlm_session_key, | 3686 | ntlmv2_flag, |
| 3659 | ntlmv2_flag, | 3687 | nls_info); |
| 3660 | nls_info); | 3688 | } |
| 3661 | } | 3689 | } else { /* old style NTLM 0.12 session setup */ |
| 3662 | } else { /* old style NTLM 0.12 session setup */ | 3690 | SMBNTencrypt(pSesInfo->password, server->cryptKey, |
| 3663 | SMBNTencrypt(pSesInfo->password, | 3691 | ntlm_session_key); |
| 3664 | pSesInfo->server->cryptKey, | ||
| 3665 | ntlm_session_key); | ||
| 3666 | 3692 | ||
| 3667 | if (first_time) | 3693 | if (first_time) |
| 3668 | cifs_calculate_mac_key( | 3694 | cifs_calculate_mac_key(&server->mac_signing_key, |
| 3669 | &pSesInfo->server->mac_signing_key, | 3695 | ntlm_session_key, |
| 3670 | ntlm_session_key, pSesInfo->password); | 3696 | pSesInfo->password); |
| 3671 | 3697 | ||
| 3672 | rc = CIFSSessSetup(xid, pSesInfo, | 3698 | rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); |
| 3673 | ntlm_session_key, nls_info); | 3699 | } |
| 3674 | } | 3700 | if (rc) { |
| 3675 | if (rc) { | 3701 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
| 3676 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 3702 | } else { |
| 3677 | } else { | 3703 | cFYI(1, ("CIFS Session Established successfully")); |
| 3678 | cFYI(1, ("CIFS Session Established successfully")); | ||
| 3679 | pSesInfo->status = CifsGood; | 3704 | pSesInfo->status = CifsGood; |
| 3680 | } | ||
| 3681 | } | 3705 | } |
| 3706 | |||
| 3682 | ss_err_exit: | 3707 | ss_err_exit: |
| 3683 | return rc; | 3708 | return rc; |
| 3684 | } | 3709 | } |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index fb69c1fa85c9..e962e75e6f7b 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -226,23 +226,28 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 226 | /* If Open reported that we actually created a file | 226 | /* If Open reported that we actually created a file |
| 227 | then we now have to set the mode if possible */ | 227 | then we now have to set the mode if possible */ |
| 228 | if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { | 228 | if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { |
| 229 | struct cifs_unix_set_info_args args = { | ||
| 230 | .mode = mode, | ||
| 231 | .ctime = NO_CHANGE_64, | ||
| 232 | .atime = NO_CHANGE_64, | ||
| 233 | .mtime = NO_CHANGE_64, | ||
| 234 | .device = 0, | ||
| 235 | }; | ||
| 236 | |||
| 229 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 237 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
| 230 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, | 238 | args.uid = (__u64) current->fsuid; |
| 231 | (__u64)current->fsuid, | 239 | if (inode->i_mode & S_ISGID) |
| 232 | (__u64)current->fsgid, | 240 | args.gid = (__u64) inode->i_gid; |
| 233 | 0 /* dev */, | 241 | else |
| 234 | cifs_sb->local_nls, | 242 | args.gid = (__u64) current->fsgid; |
| 235 | cifs_sb->mnt_cifs_flags & | ||
| 236 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 237 | } else { | 243 | } else { |
| 238 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, | 244 | args.uid = NO_CHANGE_64; |
| 239 | (__u64)-1, | 245 | args.gid = NO_CHANGE_64; |
| 240 | (__u64)-1, | ||
| 241 | 0 /* dev */, | ||
| 242 | cifs_sb->local_nls, | ||
| 243 | cifs_sb->mnt_cifs_flags & | ||
| 244 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 245 | } | 246 | } |
| 247 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | ||
| 248 | cifs_sb->local_nls, | ||
| 249 | cifs_sb->mnt_cifs_flags & | ||
| 250 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 246 | } else { | 251 | } else { |
| 247 | /* BB implement mode setting via Windows security | 252 | /* BB implement mode setting via Windows security |
| 248 | descriptors e.g. */ | 253 | descriptors e.g. */ |
| @@ -267,7 +272,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 267 | (cifs_sb->mnt_cifs_flags & | 272 | (cifs_sb->mnt_cifs_flags & |
| 268 | CIFS_MOUNT_SET_UID)) { | 273 | CIFS_MOUNT_SET_UID)) { |
| 269 | newinode->i_uid = current->fsuid; | 274 | newinode->i_uid = current->fsuid; |
| 270 | newinode->i_gid = current->fsgid; | 275 | if (inode->i_mode & S_ISGID) |
| 276 | newinode->i_gid = | ||
| 277 | inode->i_gid; | ||
| 278 | else | ||
| 279 | newinode->i_gid = | ||
| 280 | current->fsgid; | ||
| 271 | } | 281 | } |
| 272 | } | 282 | } |
| 273 | } | 283 | } |
| @@ -357,21 +367,24 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
| 357 | if (full_path == NULL) | 367 | if (full_path == NULL) |
| 358 | rc = -ENOMEM; | 368 | rc = -ENOMEM; |
| 359 | else if (pTcon->unix_ext) { | 369 | else if (pTcon->unix_ext) { |
| 360 | mode &= ~current->fs->umask; | 370 | struct cifs_unix_set_info_args args = { |
| 371 | .mode = mode & ~current->fs->umask, | ||
| 372 | .ctime = NO_CHANGE_64, | ||
| 373 | .atime = NO_CHANGE_64, | ||
| 374 | .mtime = NO_CHANGE_64, | ||
| 375 | .device = device_number, | ||
| 376 | }; | ||
| 361 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 377 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
| 362 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 378 | args.uid = (__u64) current->fsuid; |
| 363 | mode, (__u64)current->fsuid, | 379 | args.gid = (__u64) current->fsgid; |
| 364 | (__u64)current->fsgid, | ||
| 365 | device_number, cifs_sb->local_nls, | ||
| 366 | cifs_sb->mnt_cifs_flags & | ||
| 367 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 368 | } else { | 380 | } else { |
| 369 | rc = CIFSSMBUnixSetPerms(xid, pTcon, | 381 | args.uid = NO_CHANGE_64; |
| 370 | full_path, mode, (__u64)-1, (__u64)-1, | 382 | args.gid = NO_CHANGE_64; |
| 371 | device_number, cifs_sb->local_nls, | ||
| 372 | cifs_sb->mnt_cifs_flags & | ||
| 373 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 374 | } | 383 | } |
| 384 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, | ||
| 385 | &args, cifs_sb->local_nls, | ||
| 386 | cifs_sb->mnt_cifs_flags & | ||
| 387 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 375 | 388 | ||
| 376 | if (!rc) { | 389 | if (!rc) { |
| 377 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 390 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index f730ef35499e..a2e0673e1b08 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
| @@ -47,11 +47,18 @@ static int dns_resolver_instantiate(struct key *key, const void *data, | |||
| 47 | return rc; | 47 | return rc; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static void | ||
| 51 | dns_resolver_destroy(struct key *key) | ||
| 52 | { | ||
| 53 | kfree(key->payload.data); | ||
| 54 | } | ||
| 55 | |||
| 50 | struct key_type key_type_dns_resolver = { | 56 | struct key_type key_type_dns_resolver = { |
| 51 | .name = "dns_resolver", | 57 | .name = "dns_resolver", |
| 52 | .def_datalen = sizeof(struct in_addr), | 58 | .def_datalen = sizeof(struct in_addr), |
| 53 | .describe = user_describe, | 59 | .describe = user_describe, |
| 54 | .instantiate = dns_resolver_instantiate, | 60 | .instantiate = dns_resolver_instantiate, |
| 61 | .destroy = dns_resolver_destroy, | ||
| 55 | .match = user_match, | 62 | .match = user_match, |
| 56 | }; | 63 | }; |
| 57 | 64 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0aac824371a5..cbefe1f1f9fe 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -310,18 +310,19 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 310 | /* time to set mode which we can not set earlier due to | 310 | /* time to set mode which we can not set earlier due to |
| 311 | problems creating new read-only files */ | 311 | problems creating new read-only files */ |
| 312 | if (pTcon->unix_ext) { | 312 | if (pTcon->unix_ext) { |
| 313 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 313 | struct cifs_unix_set_info_args args = { |
| 314 | inode->i_mode, | 314 | .mode = inode->i_mode, |
| 315 | (__u64)-1, (__u64)-1, 0 /* dev */, | 315 | .uid = NO_CHANGE_64, |
| 316 | .gid = NO_CHANGE_64, | ||
| 317 | .ctime = NO_CHANGE_64, | ||
| 318 | .atime = NO_CHANGE_64, | ||
| 319 | .mtime = NO_CHANGE_64, | ||
| 320 | .device = 0, | ||
| 321 | }; | ||
| 322 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | ||
| 316 | cifs_sb->local_nls, | 323 | cifs_sb->local_nls, |
| 317 | cifs_sb->mnt_cifs_flags & | 324 | cifs_sb->mnt_cifs_flags & |
| 318 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 325 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 319 | } else { | ||
| 320 | /* BB implement via Windows security descriptors eg | ||
| 321 | CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, | ||
| 322 | -1, -1, local_nls); | ||
| 323 | in the meantime could set r/o dos attribute when | ||
| 324 | perms are eg: mode & 0222 == 0 */ | ||
| 325 | } | 326 | } |
| 326 | } | 327 | } |
| 327 | 328 | ||
| @@ -832,6 +833,10 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 832 | return -EBADF; | 833 | return -EBADF; |
| 833 | open_file = (struct cifsFileInfo *) file->private_data; | 834 | open_file = (struct cifsFileInfo *) file->private_data; |
| 834 | 835 | ||
| 836 | rc = generic_write_checks(file, poffset, &write_size, 0); | ||
| 837 | if (rc) | ||
| 838 | return rc; | ||
| 839 | |||
| 835 | xid = GetXid(); | 840 | xid = GetXid(); |
| 836 | 841 | ||
| 837 | if (*poffset > file->f_path.dentry->d_inode->i_size) | 842 | if (*poffset > file->f_path.dentry->d_inode->i_size) |
| @@ -1280,7 +1285,7 @@ retry: | |||
| 1280 | 1285 | ||
| 1281 | if (first < 0) | 1286 | if (first < 0) |
| 1282 | lock_page(page); | 1287 | lock_page(page); |
| 1283 | else if (TestSetPageLocked(page)) | 1288 | else if (!trylock_page(page)) |
| 1284 | break; | 1289 | break; |
| 1285 | 1290 | ||
| 1286 | if (unlikely(page->mapping != mapping)) { | 1291 | if (unlikely(page->mapping != mapping)) { |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 2e904bd111c8..9c548f110102 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -546,7 +546,8 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 546 | if ((inode->i_mode & S_IWUGO) == 0 && | 546 | if ((inode->i_mode & S_IWUGO) == 0 && |
| 547 | (attr & ATTR_READONLY) == 0) | 547 | (attr & ATTR_READONLY) == 0) |
| 548 | inode->i_mode |= (S_IWUGO & default_mode); | 548 | inode->i_mode |= (S_IWUGO & default_mode); |
| 549 | inode->i_mode &= ~S_IFMT; | 549 | |
| 550 | inode->i_mode &= ~S_IFMT; | ||
| 550 | } | 551 | } |
| 551 | /* clear write bits if ATTR_READONLY is set */ | 552 | /* clear write bits if ATTR_READONLY is set */ |
| 552 | if (attr & ATTR_READONLY) | 553 | if (attr & ATTR_READONLY) |
| @@ -649,6 +650,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino) | |||
| 649 | inode->i_fop = &simple_dir_operations; | 650 | inode->i_fop = &simple_dir_operations; |
| 650 | inode->i_uid = cifs_sb->mnt_uid; | 651 | inode->i_uid = cifs_sb->mnt_uid; |
| 651 | inode->i_gid = cifs_sb->mnt_gid; | 652 | inode->i_gid = cifs_sb->mnt_gid; |
| 653 | } else if (rc) { | ||
| 652 | _FreeXid(xid); | 654 | _FreeXid(xid); |
| 653 | iget_failed(inode); | 655 | iget_failed(inode); |
| 654 | return ERR_PTR(rc); | 656 | return ERR_PTR(rc); |
| @@ -737,7 +739,7 @@ psx_del_no_retry: | |||
| 737 | /* ATTRS set to normal clears r/o bit */ | 739 | /* ATTRS set to normal clears r/o bit */ |
| 738 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); | 740 | pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); |
| 739 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | 741 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) |
| 740 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, | 742 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, |
| 741 | pinfo_buf, | 743 | pinfo_buf, |
| 742 | cifs_sb->local_nls, | 744 | cifs_sb->local_nls, |
| 743 | cifs_sb->mnt_cifs_flags & | 745 | cifs_sb->mnt_cifs_flags & |
| @@ -767,9 +769,10 @@ psx_del_no_retry: | |||
| 767 | cifs_sb->mnt_cifs_flags & | 769 | cifs_sb->mnt_cifs_flags & |
| 768 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 770 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 769 | if (rc == 0) { | 771 | if (rc == 0) { |
| 770 | rc = CIFSSMBSetFileTimes(xid, pTcon, | 772 | rc = CIFSSMBSetFileInfo(xid, pTcon, |
| 771 | pinfo_buf, | 773 | pinfo_buf, |
| 772 | netfid); | 774 | netfid, |
| 775 | current->tgid); | ||
| 773 | CIFSSMBClose(xid, pTcon, netfid); | 776 | CIFSSMBClose(xid, pTcon, netfid); |
| 774 | } | 777 | } |
| 775 | } | 778 | } |
| @@ -984,32 +987,41 @@ mkdir_get_info: | |||
| 984 | * failed to get it from the server or was set bogus */ | 987 | * failed to get it from the server or was set bogus */ |
| 985 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) | 988 | if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) |
| 986 | direntry->d_inode->i_nlink = 2; | 989 | direntry->d_inode->i_nlink = 2; |
| 990 | |||
| 987 | mode &= ~current->fs->umask; | 991 | mode &= ~current->fs->umask; |
| 992 | /* must turn on setgid bit if parent dir has it */ | ||
| 993 | if (inode->i_mode & S_ISGID) | ||
| 994 | mode |= S_ISGID; | ||
| 995 | |||
| 988 | if (pTcon->unix_ext) { | 996 | if (pTcon->unix_ext) { |
| 997 | struct cifs_unix_set_info_args args = { | ||
| 998 | .mode = mode, | ||
| 999 | .ctime = NO_CHANGE_64, | ||
| 1000 | .atime = NO_CHANGE_64, | ||
| 1001 | .mtime = NO_CHANGE_64, | ||
| 1002 | .device = 0, | ||
| 1003 | }; | ||
| 989 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 1004 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
| 990 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 1005 | args.uid = (__u64)current->fsuid; |
| 991 | mode, | 1006 | if (inode->i_mode & S_ISGID) |
| 992 | (__u64)current->fsuid, | 1007 | args.gid = (__u64)inode->i_gid; |
| 993 | (__u64)current->fsgid, | 1008 | else |
| 994 | 0 /* dev_t */, | 1009 | args.gid = (__u64)current->fsgid; |
| 995 | cifs_sb->local_nls, | ||
| 996 | cifs_sb->mnt_cifs_flags & | ||
| 997 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 998 | } else { | 1010 | } else { |
| 999 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 1011 | args.uid = NO_CHANGE_64; |
| 1000 | mode, (__u64)-1, | 1012 | args.gid = NO_CHANGE_64; |
| 1001 | (__u64)-1, 0 /* dev_t */, | ||
| 1002 | cifs_sb->local_nls, | ||
| 1003 | cifs_sb->mnt_cifs_flags & | ||
| 1004 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1005 | } | 1013 | } |
| 1014 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | ||
| 1015 | cifs_sb->local_nls, | ||
| 1016 | cifs_sb->mnt_cifs_flags & | ||
| 1017 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1006 | } else { | 1018 | } else { |
| 1007 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | 1019 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && |
| 1008 | (mode & S_IWUGO) == 0) { | 1020 | (mode & S_IWUGO) == 0) { |
| 1009 | FILE_BASIC_INFO pInfo; | 1021 | FILE_BASIC_INFO pInfo; |
| 1010 | memset(&pInfo, 0, sizeof(pInfo)); | 1022 | memset(&pInfo, 0, sizeof(pInfo)); |
| 1011 | pInfo.Attributes = cpu_to_le32(ATTR_READONLY); | 1023 | pInfo.Attributes = cpu_to_le32(ATTR_READONLY); |
| 1012 | CIFSSMBSetTimes(xid, pTcon, full_path, | 1024 | CIFSSMBSetPathInfo(xid, pTcon, full_path, |
| 1013 | &pInfo, cifs_sb->local_nls, | 1025 | &pInfo, cifs_sb->local_nls, |
| 1014 | cifs_sb->mnt_cifs_flags & | 1026 | cifs_sb->mnt_cifs_flags & |
| 1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1027 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| @@ -1024,8 +1036,12 @@ mkdir_get_info: | |||
| 1024 | CIFS_MOUNT_SET_UID) { | 1036 | CIFS_MOUNT_SET_UID) { |
| 1025 | direntry->d_inode->i_uid = | 1037 | direntry->d_inode->i_uid = |
| 1026 | current->fsuid; | 1038 | current->fsuid; |
| 1027 | direntry->d_inode->i_gid = | 1039 | if (inode->i_mode & S_ISGID) |
| 1028 | current->fsgid; | 1040 | direntry->d_inode->i_gid = |
| 1041 | inode->i_gid; | ||
| 1042 | else | ||
| 1043 | direntry->d_inode->i_gid = | ||
| 1044 | current->fsgid; | ||
| 1029 | } | 1045 | } |
| 1030 | } | 1046 | } |
| 1031 | } | 1047 | } |
| @@ -1310,10 +1326,11 @@ int cifs_revalidate(struct dentry *direntry) | |||
| 1310 | /* if (S_ISDIR(direntry->d_inode->i_mode)) | 1326 | /* if (S_ISDIR(direntry->d_inode->i_mode)) |
| 1311 | shrink_dcache_parent(direntry); */ | 1327 | shrink_dcache_parent(direntry); */ |
| 1312 | if (S_ISREG(direntry->d_inode->i_mode)) { | 1328 | if (S_ISREG(direntry->d_inode->i_mode)) { |
| 1313 | if (direntry->d_inode->i_mapping) | 1329 | if (direntry->d_inode->i_mapping) { |
| 1314 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); | 1330 | wbrc = filemap_fdatawait(direntry->d_inode->i_mapping); |
| 1315 | if (wbrc) | 1331 | if (wbrc) |
| 1316 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; | 1332 | CIFS_I(direntry->d_inode)->write_behind_rc = wbrc; |
| 1333 | } | ||
| 1317 | /* may eventually have to do this for open files too */ | 1334 | /* may eventually have to do this for open files too */ |
| 1318 | if (list_empty(&(cifsInode->openFileList))) { | 1335 | if (list_empty(&(cifsInode->openFileList))) { |
| 1319 | /* changed on server - flush read ahead pages */ | 1336 | /* changed on server - flush read ahead pages */ |
| @@ -1413,31 +1430,304 @@ out_busy: | |||
| 1413 | return -ETXTBSY; | 1430 | return -ETXTBSY; |
| 1414 | } | 1431 | } |
| 1415 | 1432 | ||
| 1416 | int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | 1433 | static int |
| 1434 | cifs_set_file_size(struct inode *inode, struct iattr *attrs, | ||
| 1435 | int xid, char *full_path) | ||
| 1417 | { | 1436 | { |
| 1437 | int rc; | ||
| 1438 | struct cifsFileInfo *open_file; | ||
| 1439 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
| 1440 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1441 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
| 1442 | |||
| 1443 | /* | ||
| 1444 | * To avoid spurious oplock breaks from server, in the case of | ||
| 1445 | * inodes that we already have open, avoid doing path based | ||
| 1446 | * setting of file size if we can do it by handle. | ||
| 1447 | * This keeps our caching token (oplock) and avoids timeouts | ||
| 1448 | * when the local oplock break takes longer to flush | ||
| 1449 | * writebehind data than the SMB timeout for the SetPathInfo | ||
| 1450 | * request would allow | ||
| 1451 | */ | ||
| 1452 | open_file = find_writable_file(cifsInode); | ||
| 1453 | if (open_file) { | ||
| 1454 | __u16 nfid = open_file->netfid; | ||
| 1455 | __u32 npid = open_file->pid; | ||
| 1456 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid, | ||
| 1457 | npid, false); | ||
| 1458 | atomic_dec(&open_file->wrtPending); | ||
| 1459 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | ||
| 1460 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
| 1461 | unsigned int bytes_written; | ||
| 1462 | rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, | ||
| 1463 | &bytes_written, NULL, NULL, 1); | ||
| 1464 | cFYI(1, ("Wrt seteof rc %d", rc)); | ||
| 1465 | } | ||
| 1466 | } else | ||
| 1467 | rc = -EINVAL; | ||
| 1468 | |||
| 1469 | if (rc != 0) { | ||
| 1470 | /* Set file size by pathname rather than by handle | ||
| 1471 | either because no valid, writeable file handle for | ||
| 1472 | it was found or because there was an error setting | ||
| 1473 | it by handle */ | ||
| 1474 | rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, | ||
| 1475 | false, cifs_sb->local_nls, | ||
| 1476 | cifs_sb->mnt_cifs_flags & | ||
| 1477 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1478 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); | ||
| 1479 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
| 1480 | __u16 netfid; | ||
| 1481 | int oplock = 0; | ||
| 1482 | |||
| 1483 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
| 1484 | FILE_OPEN, GENERIC_WRITE, | ||
| 1485 | CREATE_NOT_DIR, &netfid, &oplock, NULL, | ||
| 1486 | cifs_sb->local_nls, | ||
| 1487 | cifs_sb->mnt_cifs_flags & | ||
| 1488 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1489 | if (rc == 0) { | ||
| 1490 | unsigned int bytes_written; | ||
| 1491 | rc = CIFSSMBWrite(xid, pTcon, netfid, 0, | ||
| 1492 | attrs->ia_size, | ||
| 1493 | &bytes_written, NULL, | ||
| 1494 | NULL, 1); | ||
| 1495 | cFYI(1, ("wrt seteof rc %d", rc)); | ||
| 1496 | CIFSSMBClose(xid, pTcon, netfid); | ||
| 1497 | } | ||
| 1498 | } | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | if (rc == 0) { | ||
| 1502 | rc = cifs_vmtruncate(inode, attrs->ia_size); | ||
| 1503 | cifs_truncate_page(inode->i_mapping, inode->i_size); | ||
| 1504 | } | ||
| 1505 | |||
| 1506 | return rc; | ||
| 1507 | } | ||
| 1508 | |||
| 1509 | static int | ||
| 1510 | cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid, | ||
| 1511 | char *full_path, __u32 dosattr) | ||
| 1512 | { | ||
| 1513 | int rc; | ||
| 1514 | int oplock = 0; | ||
| 1515 | __u16 netfid; | ||
| 1516 | __u32 netpid; | ||
| 1517 | bool set_time = false; | ||
| 1518 | struct cifsFileInfo *open_file; | ||
| 1519 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
| 1520 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1521 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
| 1522 | FILE_BASIC_INFO info_buf; | ||
| 1523 | |||
| 1524 | if (attrs->ia_valid & ATTR_ATIME) { | ||
| 1525 | set_time = true; | ||
| 1526 | info_buf.LastAccessTime = | ||
| 1527 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | ||
| 1528 | } else | ||
| 1529 | info_buf.LastAccessTime = 0; | ||
| 1530 | |||
| 1531 | if (attrs->ia_valid & ATTR_MTIME) { | ||
| 1532 | set_time = true; | ||
| 1533 | info_buf.LastWriteTime = | ||
| 1534 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
| 1535 | } else | ||
| 1536 | info_buf.LastWriteTime = 0; | ||
| 1537 | |||
| 1538 | /* | ||
| 1539 | * Samba throws this field away, but windows may actually use it. | ||
| 1540 | * Do not set ctime unless other time stamps are changed explicitly | ||
| 1541 | * (i.e. by utimes()) since we would then have a mix of client and | ||
| 1542 | * server times. | ||
| 1543 | */ | ||
| 1544 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
| 1545 | cFYI(1, ("CIFS - CTIME changed")); | ||
| 1546 | info_buf.ChangeTime = | ||
| 1547 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
| 1548 | } else | ||
| 1549 | info_buf.ChangeTime = 0; | ||
| 1550 | |||
| 1551 | info_buf.CreationTime = 0; /* don't change */ | ||
| 1552 | info_buf.Attributes = cpu_to_le32(dosattr); | ||
| 1553 | |||
| 1554 | /* | ||
| 1555 | * If the file is already open for write, just use that fileid | ||
| 1556 | */ | ||
| 1557 | open_file = find_writable_file(cifsInode); | ||
| 1558 | if (open_file) { | ||
| 1559 | netfid = open_file->netfid; | ||
| 1560 | netpid = open_file->pid; | ||
| 1561 | goto set_via_filehandle; | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | /* | ||
| 1565 | * NT4 apparently returns success on this call, but it doesn't | ||
| 1566 | * really work. | ||
| 1567 | */ | ||
| 1568 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) { | ||
| 1569 | rc = CIFSSMBSetPathInfo(xid, pTcon, full_path, | ||
| 1570 | &info_buf, cifs_sb->local_nls, | ||
| 1571 | cifs_sb->mnt_cifs_flags & | ||
| 1572 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1573 | if (rc != -EOPNOTSUPP && rc != -EINVAL) | ||
| 1574 | goto out; | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
| 1578 | "times not supported by this server")); | ||
| 1579 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
| 1580 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
| 1581 | CREATE_NOT_DIR, &netfid, &oplock, | ||
| 1582 | NULL, cifs_sb->local_nls, | ||
| 1583 | cifs_sb->mnt_cifs_flags & | ||
| 1584 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1585 | |||
| 1586 | if (rc != 0) { | ||
| 1587 | if (rc == -EIO) | ||
| 1588 | rc = -EINVAL; | ||
| 1589 | goto out; | ||
| 1590 | } | ||
| 1591 | |||
| 1592 | netpid = current->tgid; | ||
| 1593 | |||
| 1594 | set_via_filehandle: | ||
| 1595 | rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid); | ||
| 1596 | if (open_file == NULL) | ||
| 1597 | CIFSSMBClose(xid, pTcon, netfid); | ||
| 1598 | else | ||
| 1599 | atomic_dec(&open_file->wrtPending); | ||
| 1600 | out: | ||
| 1601 | return rc; | ||
| 1602 | } | ||
| 1603 | |||
| 1604 | static int | ||
| 1605 | cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | ||
| 1606 | { | ||
| 1607 | int rc; | ||
| 1418 | int xid; | 1608 | int xid; |
| 1419 | struct cifs_sb_info *cifs_sb; | ||
| 1420 | struct cifsTconInfo *pTcon; | ||
| 1421 | char *full_path = NULL; | 1609 | char *full_path = NULL; |
| 1422 | int rc = -EACCES; | ||
| 1423 | struct cifsFileInfo *open_file = NULL; | ||
| 1424 | FILE_BASIC_INFO time_buf; | ||
| 1425 | bool set_time = false; | ||
| 1426 | bool set_dosattr = false; | ||
| 1427 | __u64 mode = 0xFFFFFFFFFFFFFFFFULL; | ||
| 1428 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | ||
| 1429 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | ||
| 1430 | struct cifsInodeInfo *cifsInode; | ||
| 1431 | struct inode *inode = direntry->d_inode; | 1610 | struct inode *inode = direntry->d_inode; |
| 1611 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
| 1612 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1613 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
| 1614 | struct cifs_unix_set_info_args *args = NULL; | ||
| 1615 | |||
| 1616 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", | ||
| 1617 | direntry->d_name.name, attrs->ia_valid)); | ||
| 1618 | |||
| 1619 | xid = GetXid(); | ||
| 1620 | |||
| 1621 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | ||
| 1622 | /* check if we have permission to change attrs */ | ||
| 1623 | rc = inode_change_ok(inode, attrs); | ||
| 1624 | if (rc < 0) | ||
| 1625 | goto out; | ||
| 1626 | else | ||
| 1627 | rc = 0; | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | full_path = build_path_from_dentry(direntry); | ||
| 1631 | if (full_path == NULL) { | ||
| 1632 | rc = -ENOMEM; | ||
| 1633 | goto out; | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | ||
| 1637 | /* | ||
| 1638 | Flush data before changing file size or changing the last | ||
| 1639 | write time of the file on the server. If the | ||
| 1640 | flush returns error, store it to report later and continue. | ||
| 1641 | BB: This should be smarter. Why bother flushing pages that | ||
| 1642 | will be truncated anyway? Also, should we error out here if | ||
| 1643 | the flush returns error? | ||
| 1644 | */ | ||
| 1645 | rc = filemap_write_and_wait(inode->i_mapping); | ||
| 1646 | if (rc != 0) { | ||
| 1647 | cifsInode->write_behind_rc = rc; | ||
| 1648 | rc = 0; | ||
| 1649 | } | ||
| 1650 | } | ||
| 1651 | |||
| 1652 | if (attrs->ia_valid & ATTR_SIZE) { | ||
| 1653 | rc = cifs_set_file_size(inode, attrs, xid, full_path); | ||
| 1654 | if (rc != 0) | ||
| 1655 | goto out; | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | /* skip mode change if it's just for clearing setuid/setgid */ | ||
| 1659 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) | ||
| 1660 | attrs->ia_valid &= ~ATTR_MODE; | ||
| 1661 | |||
| 1662 | args = kmalloc(sizeof(*args), GFP_KERNEL); | ||
| 1663 | if (args == NULL) { | ||
| 1664 | rc = -ENOMEM; | ||
| 1665 | goto out; | ||
| 1666 | } | ||
| 1667 | |||
| 1668 | /* set up the struct */ | ||
| 1669 | if (attrs->ia_valid & ATTR_MODE) | ||
| 1670 | args->mode = attrs->ia_mode; | ||
| 1671 | else | ||
| 1672 | args->mode = NO_CHANGE_64; | ||
| 1673 | |||
| 1674 | if (attrs->ia_valid & ATTR_UID) | ||
| 1675 | args->uid = attrs->ia_uid; | ||
| 1676 | else | ||
| 1677 | args->uid = NO_CHANGE_64; | ||
| 1678 | |||
| 1679 | if (attrs->ia_valid & ATTR_GID) | ||
| 1680 | args->gid = attrs->ia_gid; | ||
| 1681 | else | ||
| 1682 | args->gid = NO_CHANGE_64; | ||
| 1683 | |||
| 1684 | if (attrs->ia_valid & ATTR_ATIME) | ||
| 1685 | args->atime = cifs_UnixTimeToNT(attrs->ia_atime); | ||
| 1686 | else | ||
| 1687 | args->atime = NO_CHANGE_64; | ||
| 1688 | |||
| 1689 | if (attrs->ia_valid & ATTR_MTIME) | ||
| 1690 | args->mtime = cifs_UnixTimeToNT(attrs->ia_mtime); | ||
| 1691 | else | ||
| 1692 | args->mtime = NO_CHANGE_64; | ||
| 1693 | |||
| 1694 | if (attrs->ia_valid & ATTR_CTIME) | ||
| 1695 | args->ctime = cifs_UnixTimeToNT(attrs->ia_ctime); | ||
| 1696 | else | ||
| 1697 | args->ctime = NO_CHANGE_64; | ||
| 1698 | |||
| 1699 | args->device = 0; | ||
| 1700 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args, | ||
| 1701 | cifs_sb->local_nls, | ||
| 1702 | cifs_sb->mnt_cifs_flags & | ||
| 1703 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1704 | |||
| 1705 | if (!rc) | ||
| 1706 | rc = inode_setattr(inode, attrs); | ||
| 1707 | out: | ||
| 1708 | kfree(args); | ||
| 1709 | kfree(full_path); | ||
| 1710 | FreeXid(xid); | ||
| 1711 | return rc; | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | static int | ||
| 1715 | cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | ||
| 1716 | { | ||
| 1717 | int xid; | ||
| 1718 | struct inode *inode = direntry->d_inode; | ||
| 1719 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1720 | struct cifsInodeInfo *cifsInode = CIFS_I(inode); | ||
| 1721 | char *full_path = NULL; | ||
| 1722 | int rc = -EACCES; | ||
| 1723 | __u32 dosattr = 0; | ||
| 1724 | __u64 mode = NO_CHANGE_64; | ||
| 1432 | 1725 | ||
| 1433 | xid = GetXid(); | 1726 | xid = GetXid(); |
| 1434 | 1727 | ||
| 1435 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", | 1728 | cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", |
| 1436 | direntry->d_name.name, attrs->ia_valid)); | 1729 | direntry->d_name.name, attrs->ia_valid)); |
| 1437 | 1730 | ||
| 1438 | cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1439 | pTcon = cifs_sb->tcon; | ||
| 1440 | |||
| 1441 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1731 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { |
| 1442 | /* check if we have permission to change attrs */ | 1732 | /* check if we have permission to change attrs */ |
| 1443 | rc = inode_change_ok(inode, attrs); | 1733 | rc = inode_change_ok(inode, attrs); |
| @@ -1453,7 +1743,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1453 | FreeXid(xid); | 1743 | FreeXid(xid); |
| 1454 | return -ENOMEM; | 1744 | return -ENOMEM; |
| 1455 | } | 1745 | } |
| 1456 | cifsInode = CIFS_I(inode); | ||
| 1457 | 1746 | ||
| 1458 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { | 1747 | if ((attrs->ia_valid & ATTR_MTIME) || (attrs->ia_valid & ATTR_SIZE)) { |
| 1459 | /* | 1748 | /* |
| @@ -1472,78 +1761,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1472 | } | 1761 | } |
| 1473 | 1762 | ||
| 1474 | if (attrs->ia_valid & ATTR_SIZE) { | 1763 | if (attrs->ia_valid & ATTR_SIZE) { |
| 1475 | /* To avoid spurious oplock breaks from server, in the case of | 1764 | rc = cifs_set_file_size(inode, attrs, xid, full_path); |
| 1476 | inodes that we already have open, avoid doing path based | 1765 | if (rc != 0) |
| 1477 | setting of file size if we can do it by handle. | ||
| 1478 | This keeps our caching token (oplock) and avoids timeouts | ||
| 1479 | when the local oplock break takes longer to flush | ||
| 1480 | writebehind data than the SMB timeout for the SetPathInfo | ||
| 1481 | request would allow */ | ||
| 1482 | |||
| 1483 | open_file = find_writable_file(cifsInode); | ||
| 1484 | if (open_file) { | ||
| 1485 | __u16 nfid = open_file->netfid; | ||
| 1486 | __u32 npid = open_file->pid; | ||
| 1487 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, | ||
| 1488 | nfid, npid, false); | ||
| 1489 | atomic_dec(&open_file->wrtPending); | ||
| 1490 | cFYI(1, ("SetFSize for attrs rc = %d", rc)); | ||
| 1491 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
| 1492 | unsigned int bytes_written; | ||
| 1493 | rc = CIFSSMBWrite(xid, pTcon, | ||
| 1494 | nfid, 0, attrs->ia_size, | ||
| 1495 | &bytes_written, NULL, NULL, | ||
| 1496 | 1 /* 45 seconds */); | ||
| 1497 | cFYI(1, ("Wrt seteof rc %d", rc)); | ||
| 1498 | } | ||
| 1499 | } else | ||
| 1500 | rc = -EINVAL; | ||
| 1501 | |||
| 1502 | if (rc != 0) { | ||
| 1503 | /* Set file size by pathname rather than by handle | ||
| 1504 | either because no valid, writeable file handle for | ||
| 1505 | it was found or because there was an error setting | ||
| 1506 | it by handle */ | ||
| 1507 | rc = CIFSSMBSetEOF(xid, pTcon, full_path, | ||
| 1508 | attrs->ia_size, false, | ||
| 1509 | cifs_sb->local_nls, | ||
| 1510 | cifs_sb->mnt_cifs_flags & | ||
| 1511 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1512 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); | ||
| 1513 | if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | ||
| 1514 | __u16 netfid; | ||
| 1515 | int oplock = 0; | ||
| 1516 | |||
| 1517 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
| 1518 | FILE_OPEN, GENERIC_WRITE, | ||
| 1519 | CREATE_NOT_DIR, &netfid, &oplock, | ||
| 1520 | NULL, cifs_sb->local_nls, | ||
| 1521 | cifs_sb->mnt_cifs_flags & | ||
| 1522 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1523 | if (rc == 0) { | ||
| 1524 | unsigned int bytes_written; | ||
| 1525 | rc = CIFSSMBWrite(xid, pTcon, | ||
| 1526 | netfid, 0, | ||
| 1527 | attrs->ia_size, | ||
| 1528 | &bytes_written, NULL, | ||
| 1529 | NULL, 1 /* 45 sec */); | ||
| 1530 | cFYI(1, ("wrt seteof rc %d", rc)); | ||
| 1531 | CIFSSMBClose(xid, pTcon, netfid); | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | } | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | /* Server is ok setting allocation size implicitly - no need | ||
| 1538 | to call: | ||
| 1539 | CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, true, | ||
| 1540 | cifs_sb->local_nls); | ||
| 1541 | */ | ||
| 1542 | |||
| 1543 | if (rc == 0) { | ||
| 1544 | rc = cifs_vmtruncate(inode, attrs->ia_size); | ||
| 1545 | cifs_truncate_page(inode->i_mapping, inode->i_size); | ||
| 1546 | } else | ||
| 1547 | goto cifs_setattr_exit; | 1766 | goto cifs_setattr_exit; |
| 1548 | } | 1767 | } |
| 1549 | 1768 | ||
| @@ -1554,21 +1773,8 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1554 | * CIFSACL support + proper Windows to Unix idmapping, we may be | 1773 | * CIFSACL support + proper Windows to Unix idmapping, we may be |
| 1555 | * able to support this in the future. | 1774 | * able to support this in the future. |
| 1556 | */ | 1775 | */ |
| 1557 | if (!pTcon->unix_ext && | 1776 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) |
| 1558 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { | ||
| 1559 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); | 1777 | attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); |
| 1560 | } else { | ||
| 1561 | if (attrs->ia_valid & ATTR_UID) { | ||
| 1562 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); | ||
| 1563 | uid = attrs->ia_uid; | ||
| 1564 | } | ||
| 1565 | if (attrs->ia_valid & ATTR_GID) { | ||
| 1566 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); | ||
| 1567 | gid = attrs->ia_gid; | ||
| 1568 | } | ||
| 1569 | } | ||
| 1570 | |||
| 1571 | time_buf.Attributes = 0; | ||
| 1572 | 1778 | ||
| 1573 | /* skip mode change if it's just for clearing setuid/setgid */ | 1779 | /* skip mode change if it's just for clearing setuid/setgid */ |
| 1574 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) | 1780 | if (attrs->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) |
| @@ -1579,13 +1785,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1579 | mode = attrs->ia_mode; | 1785 | mode = attrs->ia_mode; |
| 1580 | } | 1786 | } |
| 1581 | 1787 | ||
| 1582 | if ((pTcon->unix_ext) | 1788 | if (attrs->ia_valid & ATTR_MODE) { |
| 1583 | && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) | ||
| 1584 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, | ||
| 1585 | 0 /* dev_t */, cifs_sb->local_nls, | ||
| 1586 | cifs_sb->mnt_cifs_flags & | ||
| 1587 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1588 | else if (attrs->ia_valid & ATTR_MODE) { | ||
| 1589 | rc = 0; | 1789 | rc = 0; |
| 1590 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1790 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 1591 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 1791 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) |
| @@ -1594,24 +1794,19 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1594 | #endif | 1794 | #endif |
| 1595 | if (((mode & S_IWUGO) == 0) && | 1795 | if (((mode & S_IWUGO) == 0) && |
| 1596 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { | 1796 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
| 1597 | set_dosattr = true; | 1797 | |
| 1598 | time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | | 1798 | dosattr = cifsInode->cifsAttrs | ATTR_READONLY; |
| 1599 | ATTR_READONLY); | 1799 | |
| 1600 | /* fix up mode if we're not using dynperm */ | 1800 | /* fix up mode if we're not using dynperm */ |
| 1601 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | 1801 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) |
| 1602 | attrs->ia_mode = inode->i_mode & ~S_IWUGO; | 1802 | attrs->ia_mode = inode->i_mode & ~S_IWUGO; |
| 1603 | } else if ((mode & S_IWUGO) && | 1803 | } else if ((mode & S_IWUGO) && |
| 1604 | (cifsInode->cifsAttrs & ATTR_READONLY)) { | 1804 | (cifsInode->cifsAttrs & ATTR_READONLY)) { |
| 1605 | /* If file is readonly on server, we would | 1805 | |
| 1606 | not be able to write to it - so if any write | 1806 | dosattr = cifsInode->cifsAttrs & ~ATTR_READONLY; |
| 1607 | bit is enabled for user or group or other we | 1807 | /* Attributes of 0 are ignored */ |
| 1608 | need to at least try to remove r/o dos attr */ | 1808 | if (dosattr == 0) |
| 1609 | set_dosattr = true; | 1809 | dosattr |= ATTR_NORMAL; |
| 1610 | time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs & | ||
| 1611 | (~ATTR_READONLY)); | ||
| 1612 | /* Windows ignores set to zero */ | ||
| 1613 | if (time_buf.Attributes == 0) | ||
| 1614 | time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); | ||
| 1615 | 1810 | ||
| 1616 | /* reset local inode permissions to normal */ | 1811 | /* reset local inode permissions to normal */ |
| 1617 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { | 1812 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { |
| @@ -1629,82 +1824,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1629 | } | 1824 | } |
| 1630 | } | 1825 | } |
| 1631 | 1826 | ||
| 1632 | if (attrs->ia_valid & ATTR_ATIME) { | 1827 | if (attrs->ia_valid & (ATTR_MTIME|ATTR_ATIME|ATTR_CTIME) || |
| 1633 | set_time = true; | 1828 | ((attrs->ia_valid & ATTR_MODE) && dosattr)) { |
| 1634 | time_buf.LastAccessTime = | 1829 | rc = cifs_set_file_info(inode, attrs, xid, full_path, dosattr); |
| 1635 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); | 1830 | /* BB: check for rc = -EOPNOTSUPP and switch to legacy mode */ |
| 1636 | } else | ||
| 1637 | time_buf.LastAccessTime = 0; | ||
| 1638 | |||
| 1639 | if (attrs->ia_valid & ATTR_MTIME) { | ||
| 1640 | set_time = true; | ||
| 1641 | time_buf.LastWriteTime = | ||
| 1642 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | ||
| 1643 | } else | ||
| 1644 | time_buf.LastWriteTime = 0; | ||
| 1645 | /* Do not set ctime explicitly unless other time | ||
| 1646 | stamps are changed explicitly (i.e. by utime() | ||
| 1647 | since we would then have a mix of client and | ||
| 1648 | server times */ | ||
| 1649 | |||
| 1650 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
| 1651 | set_time = true; | ||
| 1652 | /* Although Samba throws this field away | ||
| 1653 | it may be useful to Windows - but we do | ||
| 1654 | not want to set ctime unless some other | ||
| 1655 | timestamp is changing */ | ||
| 1656 | cFYI(1, ("CIFS - CTIME changed")); | ||
| 1657 | time_buf.ChangeTime = | ||
| 1658 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | ||
| 1659 | } else | ||
| 1660 | time_buf.ChangeTime = 0; | ||
| 1661 | |||
| 1662 | if (set_time || set_dosattr) { | ||
| 1663 | time_buf.CreationTime = 0; /* do not change */ | ||
| 1664 | /* In the future we should experiment - try setting timestamps | ||
| 1665 | via Handle (SetFileInfo) instead of by path */ | ||
| 1666 | if (!(pTcon->ses->flags & CIFS_SES_NT4)) | ||
| 1667 | rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, | ||
| 1668 | cifs_sb->local_nls, | ||
| 1669 | cifs_sb->mnt_cifs_flags & | ||
| 1670 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1671 | else | ||
| 1672 | rc = -EOPNOTSUPP; | ||
| 1673 | 1831 | ||
| 1674 | if (rc == -EOPNOTSUPP) { | ||
| 1675 | int oplock = 0; | ||
| 1676 | __u16 netfid; | ||
| 1677 | |||
| 1678 | cFYI(1, ("calling SetFileInfo since SetPathInfo for " | ||
| 1679 | "times not supported by this server")); | ||
| 1680 | /* BB we could scan to see if we already have it open | ||
| 1681 | and pass in pid of opener to function */ | ||
| 1682 | rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, | ||
| 1683 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
| 1684 | CREATE_NOT_DIR, &netfid, &oplock, | ||
| 1685 | NULL, cifs_sb->local_nls, | ||
| 1686 | cifs_sb->mnt_cifs_flags & | ||
| 1687 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1688 | if (rc == 0) { | ||
| 1689 | rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf, | ||
| 1690 | netfid); | ||
| 1691 | CIFSSMBClose(xid, pTcon, netfid); | ||
| 1692 | } else { | ||
| 1693 | /* BB For even older servers we could convert time_buf | ||
| 1694 | into old DOS style which uses two second | ||
| 1695 | granularity */ | ||
| 1696 | |||
| 1697 | /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path, | ||
| 1698 | &time_buf, cifs_sb->local_nls); */ | ||
| 1699 | } | ||
| 1700 | } | ||
| 1701 | /* Even if error on time set, no sense failing the call if | 1832 | /* Even if error on time set, no sense failing the call if |
| 1702 | the server would set the time to a reasonable value anyway, | 1833 | the server would set the time to a reasonable value anyway, |
| 1703 | and this check ensures that we are not being called from | 1834 | and this check ensures that we are not being called from |
| 1704 | sys_utimes in which case we ought to fail the call back to | 1835 | sys_utimes in which case we ought to fail the call back to |
| 1705 | the user when the server rejects the call */ | 1836 | the user when the server rejects the call */ |
| 1706 | if ((rc) && (attrs->ia_valid & | 1837 | if ((rc) && (attrs->ia_valid & |
| 1707 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | 1838 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) |
| 1708 | rc = 0; | 1839 | rc = 0; |
| 1709 | } | 1840 | } |
| 1710 | 1841 | ||
| @@ -1718,6 +1849,21 @@ cifs_setattr_exit: | |||
| 1718 | return rc; | 1849 | return rc; |
| 1719 | } | 1850 | } |
| 1720 | 1851 | ||
| 1852 | int | ||
| 1853 | cifs_setattr(struct dentry *direntry, struct iattr *attrs) | ||
| 1854 | { | ||
| 1855 | struct inode *inode = direntry->d_inode; | ||
| 1856 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
| 1857 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | ||
| 1858 | |||
| 1859 | if (pTcon->unix_ext) | ||
| 1860 | return cifs_setattr_unix(direntry, attrs); | ||
| 1861 | |||
| 1862 | return cifs_setattr_nounix(direntry, attrs); | ||
| 1863 | |||
| 1864 | /* BB: add cifs_setattr_legacy for really old servers */ | ||
| 1865 | } | ||
| 1866 | |||
| 1721 | #if 0 | 1867 | #if 0 |
| 1722 | void cifs_delete_inode(struct inode *inode) | 1868 | void cifs_delete_inode(struct inode *inode) |
| 1723 | { | 1869 | { |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 83f306954883..5f40ed3473f5 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -690,6 +690,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 690 | else | 690 | else |
| 691 | cifs_buf_release(cifsFile->srch_inf. | 691 | cifs_buf_release(cifsFile->srch_inf. |
| 692 | ntwrk_buf_start); | 692 | ntwrk_buf_start); |
| 693 | cifsFile->srch_inf.ntwrk_buf_start = NULL; | ||
| 693 | } | 694 | } |
| 694 | rc = initiate_cifs_search(xid, file); | 695 | rc = initiate_cifs_search(xid, file); |
| 695 | if (rc) { | 696 | if (rc) { |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index ed150efbe27c..252fdc0567f1 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -409,6 +409,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 409 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 409 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 410 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; | 410 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; |
| 411 | 411 | ||
| 412 | pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; | ||
| 413 | |||
| 412 | /* no capabilities flags in old lanman negotiation */ | 414 | /* no capabilities flags in old lanman negotiation */ |
| 413 | 415 | ||
| 414 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); | 416 | pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); |
| @@ -505,7 +507,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 505 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | 507 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); |
| 506 | } else | 508 | } else |
| 507 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 509 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
| 508 | } else if (type == Kerberos) { | 510 | } else if (type == Kerberos || type == MSKerberos) { |
| 509 | #ifdef CONFIG_CIFS_UPCALL | 511 | #ifdef CONFIG_CIFS_UPCALL |
| 510 | struct cifs_spnego_msg *msg; | 512 | struct cifs_spnego_msg *msg; |
| 511 | spnego_key = cifs_get_spnego_key(ses); | 513 | spnego_key = cifs_get_spnego_key(ses); |
| @@ -516,6 +518,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 516 | } | 518 | } |
| 517 | 519 | ||
| 518 | msg = spnego_key->payload.data; | 520 | msg = spnego_key->payload.data; |
| 521 | /* check version field to make sure that cifs.upcall is | ||
| 522 | sending us a response in an expected form */ | ||
| 523 | if (msg->version != CIFS_SPNEGO_UPCALL_VERSION) { | ||
| 524 | cERROR(1, ("incorrect version of cifs.upcall (expected" | ||
| 525 | " %d but got %d)", | ||
| 526 | CIFS_SPNEGO_UPCALL_VERSION, msg->version)); | ||
| 527 | rc = -EKEYREJECTED; | ||
| 528 | goto ssetup_exit; | ||
| 529 | } | ||
| 519 | /* bail out if key is too long */ | 530 | /* bail out if key is too long */ |
| 520 | if (msg->sesskey_len > | 531 | if (msg->sesskey_len > |
| 521 | sizeof(ses->server->mac_signing_key.data.krb5)) { | 532 | sizeof(ses->server->mac_signing_key.data.krb5)) { |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 000ac509c98a..e286db9f5ee2 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -265,6 +265,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
| 265 | cFYI(1, ("Sending smb: total_len %d", total_len)); | 265 | cFYI(1, ("Sending smb: total_len %d", total_len)); |
| 266 | dump_smb(smb_buffer, len); | 266 | dump_smb(smb_buffer, len); |
| 267 | 267 | ||
| 268 | i = 0; | ||
| 268 | while (total_len) { | 269 | while (total_len) { |
| 269 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], | 270 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], |
| 270 | n_vec - first_vec, total_len); | 271 | n_vec - first_vec, total_len); |
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index e1c854890f94..bf4a3fd3c8e3 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c | |||
| @@ -28,11 +28,9 @@ int coda_fake_statfs; | |||
| 28 | char * coda_f2s(struct CodaFid *f) | 28 | char * coda_f2s(struct CodaFid *f) |
| 29 | { | 29 | { |
| 30 | static char s[60]; | 30 | static char s[60]; |
| 31 | #ifdef CONFIG_CODA_FS_OLD_API | 31 | |
| 32 | sprintf(s, "(%08x.%08x.%08x)", f->opaque[0], f->opaque[1], f->opaque[2]); | ||
| 33 | #else | ||
| 34 | sprintf(s, "(%08x.%08x.%08x.%08x)", f->opaque[0], f->opaque[1], f->opaque[2], f->opaque[3]); | 32 | sprintf(s, "(%08x.%08x.%08x.%08x)", f->opaque[0], f->opaque[1], f->opaque[2], f->opaque[3]); |
| 35 | #endif | 33 | |
| 36 | return s; | 34 | return s; |
| 37 | } | 35 | } |
| 38 | 36 | ||
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 3d2580e00a3e..c5916228243c 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
| @@ -137,9 +137,11 @@ exit: | |||
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | 139 | ||
| 140 | int coda_permission(struct inode *inode, int mask, struct nameidata *nd) | 140 | int coda_permission(struct inode *inode, int mask) |
| 141 | { | 141 | { |
| 142 | int error = 0; | 142 | int error = 0; |
| 143 | |||
| 144 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | ||
| 143 | 145 | ||
| 144 | if (!mask) | 146 | if (!mask) |
| 145 | return 0; | 147 | return 0; |
diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 2f58dfc70083..830f51abb971 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c | |||
| @@ -58,7 +58,7 @@ static void coda_destroy_inode(struct inode *inode) | |||
| 58 | kmem_cache_free(coda_inode_cachep, ITOC(inode)); | 58 | kmem_cache_free(coda_inode_cachep, ITOC(inode)); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static void init_once(struct kmem_cache * cachep, void *foo) | 61 | static void init_once(void *foo) |
| 62 | { | 62 | { |
| 63 | struct coda_inode_info *ei = (struct coda_inode_info *) foo; | 63 | struct coda_inode_info *ei = (struct coda_inode_info *) foo; |
| 64 | 64 | ||
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index c21a1f552a63..c51365422aa8 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c | |||
| @@ -24,8 +24,7 @@ | |||
| 24 | #include <linux/coda_psdev.h> | 24 | #include <linux/coda_psdev.h> |
| 25 | 25 | ||
| 26 | /* pioctl ops */ | 26 | /* pioctl ops */ |
| 27 | static int coda_ioctl_permission(struct inode *inode, int mask, | 27 | static int coda_ioctl_permission(struct inode *inode, int mask); |
| 28 | struct nameidata *nd); | ||
| 29 | static int coda_pioctl(struct inode * inode, struct file * filp, | 28 | static int coda_pioctl(struct inode * inode, struct file * filp, |
| 30 | unsigned int cmd, unsigned long user_data); | 29 | unsigned int cmd, unsigned long user_data); |
| 31 | 30 | ||
| @@ -42,8 +41,7 @@ const struct file_operations coda_ioctl_operations = { | |||
| 42 | }; | 41 | }; |
| 43 | 42 | ||
| 44 | /* the coda pioctl inode ops */ | 43 | /* the coda pioctl inode ops */ |
| 45 | static int coda_ioctl_permission(struct inode *inode, int mask, | 44 | static int coda_ioctl_permission(struct inode *inode, int mask) |
| 46 | struct nameidata *nd) | ||
| 47 | { | 45 | { |
| 48 | return 0; | 46 | return 0; |
| 49 | } | 47 | } |
| @@ -51,7 +49,7 @@ static int coda_ioctl_permission(struct inode *inode, int mask, | |||
| 51 | static int coda_pioctl(struct inode * inode, struct file * filp, | 49 | static int coda_pioctl(struct inode * inode, struct file * filp, |
| 52 | unsigned int cmd, unsigned long user_data) | 50 | unsigned int cmd, unsigned long user_data) |
| 53 | { | 51 | { |
| 54 | struct nameidata nd; | 52 | struct path path; |
| 55 | int error; | 53 | int error; |
| 56 | struct PioctlData data; | 54 | struct PioctlData data; |
| 57 | struct inode *target_inode = NULL; | 55 | struct inode *target_inode = NULL; |
| @@ -66,21 +64,21 @@ static int coda_pioctl(struct inode * inode, struct file * filp, | |||
| 66 | * Look up the pathname. Note that the pathname is in | 64 | * Look up the pathname. Note that the pathname is in |
| 67 | * user memory, and namei takes care of this | 65 | * user memory, and namei takes care of this |
| 68 | */ | 66 | */ |
| 69 | if ( data.follow ) { | 67 | if (data.follow) { |
| 70 | error = user_path_walk(data.path, &nd); | 68 | error = user_path(data.path, &path); |
| 71 | } else { | 69 | } else { |
| 72 | error = user_path_walk_link(data.path, &nd); | 70 | error = user_lpath(data.path, &path); |
| 73 | } | 71 | } |
| 74 | 72 | ||
| 75 | if ( error ) { | 73 | if ( error ) { |
| 76 | return error; | 74 | return error; |
| 77 | } else { | 75 | } else { |
| 78 | target_inode = nd.path.dentry->d_inode; | 76 | target_inode = path.dentry->d_inode; |
| 79 | } | 77 | } |
| 80 | 78 | ||
| 81 | /* return if it is not a Coda inode */ | 79 | /* return if it is not a Coda inode */ |
| 82 | if ( target_inode->i_sb != inode->i_sb ) { | 80 | if ( target_inode->i_sb != inode->i_sb ) { |
| 83 | path_put(&nd.path); | 81 | path_put(&path); |
| 84 | return -EINVAL; | 82 | return -EINVAL; |
| 85 | } | 83 | } |
| 86 | 84 | ||
| @@ -89,7 +87,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp, | |||
| 89 | 87 | ||
| 90 | error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data); | 88 | error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data); |
| 91 | 89 | ||
| 92 | path_put(&nd.path); | 90 | path_put(&path); |
| 93 | return error; | 91 | return error; |
| 94 | } | 92 | } |
| 95 | 93 | ||
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 40c36f7352a6..0d9b80ec689c 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c | |||
| @@ -378,11 +378,7 @@ MODULE_AUTHOR("Jan Harkes, Peter J. Braam"); | |||
| 378 | MODULE_DESCRIPTION("Coda Distributed File System VFS interface"); | 378 | MODULE_DESCRIPTION("Coda Distributed File System VFS interface"); |
| 379 | MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR); | 379 | MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR); |
| 380 | MODULE_LICENSE("GPL"); | 380 | MODULE_LICENSE("GPL"); |
| 381 | #ifdef CONFIG_CODA_FS_OLD_API | ||
| 382 | MODULE_VERSION("5.3.21"); | ||
| 383 | #else | ||
| 384 | MODULE_VERSION("6.6"); | 381 | MODULE_VERSION("6.6"); |
| 385 | #endif | ||
| 386 | 382 | ||
| 387 | static int __init init_coda(void) | 383 | static int __init init_coda(void) |
| 388 | { | 384 | { |
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 359e531094dd..ce432bca95d1 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c | |||
| @@ -52,12 +52,8 @@ static void *alloc_upcall(int opcode, int size) | |||
| 52 | inp->ih.opcode = opcode; | 52 | inp->ih.opcode = opcode; |
| 53 | inp->ih.pid = current->pid; | 53 | inp->ih.pid = current->pid; |
| 54 | inp->ih.pgid = task_pgrp_nr(current); | 54 | inp->ih.pgid = task_pgrp_nr(current); |
| 55 | #ifdef CONFIG_CODA_FS_OLD_API | ||
| 56 | memset(&inp->ih.cred, 0, sizeof(struct coda_cred)); | ||
| 57 | inp->ih.cred.cr_fsuid = current->fsuid; | ||
| 58 | #else | ||
| 59 | inp->ih.uid = current->fsuid; | 55 | inp->ih.uid = current->fsuid; |
| 60 | #endif | 56 | |
| 61 | return (void*)inp; | 57 | return (void*)inp; |
| 62 | } | 58 | } |
| 63 | 59 | ||
| @@ -166,20 +162,11 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags, | |||
| 166 | union inputArgs *inp; | 162 | union inputArgs *inp; |
| 167 | union outputArgs *outp; | 163 | union outputArgs *outp; |
| 168 | int insize, outsize, error; | 164 | int insize, outsize, error; |
| 169 | #ifdef CONFIG_CODA_FS_OLD_API | ||
| 170 | struct coda_cred cred = { 0, }; | ||
| 171 | cred.cr_fsuid = uid; | ||
| 172 | #endif | ||
| 173 | 165 | ||
| 174 | insize = SIZE(release); | 166 | insize = SIZE(release); |
| 175 | UPARG(CODA_CLOSE); | 167 | UPARG(CODA_CLOSE); |
| 176 | 168 | ||
| 177 | #ifdef CONFIG_CODA_FS_OLD_API | ||
| 178 | memcpy(&(inp->ih.cred), &cred, sizeof(cred)); | ||
| 179 | #else | ||
| 180 | inp->ih.uid = uid; | 169 | inp->ih.uid = uid; |
| 181 | #endif | ||
| 182 | |||
| 183 | inp->coda_close.VFid = *fid; | 170 | inp->coda_close.VFid = *fid; |
| 184 | inp->coda_close.flags = flags; | 171 | inp->coda_close.flags = flags; |
| 185 | 172 | ||
diff --git a/fs/compat.c b/fs/compat.c index 106eba28ec5a..075d0509970d 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -234,18 +234,18 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs * | |||
| 234 | * The following statfs calls are copies of code from fs/open.c and | 234 | * The following statfs calls are copies of code from fs/open.c and |
| 235 | * should be checked against those from time to time | 235 | * should be checked against those from time to time |
| 236 | */ | 236 | */ |
| 237 | asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf) | 237 | asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf) |
| 238 | { | 238 | { |
| 239 | struct nameidata nd; | 239 | struct path path; |
| 240 | int error; | 240 | int error; |
| 241 | 241 | ||
| 242 | error = user_path_walk(path, &nd); | 242 | error = user_path(pathname, &path); |
| 243 | if (!error) { | 243 | if (!error) { |
| 244 | struct kstatfs tmp; | 244 | struct kstatfs tmp; |
| 245 | error = vfs_statfs(nd.path.dentry, &tmp); | 245 | error = vfs_statfs(path.dentry, &tmp); |
| 246 | if (!error) | 246 | if (!error) |
| 247 | error = put_compat_statfs(buf, &tmp); | 247 | error = put_compat_statfs(buf, &tmp); |
| 248 | path_put(&nd.path); | 248 | path_put(&path); |
| 249 | } | 249 | } |
| 250 | return error; | 250 | return error; |
| 251 | } | 251 | } |
| @@ -299,21 +299,21 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat | |||
| 299 | return 0; | 299 | return 0; |
| 300 | } | 300 | } |
| 301 | 301 | ||
| 302 | asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf) | 302 | asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf) |
| 303 | { | 303 | { |
| 304 | struct nameidata nd; | 304 | struct path path; |
| 305 | int error; | 305 | int error; |
| 306 | 306 | ||
| 307 | if (sz != sizeof(*buf)) | 307 | if (sz != sizeof(*buf)) |
| 308 | return -EINVAL; | 308 | return -EINVAL; |
| 309 | 309 | ||
| 310 | error = user_path_walk(path, &nd); | 310 | error = user_path(pathname, &path); |
| 311 | if (!error) { | 311 | if (!error) { |
| 312 | struct kstatfs tmp; | 312 | struct kstatfs tmp; |
| 313 | error = vfs_statfs(nd.path.dentry, &tmp); | 313 | error = vfs_statfs(path.dentry, &tmp); |
| 314 | if (!error) | 314 | if (!error) |
| 315 | error = put_compat_statfs64(buf, &tmp); | 315 | error = put_compat_statfs64(buf, &tmp); |
| 316 | path_put(&nd.path); | 316 | path_put(&path); |
| 317 | } | 317 | } |
| 318 | return error; | 318 | return error; |
| 319 | } | 319 | } |
| @@ -792,8 +792,10 @@ static int compat_fillonedir(void *__buf, const char *name, int namlen, | |||
| 792 | if (buf->result) | 792 | if (buf->result) |
| 793 | return -EINVAL; | 793 | return -EINVAL; |
| 794 | d_ino = ino; | 794 | d_ino = ino; |
| 795 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) | 795 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { |
| 796 | buf->result = -EOVERFLOW; | ||
| 796 | return -EOVERFLOW; | 797 | return -EOVERFLOW; |
| 798 | } | ||
| 797 | buf->result++; | 799 | buf->result++; |
| 798 | dirent = buf->dirent; | 800 | dirent = buf->dirent; |
| 799 | if (!access_ok(VERIFY_WRITE, dirent, | 801 | if (!access_ok(VERIFY_WRITE, dirent, |
| @@ -862,8 +864,10 @@ static int compat_filldir(void *__buf, const char *name, int namlen, | |||
| 862 | if (reclen > buf->count) | 864 | if (reclen > buf->count) |
| 863 | return -EINVAL; | 865 | return -EINVAL; |
| 864 | d_ino = ino; | 866 | d_ino = ino; |
| 865 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) | 867 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { |
| 868 | buf->error = -EOVERFLOW; | ||
| 866 | return -EOVERFLOW; | 869 | return -EOVERFLOW; |
| 870 | } | ||
| 867 | dirent = buf->previous; | 871 | dirent = buf->previous; |
| 868 | if (dirent) { | 872 | if (dirent) { |
| 869 | if (__put_user(offset, &dirent->d_off)) | 873 | if (__put_user(offset, &dirent->d_off)) |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 18e2c548161d..5235c67e7594 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/raid/md.h> | 26 | #include <linux/raid/md.h> |
| 27 | #include <linux/kd.h> | 27 | #include <linux/kd.h> |
| 28 | #include <linux/dirent.h> | ||
| 29 | #include <linux/route.h> | 28 | #include <linux/route.h> |
| 30 | #include <linux/in6.h> | 29 | #include <linux/in6.h> |
| 31 | #include <linux/ipv6_route.h> | 30 | #include <linux/ipv6_route.h> |
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index da015c12e3ea..762d287123ca 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
| @@ -49,8 +49,10 @@ struct configfs_dirent { | |||
| 49 | #define CONFIGFS_USET_DEFAULT 0x0080 | 49 | #define CONFIGFS_USET_DEFAULT 0x0080 |
| 50 | #define CONFIGFS_USET_DROPPING 0x0100 | 50 | #define CONFIGFS_USET_DROPPING 0x0100 |
| 51 | #define CONFIGFS_USET_IN_MKDIR 0x0200 | 51 | #define CONFIGFS_USET_IN_MKDIR 0x0200 |
| 52 | #define CONFIGFS_USET_CREATING 0x0400 | ||
| 52 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) | 53 | #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR) |
| 53 | 54 | ||
| 55 | extern struct mutex configfs_symlink_mutex; | ||
| 54 | extern spinlock_t configfs_dirent_lock; | 56 | extern spinlock_t configfs_dirent_lock; |
| 55 | 57 | ||
| 56 | extern struct vfsmount * configfs_mount; | 58 | extern struct vfsmount * configfs_mount; |
| @@ -66,6 +68,7 @@ extern void configfs_inode_exit(void); | |||
| 66 | extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); | 68 | extern int configfs_create_file(struct config_item *, const struct configfs_attribute *); |
| 67 | extern int configfs_make_dirent(struct configfs_dirent *, | 69 | extern int configfs_make_dirent(struct configfs_dirent *, |
| 68 | struct dentry *, void *, umode_t, int); | 70 | struct dentry *, void *, umode_t, int); |
| 71 | extern int configfs_dirent_is_ready(struct configfs_dirent *); | ||
| 69 | 72 | ||
| 70 | extern int configfs_add_file(struct dentry *, const struct configfs_attribute *, int); | 73 | extern int configfs_add_file(struct dentry *, const struct configfs_attribute *, int); |
| 71 | extern void configfs_hash_and_remove(struct dentry * dir, const char * name); | 74 | extern void configfs_hash_and_remove(struct dentry * dir, const char * name); |
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 179589be063a..8e93341f3e82 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
| @@ -185,7 +185,7 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
| 185 | error = configfs_dirent_exists(p->d_fsdata, d->d_name.name); | 185 | error = configfs_dirent_exists(p->d_fsdata, d->d_name.name); |
| 186 | if (!error) | 186 | if (!error) |
| 187 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, | 187 | error = configfs_make_dirent(p->d_fsdata, d, k, mode, |
| 188 | CONFIGFS_DIR); | 188 | CONFIGFS_DIR | CONFIGFS_USET_CREATING); |
| 189 | if (!error) { | 189 | if (!error) { |
| 190 | error = configfs_create(d, mode, init_dir); | 190 | error = configfs_create(d, mode, init_dir); |
| 191 | if (!error) { | 191 | if (!error) { |
| @@ -209,6 +209,9 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
| 209 | * configfs_create_dir - create a directory for an config_item. | 209 | * configfs_create_dir - create a directory for an config_item. |
| 210 | * @item: config_itemwe're creating directory for. | 210 | * @item: config_itemwe're creating directory for. |
| 211 | * @dentry: config_item's dentry. | 211 | * @dentry: config_item's dentry. |
| 212 | * | ||
| 213 | * Note: user-created entries won't be allowed under this new directory | ||
| 214 | * until it is validated by configfs_dir_set_ready() | ||
| 212 | */ | 215 | */ |
| 213 | 216 | ||
| 214 | static int configfs_create_dir(struct config_item * item, struct dentry *dentry) | 217 | static int configfs_create_dir(struct config_item * item, struct dentry *dentry) |
| @@ -231,6 +234,44 @@ static int configfs_create_dir(struct config_item * item, struct dentry *dentry) | |||
| 231 | return error; | 234 | return error; |
| 232 | } | 235 | } |
| 233 | 236 | ||
| 237 | /* | ||
| 238 | * Allow userspace to create new entries under a new directory created with | ||
| 239 | * configfs_create_dir(), and under all of its chidlren directories recursively. | ||
| 240 | * @sd configfs_dirent of the new directory to validate | ||
| 241 | * | ||
| 242 | * Caller must hold configfs_dirent_lock. | ||
| 243 | */ | ||
| 244 | static void configfs_dir_set_ready(struct configfs_dirent *sd) | ||
| 245 | { | ||
| 246 | struct configfs_dirent *child_sd; | ||
| 247 | |||
| 248 | sd->s_type &= ~CONFIGFS_USET_CREATING; | ||
| 249 | list_for_each_entry(child_sd, &sd->s_children, s_sibling) | ||
| 250 | if (child_sd->s_type & CONFIGFS_USET_CREATING) | ||
| 251 | configfs_dir_set_ready(child_sd); | ||
| 252 | } | ||
| 253 | |||
| 254 | /* | ||
| 255 | * Check that a directory does not belong to a directory hierarchy being | ||
| 256 | * attached and not validated yet. | ||
| 257 | * @sd configfs_dirent of the directory to check | ||
| 258 | * | ||
| 259 | * @return non-zero iff the directory was validated | ||
| 260 | * | ||
| 261 | * Note: takes configfs_dirent_lock, so the result may change from false to true | ||
| 262 | * in two consecutive calls, but never from true to false. | ||
| 263 | */ | ||
| 264 | int configfs_dirent_is_ready(struct configfs_dirent *sd) | ||
| 265 | { | ||
| 266 | int ret; | ||
| 267 | |||
| 268 | spin_lock(&configfs_dirent_lock); | ||
| 269 | ret = !(sd->s_type & CONFIGFS_USET_CREATING); | ||
| 270 | spin_unlock(&configfs_dirent_lock); | ||
| 271 | |||
| 272 | return ret; | ||
| 273 | } | ||
| 274 | |||
| 234 | int configfs_create_link(struct configfs_symlink *sl, | 275 | int configfs_create_link(struct configfs_symlink *sl, |
| 235 | struct dentry *parent, | 276 | struct dentry *parent, |
| 236 | struct dentry *dentry) | 277 | struct dentry *dentry) |
| @@ -283,6 +324,8 @@ static void remove_dir(struct dentry * d) | |||
| 283 | * The only thing special about this is that we remove any files in | 324 | * The only thing special about this is that we remove any files in |
| 284 | * the directory before we remove the directory, and we've inlined | 325 | * the directory before we remove the directory, and we've inlined |
| 285 | * what used to be configfs_rmdir() below, instead of calling separately. | 326 | * what used to be configfs_rmdir() below, instead of calling separately. |
| 327 | * | ||
| 328 | * Caller holds the mutex of the item's inode | ||
| 286 | */ | 329 | */ |
| 287 | 330 | ||
| 288 | static void configfs_remove_dir(struct config_item * item) | 331 | static void configfs_remove_dir(struct config_item * item) |
| @@ -330,7 +373,19 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
| 330 | struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; | 373 | struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata; |
| 331 | struct configfs_dirent * sd; | 374 | struct configfs_dirent * sd; |
| 332 | int found = 0; | 375 | int found = 0; |
| 333 | int err = 0; | 376 | int err; |
| 377 | |||
| 378 | /* | ||
| 379 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
| 380 | * being attached | ||
| 381 | * | ||
| 382 | * This forbids userspace to read/write attributes of items which may | ||
| 383 | * not complete their initialization, since the dentries of the | ||
| 384 | * attributes won't be instantiated. | ||
| 385 | */ | ||
| 386 | err = -ENOENT; | ||
| 387 | if (!configfs_dirent_is_ready(parent_sd)) | ||
| 388 | goto out; | ||
| 334 | 389 | ||
| 335 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 390 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
| 336 | if (sd->s_type & CONFIGFS_NOT_PINNED) { | 391 | if (sd->s_type & CONFIGFS_NOT_PINNED) { |
| @@ -353,6 +408,7 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
| 353 | return simple_lookup(dir, dentry, nd); | 408 | return simple_lookup(dir, dentry, nd); |
| 354 | } | 409 | } |
| 355 | 410 | ||
| 411 | out: | ||
| 356 | return ERR_PTR(err); | 412 | return ERR_PTR(err); |
| 357 | } | 413 | } |
| 358 | 414 | ||
| @@ -370,13 +426,17 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex | |||
| 370 | struct configfs_dirent *sd; | 426 | struct configfs_dirent *sd; |
| 371 | int ret; | 427 | int ret; |
| 372 | 428 | ||
| 429 | /* Mark that we're trying to drop the group */ | ||
| 430 | parent_sd->s_type |= CONFIGFS_USET_DROPPING; | ||
| 431 | |||
| 373 | ret = -EBUSY; | 432 | ret = -EBUSY; |
| 374 | if (!list_empty(&parent_sd->s_links)) | 433 | if (!list_empty(&parent_sd->s_links)) |
| 375 | goto out; | 434 | goto out; |
| 376 | 435 | ||
| 377 | ret = 0; | 436 | ret = 0; |
| 378 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 437 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { |
| 379 | if (sd->s_type & CONFIGFS_NOT_PINNED) | 438 | if (!sd->s_element || |
| 439 | (sd->s_type & CONFIGFS_NOT_PINNED)) | ||
| 380 | continue; | 440 | continue; |
| 381 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { | 441 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { |
| 382 | /* Abort if racing with mkdir() */ | 442 | /* Abort if racing with mkdir() */ |
| @@ -385,8 +445,6 @@ static int configfs_detach_prep(struct dentry *dentry, struct mutex **wait_mutex | |||
| 385 | *wait_mutex = &sd->s_dentry->d_inode->i_mutex; | 445 | *wait_mutex = &sd->s_dentry->d_inode->i_mutex; |
| 386 | return -EAGAIN; | 446 | return -EAGAIN; |
| 387 | } | 447 | } |
| 388 | /* Mark that we're trying to drop the group */ | ||
| 389 | sd->s_type |= CONFIGFS_USET_DROPPING; | ||
| 390 | 448 | ||
| 391 | /* | 449 | /* |
| 392 | * Yup, recursive. If there's a problem, blame | 450 | * Yup, recursive. If there's a problem, blame |
| @@ -414,12 +472,11 @@ static void configfs_detach_rollback(struct dentry *dentry) | |||
| 414 | struct configfs_dirent *parent_sd = dentry->d_fsdata; | 472 | struct configfs_dirent *parent_sd = dentry->d_fsdata; |
| 415 | struct configfs_dirent *sd; | 473 | struct configfs_dirent *sd; |
| 416 | 474 | ||
| 417 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | 475 | parent_sd->s_type &= ~CONFIGFS_USET_DROPPING; |
| 418 | if (sd->s_type & CONFIGFS_USET_DEFAULT) { | 476 | |
| 477 | list_for_each_entry(sd, &parent_sd->s_children, s_sibling) | ||
| 478 | if (sd->s_type & CONFIGFS_USET_DEFAULT) | ||
| 419 | configfs_detach_rollback(sd->s_dentry); | 479 | configfs_detach_rollback(sd->s_dentry); |
| 420 | sd->s_type &= ~CONFIGFS_USET_DROPPING; | ||
| 421 | } | ||
| 422 | } | ||
| 423 | } | 480 | } |
| 424 | 481 | ||
| 425 | static void detach_attrs(struct config_item * item) | 482 | static void detach_attrs(struct config_item * item) |
| @@ -558,36 +615,21 @@ static int create_default_group(struct config_group *parent_group, | |||
| 558 | static int populate_groups(struct config_group *group) | 615 | static int populate_groups(struct config_group *group) |
| 559 | { | 616 | { |
| 560 | struct config_group *new_group; | 617 | struct config_group *new_group; |
| 561 | struct dentry *dentry = group->cg_item.ci_dentry; | ||
| 562 | int ret = 0; | 618 | int ret = 0; |
| 563 | int i; | 619 | int i; |
| 564 | 620 | ||
| 565 | if (group->default_groups) { | 621 | if (group->default_groups) { |
| 566 | /* | ||
| 567 | * FYI, we're faking mkdir here | ||
| 568 | * I'm not sure we need this semaphore, as we're called | ||
| 569 | * from our parent's mkdir. That holds our parent's | ||
| 570 | * i_mutex, so afaik lookup cannot continue through our | ||
| 571 | * parent to find us, let alone mess with our tree. | ||
| 572 | * That said, taking our i_mutex is closer to mkdir | ||
| 573 | * emulation, and shouldn't hurt. | ||
| 574 | */ | ||
| 575 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | ||
| 576 | |||
| 577 | for (i = 0; group->default_groups[i]; i++) { | 622 | for (i = 0; group->default_groups[i]; i++) { |
| 578 | new_group = group->default_groups[i]; | 623 | new_group = group->default_groups[i]; |
| 579 | 624 | ||
| 580 | ret = create_default_group(group, new_group); | 625 | ret = create_default_group(group, new_group); |
| 581 | if (ret) | 626 | if (ret) { |
| 627 | detach_groups(group); | ||
| 582 | break; | 628 | break; |
| 629 | } | ||
| 583 | } | 630 | } |
| 584 | |||
| 585 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
| 586 | } | 631 | } |
| 587 | 632 | ||
| 588 | if (ret) | ||
| 589 | detach_groups(group); | ||
| 590 | |||
| 591 | return ret; | 633 | return ret; |
| 592 | } | 634 | } |
| 593 | 635 | ||
| @@ -702,7 +744,15 @@ static int configfs_attach_item(struct config_item *parent_item, | |||
| 702 | if (!ret) { | 744 | if (!ret) { |
| 703 | ret = populate_attrs(item); | 745 | ret = populate_attrs(item); |
| 704 | if (ret) { | 746 | if (ret) { |
| 747 | /* | ||
| 748 | * We are going to remove an inode and its dentry but | ||
| 749 | * the VFS may already have hit and used them. Thus, | ||
| 750 | * we must lock them as rmdir() would. | ||
| 751 | */ | ||
| 752 | mutex_lock(&dentry->d_inode->i_mutex); | ||
| 705 | configfs_remove_dir(item); | 753 | configfs_remove_dir(item); |
| 754 | dentry->d_inode->i_flags |= S_DEAD; | ||
| 755 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
| 706 | d_delete(dentry); | 756 | d_delete(dentry); |
| 707 | } | 757 | } |
| 708 | } | 758 | } |
| @@ -710,6 +760,7 @@ static int configfs_attach_item(struct config_item *parent_item, | |||
| 710 | return ret; | 760 | return ret; |
| 711 | } | 761 | } |
| 712 | 762 | ||
| 763 | /* Caller holds the mutex of the item's inode */ | ||
| 713 | static void configfs_detach_item(struct config_item *item) | 764 | static void configfs_detach_item(struct config_item *item) |
| 714 | { | 765 | { |
| 715 | detach_attrs(item); | 766 | detach_attrs(item); |
| @@ -728,16 +779,30 @@ static int configfs_attach_group(struct config_item *parent_item, | |||
| 728 | sd = dentry->d_fsdata; | 779 | sd = dentry->d_fsdata; |
| 729 | sd->s_type |= CONFIGFS_USET_DIR; | 780 | sd->s_type |= CONFIGFS_USET_DIR; |
| 730 | 781 | ||
| 782 | /* | ||
| 783 | * FYI, we're faking mkdir in populate_groups() | ||
| 784 | * We must lock the group's inode to avoid races with the VFS | ||
| 785 | * which can already hit the inode and try to add/remove entries | ||
| 786 | * under it. | ||
| 787 | * | ||
| 788 | * We must also lock the inode to remove it safely in case of | ||
| 789 | * error, as rmdir() would. | ||
| 790 | */ | ||
| 791 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | ||
| 731 | ret = populate_groups(to_config_group(item)); | 792 | ret = populate_groups(to_config_group(item)); |
| 732 | if (ret) { | 793 | if (ret) { |
| 733 | configfs_detach_item(item); | 794 | configfs_detach_item(item); |
| 734 | d_delete(dentry); | 795 | dentry->d_inode->i_flags |= S_DEAD; |
| 735 | } | 796 | } |
| 797 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
| 798 | if (ret) | ||
| 799 | d_delete(dentry); | ||
| 736 | } | 800 | } |
| 737 | 801 | ||
| 738 | return ret; | 802 | return ret; |
| 739 | } | 803 | } |
| 740 | 804 | ||
| 805 | /* Caller holds the mutex of the group's inode */ | ||
| 741 | static void configfs_detach_group(struct config_item *item) | 806 | static void configfs_detach_group(struct config_item *item) |
| 742 | { | 807 | { |
| 743 | detach_groups(to_config_group(item)); | 808 | detach_groups(to_config_group(item)); |
| @@ -1035,7 +1100,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1035 | struct configfs_subsystem *subsys; | 1100 | struct configfs_subsystem *subsys; |
| 1036 | struct configfs_dirent *sd; | 1101 | struct configfs_dirent *sd; |
| 1037 | struct config_item_type *type; | 1102 | struct config_item_type *type; |
| 1038 | struct module *owner = NULL; | 1103 | struct module *subsys_owner = NULL, *new_item_owner = NULL; |
| 1039 | char *name; | 1104 | char *name; |
| 1040 | 1105 | ||
| 1041 | if (dentry->d_parent == configfs_sb->s_root) { | 1106 | if (dentry->d_parent == configfs_sb->s_root) { |
| @@ -1044,6 +1109,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1044 | } | 1109 | } |
| 1045 | 1110 | ||
| 1046 | sd = dentry->d_parent->d_fsdata; | 1111 | sd = dentry->d_parent->d_fsdata; |
| 1112 | |||
| 1113 | /* | ||
| 1114 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
| 1115 | * being attached | ||
| 1116 | */ | ||
| 1117 | if (!configfs_dirent_is_ready(sd)) { | ||
| 1118 | ret = -ENOENT; | ||
| 1119 | goto out; | ||
| 1120 | } | ||
| 1121 | |||
| 1047 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { | 1122 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { |
| 1048 | ret = -EPERM; | 1123 | ret = -EPERM; |
| 1049 | goto out; | 1124 | goto out; |
| @@ -1062,10 +1137,25 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1062 | goto out_put; | 1137 | goto out_put; |
| 1063 | } | 1138 | } |
| 1064 | 1139 | ||
| 1140 | /* | ||
| 1141 | * The subsystem may belong to a different module than the item | ||
| 1142 | * being created. We don't want to safely pin the new item but | ||
| 1143 | * fail to pin the subsystem it sits under. | ||
| 1144 | */ | ||
| 1145 | if (!subsys->su_group.cg_item.ci_type) { | ||
| 1146 | ret = -EINVAL; | ||
| 1147 | goto out_put; | ||
| 1148 | } | ||
| 1149 | subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; | ||
| 1150 | if (!try_module_get(subsys_owner)) { | ||
| 1151 | ret = -EINVAL; | ||
| 1152 | goto out_put; | ||
| 1153 | } | ||
| 1154 | |||
| 1065 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); | 1155 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); |
| 1066 | if (!name) { | 1156 | if (!name) { |
| 1067 | ret = -ENOMEM; | 1157 | ret = -ENOMEM; |
| 1068 | goto out_put; | 1158 | goto out_subsys_put; |
| 1069 | } | 1159 | } |
| 1070 | 1160 | ||
| 1071 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); | 1161 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); |
| @@ -1094,10 +1184,10 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1094 | kfree(name); | 1184 | kfree(name); |
| 1095 | if (ret) { | 1185 | if (ret) { |
| 1096 | /* | 1186 | /* |
| 1097 | * If item == NULL, then link_obj() was never called. | 1187 | * If ret != 0, then link_obj() was never called. |
| 1098 | * There are no extra references to clean up. | 1188 | * There are no extra references to clean up. |
| 1099 | */ | 1189 | */ |
| 1100 | goto out_put; | 1190 | goto out_subsys_put; |
| 1101 | } | 1191 | } |
| 1102 | 1192 | ||
| 1103 | /* | 1193 | /* |
| @@ -1111,8 +1201,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1111 | goto out_unlink; | 1201 | goto out_unlink; |
| 1112 | } | 1202 | } |
| 1113 | 1203 | ||
| 1114 | owner = type->ct_owner; | 1204 | new_item_owner = type->ct_owner; |
| 1115 | if (!try_module_get(owner)) { | 1205 | if (!try_module_get(new_item_owner)) { |
| 1116 | ret = -EINVAL; | 1206 | ret = -EINVAL; |
| 1117 | goto out_unlink; | 1207 | goto out_unlink; |
| 1118 | } | 1208 | } |
| @@ -1142,6 +1232,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 1142 | 1232 | ||
| 1143 | spin_lock(&configfs_dirent_lock); | 1233 | spin_lock(&configfs_dirent_lock); |
| 1144 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; | 1234 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; |
| 1235 | if (!ret) | ||
| 1236 | configfs_dir_set_ready(dentry->d_fsdata); | ||
| 1145 | spin_unlock(&configfs_dirent_lock); | 1237 | spin_unlock(&configfs_dirent_lock); |
| 1146 | 1238 | ||
| 1147 | out_unlink: | 1239 | out_unlink: |
| @@ -1159,9 +1251,13 @@ out_unlink: | |||
| 1159 | mutex_unlock(&subsys->su_mutex); | 1251 | mutex_unlock(&subsys->su_mutex); |
| 1160 | 1252 | ||
| 1161 | if (module_got) | 1253 | if (module_got) |
| 1162 | module_put(owner); | 1254 | module_put(new_item_owner); |
| 1163 | } | 1255 | } |
| 1164 | 1256 | ||
| 1257 | out_subsys_put: | ||
| 1258 | if (ret) | ||
| 1259 | module_put(subsys_owner); | ||
| 1260 | |||
| 1165 | out_put: | 1261 | out_put: |
| 1166 | /* | 1262 | /* |
| 1167 | * link_obj()/link_group() took a reference from child->parent, | 1263 | * link_obj()/link_group() took a reference from child->parent, |
| @@ -1180,7 +1276,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1180 | struct config_item *item; | 1276 | struct config_item *item; |
| 1181 | struct configfs_subsystem *subsys; | 1277 | struct configfs_subsystem *subsys; |
| 1182 | struct configfs_dirent *sd; | 1278 | struct configfs_dirent *sd; |
| 1183 | struct module *owner = NULL; | 1279 | struct module *subsys_owner = NULL, *dead_item_owner = NULL; |
| 1184 | int ret; | 1280 | int ret; |
| 1185 | 1281 | ||
| 1186 | if (dentry->d_parent == configfs_sb->s_root) | 1282 | if (dentry->d_parent == configfs_sb->s_root) |
| @@ -1207,14 +1303,26 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1207 | return -EINVAL; | 1303 | return -EINVAL; |
| 1208 | } | 1304 | } |
| 1209 | 1305 | ||
| 1210 | spin_lock(&configfs_dirent_lock); | 1306 | /* configfs_mkdir() shouldn't have allowed this */ |
| 1307 | BUG_ON(!subsys->su_group.cg_item.ci_type); | ||
| 1308 | subsys_owner = subsys->su_group.cg_item.ci_type->ct_owner; | ||
| 1309 | |||
| 1310 | /* | ||
| 1311 | * Ensure that no racing symlink() will make detach_prep() fail while | ||
| 1312 | * the new link is temporarily attached | ||
| 1313 | */ | ||
| 1211 | do { | 1314 | do { |
| 1212 | struct mutex *wait_mutex; | 1315 | struct mutex *wait_mutex; |
| 1213 | 1316 | ||
| 1317 | mutex_lock(&configfs_symlink_mutex); | ||
| 1318 | spin_lock(&configfs_dirent_lock); | ||
| 1214 | ret = configfs_detach_prep(dentry, &wait_mutex); | 1319 | ret = configfs_detach_prep(dentry, &wait_mutex); |
| 1215 | if (ret) { | 1320 | if (ret) |
| 1216 | configfs_detach_rollback(dentry); | 1321 | configfs_detach_rollback(dentry); |
| 1217 | spin_unlock(&configfs_dirent_lock); | 1322 | spin_unlock(&configfs_dirent_lock); |
| 1323 | mutex_unlock(&configfs_symlink_mutex); | ||
| 1324 | |||
| 1325 | if (ret) { | ||
| 1218 | if (ret != -EAGAIN) { | 1326 | if (ret != -EAGAIN) { |
| 1219 | config_item_put(parent_item); | 1327 | config_item_put(parent_item); |
| 1220 | return ret; | 1328 | return ret; |
| @@ -1223,11 +1331,8 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1223 | /* Wait until the racing operation terminates */ | 1331 | /* Wait until the racing operation terminates */ |
| 1224 | mutex_lock(wait_mutex); | 1332 | mutex_lock(wait_mutex); |
| 1225 | mutex_unlock(wait_mutex); | 1333 | mutex_unlock(wait_mutex); |
| 1226 | |||
| 1227 | spin_lock(&configfs_dirent_lock); | ||
| 1228 | } | 1334 | } |
| 1229 | } while (ret == -EAGAIN); | 1335 | } while (ret == -EAGAIN); |
| 1230 | spin_unlock(&configfs_dirent_lock); | ||
| 1231 | 1336 | ||
| 1232 | /* Get a working ref for the duration of this function */ | 1337 | /* Get a working ref for the duration of this function */ |
| 1233 | item = configfs_get_config_item(dentry); | 1338 | item = configfs_get_config_item(dentry); |
| @@ -1236,7 +1341,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1236 | config_item_put(parent_item); | 1341 | config_item_put(parent_item); |
| 1237 | 1342 | ||
| 1238 | if (item->ci_type) | 1343 | if (item->ci_type) |
| 1239 | owner = item->ci_type->ct_owner; | 1344 | dead_item_owner = item->ci_type->ct_owner; |
| 1240 | 1345 | ||
| 1241 | if (sd->s_type & CONFIGFS_USET_DIR) { | 1346 | if (sd->s_type & CONFIGFS_USET_DIR) { |
| 1242 | configfs_detach_group(item); | 1347 | configfs_detach_group(item); |
| @@ -1258,7 +1363,8 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 1258 | /* Drop our reference from above */ | 1363 | /* Drop our reference from above */ |
| 1259 | config_item_put(item); | 1364 | config_item_put(item); |
| 1260 | 1365 | ||
| 1261 | module_put(owner); | 1366 | module_put(dead_item_owner); |
| 1367 | module_put(subsys_owner); | ||
| 1262 | 1368 | ||
| 1263 | return 0; | 1369 | return 0; |
| 1264 | } | 1370 | } |
| @@ -1314,13 +1420,24 @@ static int configfs_dir_open(struct inode *inode, struct file *file) | |||
| 1314 | { | 1420 | { |
| 1315 | struct dentry * dentry = file->f_path.dentry; | 1421 | struct dentry * dentry = file->f_path.dentry; |
| 1316 | struct configfs_dirent * parent_sd = dentry->d_fsdata; | 1422 | struct configfs_dirent * parent_sd = dentry->d_fsdata; |
| 1423 | int err; | ||
| 1317 | 1424 | ||
| 1318 | mutex_lock(&dentry->d_inode->i_mutex); | 1425 | mutex_lock(&dentry->d_inode->i_mutex); |
| 1319 | file->private_data = configfs_new_dirent(parent_sd, NULL); | 1426 | /* |
| 1427 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
| 1428 | * being attached | ||
| 1429 | */ | ||
| 1430 | err = -ENOENT; | ||
| 1431 | if (configfs_dirent_is_ready(parent_sd)) { | ||
| 1432 | file->private_data = configfs_new_dirent(parent_sd, NULL); | ||
| 1433 | if (IS_ERR(file->private_data)) | ||
| 1434 | err = PTR_ERR(file->private_data); | ||
| 1435 | else | ||
| 1436 | err = 0; | ||
| 1437 | } | ||
| 1320 | mutex_unlock(&dentry->d_inode->i_mutex); | 1438 | mutex_unlock(&dentry->d_inode->i_mutex); |
| 1321 | 1439 | ||
| 1322 | return IS_ERR(file->private_data) ? PTR_ERR(file->private_data) : 0; | 1440 | return err; |
| 1323 | |||
| 1324 | } | 1441 | } |
| 1325 | 1442 | ||
| 1326 | static int configfs_dir_close(struct inode *inode, struct file *file) | 1443 | static int configfs_dir_close(struct inode *inode, struct file *file) |
| @@ -1491,6 +1608,10 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) | |||
| 1491 | if (err) { | 1608 | if (err) { |
| 1492 | d_delete(dentry); | 1609 | d_delete(dentry); |
| 1493 | dput(dentry); | 1610 | dput(dentry); |
| 1611 | } else { | ||
| 1612 | spin_lock(&configfs_dirent_lock); | ||
| 1613 | configfs_dir_set_ready(dentry->d_fsdata); | ||
| 1614 | spin_unlock(&configfs_dirent_lock); | ||
| 1494 | } | 1615 | } |
| 1495 | } | 1616 | } |
| 1496 | 1617 | ||
| @@ -1517,11 +1638,13 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) | |||
| 1517 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, | 1638 | mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, |
| 1518 | I_MUTEX_PARENT); | 1639 | I_MUTEX_PARENT); |
| 1519 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); | 1640 | mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); |
| 1641 | mutex_lock(&configfs_symlink_mutex); | ||
| 1520 | spin_lock(&configfs_dirent_lock); | 1642 | spin_lock(&configfs_dirent_lock); |
| 1521 | if (configfs_detach_prep(dentry, NULL)) { | 1643 | if (configfs_detach_prep(dentry, NULL)) { |
| 1522 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); | 1644 | printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); |
| 1523 | } | 1645 | } |
| 1524 | spin_unlock(&configfs_dirent_lock); | 1646 | spin_unlock(&configfs_dirent_lock); |
| 1647 | mutex_unlock(&configfs_symlink_mutex); | ||
| 1525 | configfs_detach_group(&group->cg_item); | 1648 | configfs_detach_group(&group->cg_item); |
| 1526 | dentry->d_inode->i_flags |= S_DEAD; | 1649 | dentry->d_inode->i_flags |= S_DEAD; |
| 1527 | mutex_unlock(&dentry->d_inode->i_mutex); | 1650 | mutex_unlock(&dentry->d_inode->i_mutex); |
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index 0004d18c40ac..bf74973b0492 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c | |||
| @@ -31,6 +31,9 @@ | |||
| 31 | #include <linux/configfs.h> | 31 | #include <linux/configfs.h> |
| 32 | #include "configfs_internal.h" | 32 | #include "configfs_internal.h" |
| 33 | 33 | ||
| 34 | /* Protects attachments of new symlinks */ | ||
| 35 | DEFINE_MUTEX(configfs_symlink_mutex); | ||
| 36 | |||
| 34 | static int item_depth(struct config_item * item) | 37 | static int item_depth(struct config_item * item) |
| 35 | { | 38 | { |
| 36 | struct config_item * p = item; | 39 | struct config_item * p = item; |
| @@ -73,11 +76,20 @@ static int create_link(struct config_item *parent_item, | |||
| 73 | struct configfs_symlink *sl; | 76 | struct configfs_symlink *sl; |
| 74 | int ret; | 77 | int ret; |
| 75 | 78 | ||
| 79 | ret = -ENOENT; | ||
| 80 | if (!configfs_dirent_is_ready(target_sd)) | ||
| 81 | goto out; | ||
| 76 | ret = -ENOMEM; | 82 | ret = -ENOMEM; |
| 77 | sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); | 83 | sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); |
| 78 | if (sl) { | 84 | if (sl) { |
| 79 | sl->sl_target = config_item_get(item); | 85 | sl->sl_target = config_item_get(item); |
| 80 | spin_lock(&configfs_dirent_lock); | 86 | spin_lock(&configfs_dirent_lock); |
| 87 | if (target_sd->s_type & CONFIGFS_USET_DROPPING) { | ||
| 88 | spin_unlock(&configfs_dirent_lock); | ||
| 89 | config_item_put(item); | ||
| 90 | kfree(sl); | ||
| 91 | return -ENOENT; | ||
| 92 | } | ||
| 81 | list_add(&sl->sl_list, &target_sd->s_links); | 93 | list_add(&sl->sl_list, &target_sd->s_links); |
| 82 | spin_unlock(&configfs_dirent_lock); | 94 | spin_unlock(&configfs_dirent_lock); |
| 83 | ret = configfs_create_link(sl, parent_item->ci_dentry, | 95 | ret = configfs_create_link(sl, parent_item->ci_dentry, |
| @@ -91,6 +103,7 @@ static int create_link(struct config_item *parent_item, | |||
| 91 | } | 103 | } |
| 92 | } | 104 | } |
| 93 | 105 | ||
| 106 | out: | ||
| 94 | return ret; | 107 | return ret; |
| 95 | } | 108 | } |
| 96 | 109 | ||
| @@ -120,6 +133,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna | |||
| 120 | { | 133 | { |
| 121 | int ret; | 134 | int ret; |
| 122 | struct nameidata nd; | 135 | struct nameidata nd; |
| 136 | struct configfs_dirent *sd; | ||
| 123 | struct config_item *parent_item; | 137 | struct config_item *parent_item; |
| 124 | struct config_item *target_item; | 138 | struct config_item *target_item; |
| 125 | struct config_item_type *type; | 139 | struct config_item_type *type; |
| @@ -128,9 +142,19 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna | |||
| 128 | if (dentry->d_parent == configfs_sb->s_root) | 142 | if (dentry->d_parent == configfs_sb->s_root) |
| 129 | goto out; | 143 | goto out; |
| 130 | 144 | ||
| 145 | sd = dentry->d_parent->d_fsdata; | ||
| 146 | /* | ||
| 147 | * Fake invisibility if dir belongs to a group/default groups hierarchy | ||
| 148 | * being attached | ||
| 149 | */ | ||
| 150 | ret = -ENOENT; | ||
| 151 | if (!configfs_dirent_is_ready(sd)) | ||
| 152 | goto out; | ||
| 153 | |||
| 131 | parent_item = configfs_get_config_item(dentry->d_parent); | 154 | parent_item = configfs_get_config_item(dentry->d_parent); |
| 132 | type = parent_item->ci_type; | 155 | type = parent_item->ci_type; |
| 133 | 156 | ||
| 157 | ret = -EPERM; | ||
| 134 | if (!type || !type->ct_item_ops || | 158 | if (!type || !type->ct_item_ops || |
| 135 | !type->ct_item_ops->allow_link) | 159 | !type->ct_item_ops->allow_link) |
| 136 | goto out_put; | 160 | goto out_put; |
| @@ -141,7 +165,9 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna | |||
| 141 | 165 | ||
| 142 | ret = type->ct_item_ops->allow_link(parent_item, target_item); | 166 | ret = type->ct_item_ops->allow_link(parent_item, target_item); |
| 143 | if (!ret) { | 167 | if (!ret) { |
| 168 | mutex_lock(&configfs_symlink_mutex); | ||
| 144 | ret = create_link(parent_item, target_item, dentry); | 169 | ret = create_link(parent_item, target_item, dentry); |
| 170 | mutex_unlock(&configfs_symlink_mutex); | ||
| 145 | if (ret && type->ct_item_ops->drop_link) | 171 | if (ret && type->ct_item_ops->drop_link) |
| 146 | type->ct_item_ops->drop_link(parent_item, | 172 | type->ct_item_ops->drop_link(parent_item, |
| 147 | target_item); | 173 | target_item); |
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 0c3b618c15b3..f40423eb1a14 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c | |||
| @@ -43,58 +43,13 @@ static DEFINE_MUTEX(read_mutex); | |||
| 43 | static int cramfs_iget5_test(struct inode *inode, void *opaque) | 43 | static int cramfs_iget5_test(struct inode *inode, void *opaque) |
| 44 | { | 44 | { |
| 45 | struct cramfs_inode *cramfs_inode = opaque; | 45 | struct cramfs_inode *cramfs_inode = opaque; |
| 46 | 46 | return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1; | |
| 47 | if (inode->i_ino != CRAMINO(cramfs_inode)) | ||
| 48 | return 0; /* does not match */ | ||
| 49 | |||
| 50 | if (inode->i_ino != 1) | ||
| 51 | return 1; | ||
| 52 | |||
| 53 | /* all empty directories, char, block, pipe, and sock, share inode #1 */ | ||
| 54 | |||
| 55 | if ((inode->i_mode != cramfs_inode->mode) || | ||
| 56 | (inode->i_gid != cramfs_inode->gid) || | ||
| 57 | (inode->i_uid != cramfs_inode->uid)) | ||
| 58 | return 0; /* does not match */ | ||
| 59 | |||
| 60 | if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) && | ||
| 61 | (inode->i_rdev != old_decode_dev(cramfs_inode->size))) | ||
| 62 | return 0; /* does not match */ | ||
| 63 | |||
| 64 | return 1; /* matches */ | ||
| 65 | } | 47 | } |
| 66 | 48 | ||
| 67 | static int cramfs_iget5_set(struct inode *inode, void *opaque) | 49 | static int cramfs_iget5_set(struct inode *inode, void *opaque) |
| 68 | { | 50 | { |
| 69 | static struct timespec zerotime; | ||
| 70 | struct cramfs_inode *cramfs_inode = opaque; | 51 | struct cramfs_inode *cramfs_inode = opaque; |
| 71 | inode->i_mode = cramfs_inode->mode; | ||
| 72 | inode->i_uid = cramfs_inode->uid; | ||
| 73 | inode->i_size = cramfs_inode->size; | ||
| 74 | inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; | ||
| 75 | inode->i_gid = cramfs_inode->gid; | ||
| 76 | /* Struct copy intentional */ | ||
| 77 | inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; | ||
| 78 | inode->i_ino = CRAMINO(cramfs_inode); | 52 | inode->i_ino = CRAMINO(cramfs_inode); |
| 79 | /* inode->i_nlink is left 1 - arguably wrong for directories, | ||
| 80 | but it's the best we can do without reading the directory | ||
| 81 | contents. 1 yields the right result in GNU find, even | ||
| 82 | without -noleaf option. */ | ||
| 83 | if (S_ISREG(inode->i_mode)) { | ||
| 84 | inode->i_fop = &generic_ro_fops; | ||
| 85 | inode->i_data.a_ops = &cramfs_aops; | ||
| 86 | } else if (S_ISDIR(inode->i_mode)) { | ||
| 87 | inode->i_op = &cramfs_dir_inode_operations; | ||
| 88 | inode->i_fop = &cramfs_directory_operations; | ||
| 89 | } else if (S_ISLNK(inode->i_mode)) { | ||
| 90 | inode->i_op = &page_symlink_inode_operations; | ||
| 91 | inode->i_data.a_ops = &cramfs_aops; | ||
| 92 | } else { | ||
| 93 | inode->i_size = 0; | ||
| 94 | inode->i_blocks = 0; | ||
| 95 | init_special_inode(inode, inode->i_mode, | ||
| 96 | old_decode_dev(cramfs_inode->size)); | ||
| 97 | } | ||
| 98 | return 0; | 53 | return 0; |
| 99 | } | 54 | } |
| 100 | 55 | ||
| @@ -104,12 +59,48 @@ static struct inode *get_cramfs_inode(struct super_block *sb, | |||
| 104 | struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode), | 59 | struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode), |
| 105 | cramfs_iget5_test, cramfs_iget5_set, | 60 | cramfs_iget5_test, cramfs_iget5_set, |
| 106 | cramfs_inode); | 61 | cramfs_inode); |
| 62 | static struct timespec zerotime; | ||
| 63 | |||
| 107 | if (inode && (inode->i_state & I_NEW)) { | 64 | if (inode && (inode->i_state & I_NEW)) { |
| 65 | inode->i_mode = cramfs_inode->mode; | ||
| 66 | inode->i_uid = cramfs_inode->uid; | ||
| 67 | inode->i_size = cramfs_inode->size; | ||
| 68 | inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; | ||
| 69 | inode->i_gid = cramfs_inode->gid; | ||
| 70 | /* Struct copy intentional */ | ||
| 71 | inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; | ||
| 72 | /* inode->i_nlink is left 1 - arguably wrong for directories, | ||
| 73 | but it's the best we can do without reading the directory | ||
| 74 | contents. 1 yields the right result in GNU find, even | ||
| 75 | without -noleaf option. */ | ||
| 76 | if (S_ISREG(inode->i_mode)) { | ||
| 77 | inode->i_fop = &generic_ro_fops; | ||
| 78 | inode->i_data.a_ops = &cramfs_aops; | ||
| 79 | } else if (S_ISDIR(inode->i_mode)) { | ||
| 80 | inode->i_op = &cramfs_dir_inode_operations; | ||
| 81 | inode->i_fop = &cramfs_directory_operations; | ||
| 82 | } else if (S_ISLNK(inode->i_mode)) { | ||
| 83 | inode->i_op = &page_symlink_inode_operations; | ||
| 84 | inode->i_data.a_ops = &cramfs_aops; | ||
| 85 | } else { | ||
| 86 | inode->i_size = 0; | ||
| 87 | inode->i_blocks = 0; | ||
| 88 | init_special_inode(inode, inode->i_mode, | ||
| 89 | old_decode_dev(cramfs_inode->size)); | ||
| 90 | } | ||
| 108 | unlock_new_inode(inode); | 91 | unlock_new_inode(inode); |
| 109 | } | 92 | } |
| 110 | return inode; | 93 | return inode; |
| 111 | } | 94 | } |
| 112 | 95 | ||
| 96 | static void cramfs_drop_inode(struct inode *inode) | ||
| 97 | { | ||
| 98 | if (inode->i_ino == 1) | ||
| 99 | generic_delete_inode(inode); | ||
| 100 | else | ||
| 101 | generic_drop_inode(inode); | ||
| 102 | } | ||
| 103 | |||
| 113 | /* | 104 | /* |
| 114 | * We have our own block cache: don't fill up the buffer cache | 105 | * We have our own block cache: don't fill up the buffer cache |
| 115 | * with the rom-image, because the way the filesystem is set | 106 | * with the rom-image, because the way the filesystem is set |
| @@ -534,6 +525,7 @@ static const struct super_operations cramfs_ops = { | |||
| 534 | .put_super = cramfs_put_super, | 525 | .put_super = cramfs_put_super, |
| 535 | .remount_fs = cramfs_remount, | 526 | .remount_fs = cramfs_remount, |
| 536 | .statfs = cramfs_statfs, | 527 | .statfs = cramfs_statfs, |
| 528 | .drop_inode = cramfs_drop_inode, | ||
| 537 | }; | 529 | }; |
| 538 | 530 | ||
| 539 | static int cramfs_get_sb(struct file_system_type *fs_type, | 531 | static int cramfs_get_sb(struct file_system_type *fs_type, |
diff --git a/fs/dcache.c b/fs/dcache.c index 3818d6ab76ca..80e93956aced 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -487,6 +487,7 @@ restart: | |||
| 487 | if (!cnt) | 487 | if (!cnt) |
| 488 | break; | 488 | break; |
| 489 | } | 489 | } |
| 490 | cond_resched_lock(&dcache_lock); | ||
| 490 | } | 491 | } |
| 491 | } | 492 | } |
| 492 | while (!list_empty(&tmp)) { | 493 | while (!list_empty(&tmp)) { |
| @@ -1219,6 +1220,107 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
| 1219 | return new; | 1220 | return new; |
| 1220 | } | 1221 | } |
| 1221 | 1222 | ||
| 1223 | /** | ||
| 1224 | * d_add_ci - lookup or allocate new dentry with case-exact name | ||
| 1225 | * @inode: the inode case-insensitive lookup has found | ||
| 1226 | * @dentry: the negative dentry that was passed to the parent's lookup func | ||
| 1227 | * @name: the case-exact name to be associated with the returned dentry | ||
| 1228 | * | ||
| 1229 | * This is to avoid filling the dcache with case-insensitive names to the | ||
| 1230 | * same inode, only the actual correct case is stored in the dcache for | ||
| 1231 | * case-insensitive filesystems. | ||
| 1232 | * | ||
| 1233 | * For a case-insensitive lookup match and if the the case-exact dentry | ||
| 1234 | * already exists in in the dcache, use it and return it. | ||
| 1235 | * | ||
| 1236 | * If no entry exists with the exact case name, allocate new dentry with | ||
| 1237 | * the exact case, and return the spliced entry. | ||
| 1238 | */ | ||
| 1239 | struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | ||
| 1240 | struct qstr *name) | ||
| 1241 | { | ||
| 1242 | int error; | ||
| 1243 | struct dentry *found; | ||
| 1244 | struct dentry *new; | ||
| 1245 | |||
| 1246 | /* Does a dentry matching the name exist already? */ | ||
| 1247 | found = d_hash_and_lookup(dentry->d_parent, name); | ||
| 1248 | /* If not, create it now and return */ | ||
| 1249 | if (!found) { | ||
| 1250 | new = d_alloc(dentry->d_parent, name); | ||
| 1251 | if (!new) { | ||
| 1252 | error = -ENOMEM; | ||
| 1253 | goto err_out; | ||
| 1254 | } | ||
| 1255 | found = d_splice_alias(inode, new); | ||
| 1256 | if (found) { | ||
| 1257 | dput(new); | ||
| 1258 | return found; | ||
| 1259 | } | ||
| 1260 | return new; | ||
| 1261 | } | ||
| 1262 | /* Matching dentry exists, check if it is negative. */ | ||
| 1263 | if (found->d_inode) { | ||
| 1264 | if (unlikely(found->d_inode != inode)) { | ||
| 1265 | /* This can't happen because bad inodes are unhashed. */ | ||
| 1266 | BUG_ON(!is_bad_inode(inode)); | ||
| 1267 | BUG_ON(!is_bad_inode(found->d_inode)); | ||
| 1268 | } | ||
| 1269 | /* | ||
| 1270 | * Already have the inode and the dentry attached, decrement | ||
| 1271 | * the reference count to balance the iget() done | ||
| 1272 | * earlier on. We found the dentry using d_lookup() so it | ||
| 1273 | * cannot be disconnected and thus we do not need to worry | ||
| 1274 | * about any NFS/disconnectedness issues here. | ||
| 1275 | */ | ||
| 1276 | iput(inode); | ||
| 1277 | return found; | ||
| 1278 | } | ||
| 1279 | /* | ||
| 1280 | * Negative dentry: instantiate it unless the inode is a directory and | ||
| 1281 | * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED), | ||
| 1282 | * in which case d_move() that in place of the found dentry. | ||
| 1283 | */ | ||
| 1284 | if (!S_ISDIR(inode->i_mode)) { | ||
| 1285 | /* Not a directory; everything is easy. */ | ||
| 1286 | d_instantiate(found, inode); | ||
| 1287 | return found; | ||
| 1288 | } | ||
| 1289 | spin_lock(&dcache_lock); | ||
| 1290 | if (list_empty(&inode->i_dentry)) { | ||
| 1291 | /* | ||
| 1292 | * Directory without a 'disconnected' dentry; we need to do | ||
| 1293 | * d_instantiate() by hand because it takes dcache_lock which | ||
| 1294 | * we already hold. | ||
| 1295 | */ | ||
| 1296 | list_add(&found->d_alias, &inode->i_dentry); | ||
| 1297 | found->d_inode = inode; | ||
| 1298 | spin_unlock(&dcache_lock); | ||
| 1299 | security_d_instantiate(found, inode); | ||
| 1300 | return found; | ||
| 1301 | } | ||
| 1302 | /* | ||
| 1303 | * Directory with a 'disconnected' dentry; get a reference to the | ||
| 1304 | * 'disconnected' dentry. | ||
| 1305 | */ | ||
| 1306 | new = list_entry(inode->i_dentry.next, struct dentry, d_alias); | ||
| 1307 | dget_locked(new); | ||
| 1308 | spin_unlock(&dcache_lock); | ||
| 1309 | /* Do security vodoo. */ | ||
| 1310 | security_d_instantiate(found, inode); | ||
| 1311 | /* Move new in place of found. */ | ||
| 1312 | d_move(new, found); | ||
| 1313 | /* Balance the iget() we did above. */ | ||
| 1314 | iput(inode); | ||
| 1315 | /* Throw away found. */ | ||
| 1316 | dput(found); | ||
| 1317 | /* Use new as the actual dentry. */ | ||
| 1318 | return new; | ||
| 1319 | |||
| 1320 | err_out: | ||
| 1321 | iput(inode); | ||
| 1322 | return ERR_PTR(error); | ||
| 1323 | } | ||
| 1222 | 1324 | ||
| 1223 | /** | 1325 | /** |
| 1224 | * d_lookup - search for a dentry | 1326 | * d_lookup - search for a dentry |
| @@ -2253,6 +2355,7 @@ EXPORT_SYMBOL(d_path); | |||
| 2253 | EXPORT_SYMBOL(d_prune_aliases); | 2355 | EXPORT_SYMBOL(d_prune_aliases); |
| 2254 | EXPORT_SYMBOL(d_rehash); | 2356 | EXPORT_SYMBOL(d_rehash); |
| 2255 | EXPORT_SYMBOL(d_splice_alias); | 2357 | EXPORT_SYMBOL(d_splice_alias); |
| 2358 | EXPORT_SYMBOL(d_add_ci); | ||
| 2256 | EXPORT_SYMBOL(d_validate); | 2359 | EXPORT_SYMBOL(d_validate); |
| 2257 | EXPORT_SYMBOL(dget_locked); | 2360 | EXPORT_SYMBOL(dget_locked); |
| 2258 | EXPORT_SYMBOL(dput); | 2361 | EXPORT_SYMBOL(dput); |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 285b64a8b06e..488eb424f662 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | #define DEVPTS_DEFAULT_MODE 0600 | 29 | #define DEVPTS_DEFAULT_MODE 0600 |
| 30 | 30 | ||
| 31 | extern int pty_limit; /* Config limit on Unix98 ptys */ | 31 | extern int pty_limit; /* Config limit on Unix98 ptys */ |
| 32 | static DEFINE_IDR(allocated_ptys); | 32 | static DEFINE_IDA(allocated_ptys); |
| 33 | static DEFINE_MUTEX(allocated_ptys_lock); | 33 | static DEFINE_MUTEX(allocated_ptys_lock); |
| 34 | 34 | ||
| 35 | static struct vfsmount *devpts_mnt; | 35 | static struct vfsmount *devpts_mnt; |
| @@ -180,24 +180,24 @@ static struct dentry *get_node(int num) | |||
| 180 | int devpts_new_index(void) | 180 | int devpts_new_index(void) |
| 181 | { | 181 | { |
| 182 | int index; | 182 | int index; |
| 183 | int idr_ret; | 183 | int ida_ret; |
| 184 | 184 | ||
| 185 | retry: | 185 | retry: |
| 186 | if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { | 186 | if (!ida_pre_get(&allocated_ptys, GFP_KERNEL)) { |
| 187 | return -ENOMEM; | 187 | return -ENOMEM; |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | mutex_lock(&allocated_ptys_lock); | 190 | mutex_lock(&allocated_ptys_lock); |
| 191 | idr_ret = idr_get_new(&allocated_ptys, NULL, &index); | 191 | ida_ret = ida_get_new(&allocated_ptys, &index); |
| 192 | if (idr_ret < 0) { | 192 | if (ida_ret < 0) { |
| 193 | mutex_unlock(&allocated_ptys_lock); | 193 | mutex_unlock(&allocated_ptys_lock); |
| 194 | if (idr_ret == -EAGAIN) | 194 | if (ida_ret == -EAGAIN) |
| 195 | goto retry; | 195 | goto retry; |
| 196 | return -EIO; | 196 | return -EIO; |
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | if (index >= pty_limit) { | 199 | if (index >= pty_limit) { |
| 200 | idr_remove(&allocated_ptys, index); | 200 | ida_remove(&allocated_ptys, index); |
| 201 | mutex_unlock(&allocated_ptys_lock); | 201 | mutex_unlock(&allocated_ptys_lock); |
| 202 | return -EIO; | 202 | return -EIO; |
| 203 | } | 203 | } |
| @@ -208,7 +208,7 @@ retry: | |||
| 208 | void devpts_kill_index(int idx) | 208 | void devpts_kill_index(int idx) |
| 209 | { | 209 | { |
| 210 | mutex_lock(&allocated_ptys_lock); | 210 | mutex_lock(&allocated_ptys_lock); |
| 211 | idr_remove(&allocated_ptys, idx); | 211 | ida_remove(&allocated_ptys, idx); |
| 212 | mutex_unlock(&allocated_ptys_lock); | 212 | mutex_unlock(&allocated_ptys_lock); |
| 213 | } | 213 | } |
| 214 | 214 | ||
diff --git a/fs/direct-io.c b/fs/direct-io.c index 9e81addbd6ea..9606ee848fd8 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
| @@ -150,17 +150,11 @@ static int dio_refill_pages(struct dio *dio) | |||
| 150 | int nr_pages; | 150 | int nr_pages; |
| 151 | 151 | ||
| 152 | nr_pages = min(dio->total_pages - dio->curr_page, DIO_PAGES); | 152 | nr_pages = min(dio->total_pages - dio->curr_page, DIO_PAGES); |
| 153 | down_read(¤t->mm->mmap_sem); | 153 | ret = get_user_pages_fast( |
| 154 | ret = get_user_pages( | ||
| 155 | current, /* Task for fault acounting */ | ||
| 156 | current->mm, /* whose pages? */ | ||
| 157 | dio->curr_user_address, /* Where from? */ | 154 | dio->curr_user_address, /* Where from? */ |
| 158 | nr_pages, /* How many pages? */ | 155 | nr_pages, /* How many pages? */ |
| 159 | dio->rw == READ, /* Write to memory? */ | 156 | dio->rw == READ, /* Write to memory? */ |
| 160 | 0, /* force (?) */ | 157 | &dio->pages[0]); /* Put results here */ |
| 161 | &dio->pages[0], | ||
| 162 | NULL); /* vmas */ | ||
| 163 | up_read(¤t->mm->mmap_sem); | ||
| 164 | 158 | ||
| 165 | if (ret < 0 && dio->blocks_available && (dio->rw & WRITE)) { | 159 | if (ret < 0 && dio->blocks_available && (dio->rw & WRITE)) { |
| 166 | struct page *page = ZERO_PAGE(0); | 160 | struct page *page = ZERO_PAGE(0); |
diff --git a/fs/dlm/config.c b/fs/dlm/config.c index c4e7d721bd8d..89d2fb7b991a 100644 --- a/fs/dlm/config.c +++ b/fs/dlm/config.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | ******************************************************************************* | 2 | ******************************************************************************* |
| 3 | ** | 3 | ** |
| 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | 4 | ** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
| 5 | ** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | 5 | ** Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved. |
| 6 | ** | 6 | ** |
| 7 | ** This copyrighted material is made available to anyone wishing to use, | 7 | ** This copyrighted material is made available to anyone wishing to use, |
| 8 | ** modify, copy, or redistribute it subject to the terms and conditions | 8 | ** modify, copy, or redistribute it subject to the terms and conditions |
| @@ -30,16 +30,16 @@ | |||
| 30 | 30 | ||
| 31 | static struct config_group *space_list; | 31 | static struct config_group *space_list; |
| 32 | static struct config_group *comm_list; | 32 | static struct config_group *comm_list; |
| 33 | static struct comm *local_comm; | 33 | static struct dlm_comm *local_comm; |
| 34 | 34 | ||
| 35 | struct clusters; | 35 | struct dlm_clusters; |
| 36 | struct cluster; | 36 | struct dlm_cluster; |
| 37 | struct spaces; | 37 | struct dlm_spaces; |
| 38 | struct space; | 38 | struct dlm_space; |
| 39 | struct comms; | 39 | struct dlm_comms; |
| 40 | struct comm; | 40 | struct dlm_comm; |
| 41 | struct nodes; | 41 | struct dlm_nodes; |
| 42 | struct node; | 42 | struct dlm_node; |
| 43 | 43 | ||
| 44 | static struct config_group *make_cluster(struct config_group *, const char *); | 44 | static struct config_group *make_cluster(struct config_group *, const char *); |
| 45 | static void drop_cluster(struct config_group *, struct config_item *); | 45 | static void drop_cluster(struct config_group *, struct config_item *); |
| @@ -68,17 +68,22 @@ static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, | |||
| 68 | static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, | 68 | static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, |
| 69 | const char *buf, size_t len); | 69 | const char *buf, size_t len); |
| 70 | 70 | ||
| 71 | static ssize_t comm_nodeid_read(struct comm *cm, char *buf); | 71 | static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf); |
| 72 | static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len); | 72 | static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf, |
| 73 | static ssize_t comm_local_read(struct comm *cm, char *buf); | 73 | size_t len); |
| 74 | static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len); | 74 | static ssize_t comm_local_read(struct dlm_comm *cm, char *buf); |
| 75 | static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len); | 75 | static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf, |
| 76 | static ssize_t node_nodeid_read(struct node *nd, char *buf); | 76 | size_t len); |
| 77 | static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len); | 77 | static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, |
| 78 | static ssize_t node_weight_read(struct node *nd, char *buf); | 78 | size_t len); |
| 79 | static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len); | 79 | static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf); |
| 80 | 80 | static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf, | |
| 81 | struct cluster { | 81 | size_t len); |
| 82 | static ssize_t node_weight_read(struct dlm_node *nd, char *buf); | ||
| 83 | static ssize_t node_weight_write(struct dlm_node *nd, const char *buf, | ||
| 84 | size_t len); | ||
| 85 | |||
| 86 | struct dlm_cluster { | ||
| 82 | struct config_group group; | 87 | struct config_group group; |
| 83 | unsigned int cl_tcp_port; | 88 | unsigned int cl_tcp_port; |
| 84 | unsigned int cl_buffer_size; | 89 | unsigned int cl_buffer_size; |
| @@ -109,11 +114,11 @@ enum { | |||
| 109 | 114 | ||
| 110 | struct cluster_attribute { | 115 | struct cluster_attribute { |
| 111 | struct configfs_attribute attr; | 116 | struct configfs_attribute attr; |
| 112 | ssize_t (*show)(struct cluster *, char *); | 117 | ssize_t (*show)(struct dlm_cluster *, char *); |
| 113 | ssize_t (*store)(struct cluster *, const char *, size_t); | 118 | ssize_t (*store)(struct dlm_cluster *, const char *, size_t); |
| 114 | }; | 119 | }; |
| 115 | 120 | ||
| 116 | static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, | 121 | static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field, |
| 117 | int *info_field, int check_zero, | 122 | int *info_field, int check_zero, |
| 118 | const char *buf, size_t len) | 123 | const char *buf, size_t len) |
| 119 | { | 124 | { |
| @@ -134,12 +139,12 @@ static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field, | |||
| 134 | } | 139 | } |
| 135 | 140 | ||
| 136 | #define CLUSTER_ATTR(name, check_zero) \ | 141 | #define CLUSTER_ATTR(name, check_zero) \ |
| 137 | static ssize_t name##_write(struct cluster *cl, const char *buf, size_t len) \ | 142 | static ssize_t name##_write(struct dlm_cluster *cl, const char *buf, size_t len) \ |
| 138 | { \ | 143 | { \ |
| 139 | return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \ | 144 | return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \ |
| 140 | check_zero, buf, len); \ | 145 | check_zero, buf, len); \ |
| 141 | } \ | 146 | } \ |
| 142 | static ssize_t name##_read(struct cluster *cl, char *buf) \ | 147 | static ssize_t name##_read(struct dlm_cluster *cl, char *buf) \ |
| 143 | { \ | 148 | { \ |
| 144 | return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name); \ | 149 | return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name); \ |
| 145 | } \ | 150 | } \ |
| @@ -181,8 +186,8 @@ enum { | |||
| 181 | 186 | ||
| 182 | struct comm_attribute { | 187 | struct comm_attribute { |
| 183 | struct configfs_attribute attr; | 188 | struct configfs_attribute attr; |
| 184 | ssize_t (*show)(struct comm *, char *); | 189 | ssize_t (*show)(struct dlm_comm *, char *); |
| 185 | ssize_t (*store)(struct comm *, const char *, size_t); | 190 | ssize_t (*store)(struct dlm_comm *, const char *, size_t); |
| 186 | }; | 191 | }; |
| 187 | 192 | ||
| 188 | static struct comm_attribute comm_attr_nodeid = { | 193 | static struct comm_attribute comm_attr_nodeid = { |
| @@ -222,8 +227,8 @@ enum { | |||
| 222 | 227 | ||
| 223 | struct node_attribute { | 228 | struct node_attribute { |
| 224 | struct configfs_attribute attr; | 229 | struct configfs_attribute attr; |
| 225 | ssize_t (*show)(struct node *, char *); | 230 | ssize_t (*show)(struct dlm_node *, char *); |
| 226 | ssize_t (*store)(struct node *, const char *, size_t); | 231 | ssize_t (*store)(struct dlm_node *, const char *, size_t); |
| 227 | }; | 232 | }; |
| 228 | 233 | ||
| 229 | static struct node_attribute node_attr_nodeid = { | 234 | static struct node_attribute node_attr_nodeid = { |
| @@ -248,26 +253,26 @@ static struct configfs_attribute *node_attrs[] = { | |||
| 248 | NULL, | 253 | NULL, |
| 249 | }; | 254 | }; |
| 250 | 255 | ||
| 251 | struct clusters { | 256 | struct dlm_clusters { |
| 252 | struct configfs_subsystem subsys; | 257 | struct configfs_subsystem subsys; |
| 253 | }; | 258 | }; |
| 254 | 259 | ||
| 255 | struct spaces { | 260 | struct dlm_spaces { |
| 256 | struct config_group ss_group; | 261 | struct config_group ss_group; |
| 257 | }; | 262 | }; |
| 258 | 263 | ||
| 259 | struct space { | 264 | struct dlm_space { |
| 260 | struct config_group group; | 265 | struct config_group group; |
| 261 | struct list_head members; | 266 | struct list_head members; |
| 262 | struct mutex members_lock; | 267 | struct mutex members_lock; |
| 263 | int members_count; | 268 | int members_count; |
| 264 | }; | 269 | }; |
| 265 | 270 | ||
| 266 | struct comms { | 271 | struct dlm_comms { |
| 267 | struct config_group cs_group; | 272 | struct config_group cs_group; |
| 268 | }; | 273 | }; |
| 269 | 274 | ||
| 270 | struct comm { | 275 | struct dlm_comm { |
| 271 | struct config_item item; | 276 | struct config_item item; |
| 272 | int nodeid; | 277 | int nodeid; |
| 273 | int local; | 278 | int local; |
| @@ -275,11 +280,11 @@ struct comm { | |||
| 275 | struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT]; | 280 | struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT]; |
| 276 | }; | 281 | }; |
| 277 | 282 | ||
| 278 | struct nodes { | 283 | struct dlm_nodes { |
| 279 | struct config_group ns_group; | 284 | struct config_group ns_group; |
| 280 | }; | 285 | }; |
| 281 | 286 | ||
| 282 | struct node { | 287 | struct dlm_node { |
| 283 | struct config_item item; | 288 | struct config_item item; |
| 284 | struct list_head list; /* space->members */ | 289 | struct list_head list; /* space->members */ |
| 285 | int nodeid; | 290 | int nodeid; |
| @@ -372,38 +377,40 @@ static struct config_item_type node_type = { | |||
| 372 | .ct_owner = THIS_MODULE, | 377 | .ct_owner = THIS_MODULE, |
| 373 | }; | 378 | }; |
| 374 | 379 | ||
| 375 | static struct cluster *to_cluster(struct config_item *i) | 380 | static struct dlm_cluster *to_cluster(struct config_item *i) |
| 376 | { | 381 | { |
| 377 | return i ? container_of(to_config_group(i), struct cluster, group):NULL; | 382 | return i ? container_of(to_config_group(i), struct dlm_cluster, group) : |
| 383 | NULL; | ||
| 378 | } | 384 | } |
| 379 | 385 | ||
| 380 | static struct space *to_space(struct config_item *i) | 386 | static struct dlm_space *to_space(struct config_item *i) |
| 381 | { | 387 | { |
| 382 | return i ? container_of(to_config_group(i), struct space, group) : NULL; | 388 | return i ? container_of(to_config_group(i), struct dlm_space, group) : |
| 389 | NULL; | ||
| 383 | } | 390 | } |
| 384 | 391 | ||
| 385 | static struct comm *to_comm(struct config_item *i) | 392 | static struct dlm_comm *to_comm(struct config_item *i) |
| 386 | { | 393 | { |
| 387 | return i ? container_of(i, struct comm, item) : NULL; | 394 | return i ? container_of(i, struct dlm_comm, item) : NULL; |
| 388 | } | 395 | } |
| 389 | 396 | ||
| 390 | static struct node *to_node(struct config_item *i) | 397 | static struct dlm_node *to_node(struct config_item *i) |
| 391 | { | 398 | { |
| 392 | return i ? container_of(i, struct node, item) : NULL; | 399 | return i ? container_of(i, struct dlm_node, item) : NULL; |
| 393 | } | 400 | } |
| 394 | 401 | ||
| 395 | static struct config_group *make_cluster(struct config_group *g, | 402 | static struct config_group *make_cluster(struct config_group *g, |
| 396 | const char *name) | 403 | const char *name) |
| 397 | { | 404 | { |
| 398 | struct cluster *cl = NULL; | 405 | struct dlm_cluster *cl = NULL; |
| 399 | struct spaces *sps = NULL; | 406 | struct dlm_spaces *sps = NULL; |
| 400 | struct comms *cms = NULL; | 407 | struct dlm_comms *cms = NULL; |
| 401 | void *gps = NULL; | 408 | void *gps = NULL; |
| 402 | 409 | ||
| 403 | cl = kzalloc(sizeof(struct cluster), GFP_KERNEL); | 410 | cl = kzalloc(sizeof(struct dlm_cluster), GFP_KERNEL); |
| 404 | gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL); | 411 | gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL); |
| 405 | sps = kzalloc(sizeof(struct spaces), GFP_KERNEL); | 412 | sps = kzalloc(sizeof(struct dlm_spaces), GFP_KERNEL); |
| 406 | cms = kzalloc(sizeof(struct comms), GFP_KERNEL); | 413 | cms = kzalloc(sizeof(struct dlm_comms), GFP_KERNEL); |
| 407 | 414 | ||
| 408 | if (!cl || !gps || !sps || !cms) | 415 | if (!cl || !gps || !sps || !cms) |
| 409 | goto fail; | 416 | goto fail; |
| @@ -443,7 +450,7 @@ static struct config_group *make_cluster(struct config_group *g, | |||
| 443 | 450 | ||
| 444 | static void drop_cluster(struct config_group *g, struct config_item *i) | 451 | static void drop_cluster(struct config_group *g, struct config_item *i) |
| 445 | { | 452 | { |
| 446 | struct cluster *cl = to_cluster(i); | 453 | struct dlm_cluster *cl = to_cluster(i); |
| 447 | struct config_item *tmp; | 454 | struct config_item *tmp; |
| 448 | int j; | 455 | int j; |
| 449 | 456 | ||
| @@ -461,20 +468,20 @@ static void drop_cluster(struct config_group *g, struct config_item *i) | |||
| 461 | 468 | ||
| 462 | static void release_cluster(struct config_item *i) | 469 | static void release_cluster(struct config_item *i) |
| 463 | { | 470 | { |
| 464 | struct cluster *cl = to_cluster(i); | 471 | struct dlm_cluster *cl = to_cluster(i); |
| 465 | kfree(cl->group.default_groups); | 472 | kfree(cl->group.default_groups); |
| 466 | kfree(cl); | 473 | kfree(cl); |
| 467 | } | 474 | } |
| 468 | 475 | ||
| 469 | static struct config_group *make_space(struct config_group *g, const char *name) | 476 | static struct config_group *make_space(struct config_group *g, const char *name) |
| 470 | { | 477 | { |
| 471 | struct space *sp = NULL; | 478 | struct dlm_space *sp = NULL; |
| 472 | struct nodes *nds = NULL; | 479 | struct dlm_nodes *nds = NULL; |
| 473 | void *gps = NULL; | 480 | void *gps = NULL; |
| 474 | 481 | ||
| 475 | sp = kzalloc(sizeof(struct space), GFP_KERNEL); | 482 | sp = kzalloc(sizeof(struct dlm_space), GFP_KERNEL); |
| 476 | gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL); | 483 | gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL); |
| 477 | nds = kzalloc(sizeof(struct nodes), GFP_KERNEL); | 484 | nds = kzalloc(sizeof(struct dlm_nodes), GFP_KERNEL); |
| 478 | 485 | ||
| 479 | if (!sp || !gps || !nds) | 486 | if (!sp || !gps || !nds) |
| 480 | goto fail; | 487 | goto fail; |
| @@ -500,7 +507,7 @@ static struct config_group *make_space(struct config_group *g, const char *name) | |||
| 500 | 507 | ||
| 501 | static void drop_space(struct config_group *g, struct config_item *i) | 508 | static void drop_space(struct config_group *g, struct config_item *i) |
| 502 | { | 509 | { |
| 503 | struct space *sp = to_space(i); | 510 | struct dlm_space *sp = to_space(i); |
| 504 | struct config_item *tmp; | 511 | struct config_item *tmp; |
| 505 | int j; | 512 | int j; |
| 506 | 513 | ||
| @@ -517,16 +524,16 @@ static void drop_space(struct config_group *g, struct config_item *i) | |||
| 517 | 524 | ||
| 518 | static void release_space(struct config_item *i) | 525 | static void release_space(struct config_item *i) |
| 519 | { | 526 | { |
| 520 | struct space *sp = to_space(i); | 527 | struct dlm_space *sp = to_space(i); |
| 521 | kfree(sp->group.default_groups); | 528 | kfree(sp->group.default_groups); |
| 522 | kfree(sp); | 529 | kfree(sp); |
| 523 | } | 530 | } |
| 524 | 531 | ||
| 525 | static struct config_item *make_comm(struct config_group *g, const char *name) | 532 | static struct config_item *make_comm(struct config_group *g, const char *name) |
| 526 | { | 533 | { |
| 527 | struct comm *cm; | 534 | struct dlm_comm *cm; |
| 528 | 535 | ||
| 529 | cm = kzalloc(sizeof(struct comm), GFP_KERNEL); | 536 | cm = kzalloc(sizeof(struct dlm_comm), GFP_KERNEL); |
| 530 | if (!cm) | 537 | if (!cm) |
| 531 | return ERR_PTR(-ENOMEM); | 538 | return ERR_PTR(-ENOMEM); |
| 532 | 539 | ||
| @@ -539,7 +546,7 @@ static struct config_item *make_comm(struct config_group *g, const char *name) | |||
| 539 | 546 | ||
| 540 | static void drop_comm(struct config_group *g, struct config_item *i) | 547 | static void drop_comm(struct config_group *g, struct config_item *i) |
| 541 | { | 548 | { |
| 542 | struct comm *cm = to_comm(i); | 549 | struct dlm_comm *cm = to_comm(i); |
| 543 | if (local_comm == cm) | 550 | if (local_comm == cm) |
| 544 | local_comm = NULL; | 551 | local_comm = NULL; |
| 545 | dlm_lowcomms_close(cm->nodeid); | 552 | dlm_lowcomms_close(cm->nodeid); |
| @@ -550,16 +557,16 @@ static void drop_comm(struct config_group *g, struct config_item *i) | |||
| 550 | 557 | ||
| 551 | static void release_comm(struct config_item *i) | 558 | static void release_comm(struct config_item *i) |
| 552 | { | 559 | { |
| 553 | struct comm *cm = to_comm(i); | 560 | struct dlm_comm *cm = to_comm(i); |
| 554 | kfree(cm); | 561 | kfree(cm); |
| 555 | } | 562 | } |
| 556 | 563 | ||
| 557 | static struct config_item *make_node(struct config_group *g, const char *name) | 564 | static struct config_item *make_node(struct config_group *g, const char *name) |
| 558 | { | 565 | { |
| 559 | struct space *sp = to_space(g->cg_item.ci_parent); | 566 | struct dlm_space *sp = to_space(g->cg_item.ci_parent); |
| 560 | struct node *nd; | 567 | struct dlm_node *nd; |
| 561 | 568 | ||
| 562 | nd = kzalloc(sizeof(struct node), GFP_KERNEL); | 569 | nd = kzalloc(sizeof(struct dlm_node), GFP_KERNEL); |
| 563 | if (!nd) | 570 | if (!nd) |
| 564 | return ERR_PTR(-ENOMEM); | 571 | return ERR_PTR(-ENOMEM); |
| 565 | 572 | ||
| @@ -578,8 +585,8 @@ static struct config_item *make_node(struct config_group *g, const char *name) | |||
| 578 | 585 | ||
| 579 | static void drop_node(struct config_group *g, struct config_item *i) | 586 | static void drop_node(struct config_group *g, struct config_item *i) |
| 580 | { | 587 | { |
| 581 | struct space *sp = to_space(g->cg_item.ci_parent); | 588 | struct dlm_space *sp = to_space(g->cg_item.ci_parent); |
| 582 | struct node *nd = to_node(i); | 589 | struct dlm_node *nd = to_node(i); |
| 583 | 590 | ||
| 584 | mutex_lock(&sp->members_lock); | 591 | mutex_lock(&sp->members_lock); |
| 585 | list_del(&nd->list); | 592 | list_del(&nd->list); |
| @@ -591,11 +598,11 @@ static void drop_node(struct config_group *g, struct config_item *i) | |||
| 591 | 598 | ||
| 592 | static void release_node(struct config_item *i) | 599 | static void release_node(struct config_item *i) |
| 593 | { | 600 | { |
| 594 | struct node *nd = to_node(i); | 601 | struct dlm_node *nd = to_node(i); |
| 595 | kfree(nd); | 602 | kfree(nd); |
| 596 | } | 603 | } |
| 597 | 604 | ||
| 598 | static struct clusters clusters_root = { | 605 | static struct dlm_clusters clusters_root = { |
| 599 | .subsys = { | 606 | .subsys = { |
| 600 | .su_group = { | 607 | .su_group = { |
| 601 | .cg_item = { | 608 | .cg_item = { |
| @@ -625,7 +632,7 @@ void dlm_config_exit(void) | |||
| 625 | static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, | 632 | static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a, |
| 626 | char *buf) | 633 | char *buf) |
| 627 | { | 634 | { |
| 628 | struct cluster *cl = to_cluster(i); | 635 | struct dlm_cluster *cl = to_cluster(i); |
| 629 | struct cluster_attribute *cla = | 636 | struct cluster_attribute *cla = |
| 630 | container_of(a, struct cluster_attribute, attr); | 637 | container_of(a, struct cluster_attribute, attr); |
| 631 | return cla->show ? cla->show(cl, buf) : 0; | 638 | return cla->show ? cla->show(cl, buf) : 0; |
| @@ -635,7 +642,7 @@ static ssize_t store_cluster(struct config_item *i, | |||
| 635 | struct configfs_attribute *a, | 642 | struct configfs_attribute *a, |
| 636 | const char *buf, size_t len) | 643 | const char *buf, size_t len) |
| 637 | { | 644 | { |
| 638 | struct cluster *cl = to_cluster(i); | 645 | struct dlm_cluster *cl = to_cluster(i); |
| 639 | struct cluster_attribute *cla = | 646 | struct cluster_attribute *cla = |
| 640 | container_of(a, struct cluster_attribute, attr); | 647 | container_of(a, struct cluster_attribute, attr); |
| 641 | return cla->store ? cla->store(cl, buf, len) : -EINVAL; | 648 | return cla->store ? cla->store(cl, buf, len) : -EINVAL; |
| @@ -644,7 +651,7 @@ static ssize_t store_cluster(struct config_item *i, | |||
| 644 | static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, | 651 | static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, |
| 645 | char *buf) | 652 | char *buf) |
| 646 | { | 653 | { |
| 647 | struct comm *cm = to_comm(i); | 654 | struct dlm_comm *cm = to_comm(i); |
| 648 | struct comm_attribute *cma = | 655 | struct comm_attribute *cma = |
| 649 | container_of(a, struct comm_attribute, attr); | 656 | container_of(a, struct comm_attribute, attr); |
| 650 | return cma->show ? cma->show(cm, buf) : 0; | 657 | return cma->show ? cma->show(cm, buf) : 0; |
| @@ -653,29 +660,31 @@ static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a, | |||
| 653 | static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, | 660 | static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a, |
| 654 | const char *buf, size_t len) | 661 | const char *buf, size_t len) |
| 655 | { | 662 | { |
| 656 | struct comm *cm = to_comm(i); | 663 | struct dlm_comm *cm = to_comm(i); |
| 657 | struct comm_attribute *cma = | 664 | struct comm_attribute *cma = |
| 658 | container_of(a, struct comm_attribute, attr); | 665 | container_of(a, struct comm_attribute, attr); |
| 659 | return cma->store ? cma->store(cm, buf, len) : -EINVAL; | 666 | return cma->store ? cma->store(cm, buf, len) : -EINVAL; |
| 660 | } | 667 | } |
| 661 | 668 | ||
| 662 | static ssize_t comm_nodeid_read(struct comm *cm, char *buf) | 669 | static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf) |
| 663 | { | 670 | { |
| 664 | return sprintf(buf, "%d\n", cm->nodeid); | 671 | return sprintf(buf, "%d\n", cm->nodeid); |
| 665 | } | 672 | } |
| 666 | 673 | ||
| 667 | static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len) | 674 | static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf, |
| 675 | size_t len) | ||
| 668 | { | 676 | { |
| 669 | cm->nodeid = simple_strtol(buf, NULL, 0); | 677 | cm->nodeid = simple_strtol(buf, NULL, 0); |
| 670 | return len; | 678 | return len; |
| 671 | } | 679 | } |
| 672 | 680 | ||
| 673 | static ssize_t comm_local_read(struct comm *cm, char *buf) | 681 | static ssize_t comm_local_read(struct dlm_comm *cm, char *buf) |
| 674 | { | 682 | { |
| 675 | return sprintf(buf, "%d\n", cm->local); | 683 | return sprintf(buf, "%d\n", cm->local); |
| 676 | } | 684 | } |
| 677 | 685 | ||
| 678 | static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len) | 686 | static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf, |
| 687 | size_t len) | ||
| 679 | { | 688 | { |
| 680 | cm->local= simple_strtol(buf, NULL, 0); | 689 | cm->local= simple_strtol(buf, NULL, 0); |
| 681 | if (cm->local && !local_comm) | 690 | if (cm->local && !local_comm) |
| @@ -683,7 +692,7 @@ static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len) | |||
| 683 | return len; | 692 | return len; |
| 684 | } | 693 | } |
| 685 | 694 | ||
| 686 | static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len) | 695 | static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len) |
| 687 | { | 696 | { |
| 688 | struct sockaddr_storage *addr; | 697 | struct sockaddr_storage *addr; |
| 689 | 698 | ||
| @@ -705,7 +714,7 @@ static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len) | |||
| 705 | static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, | 714 | static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, |
| 706 | char *buf) | 715 | char *buf) |
| 707 | { | 716 | { |
| 708 | struct node *nd = to_node(i); | 717 | struct dlm_node *nd = to_node(i); |
| 709 | struct node_attribute *nda = | 718 | struct node_attribute *nda = |
| 710 | container_of(a, struct node_attribute, attr); | 719 | container_of(a, struct node_attribute, attr); |
| 711 | return nda->show ? nda->show(nd, buf) : 0; | 720 | return nda->show ? nda->show(nd, buf) : 0; |
| @@ -714,29 +723,31 @@ static ssize_t show_node(struct config_item *i, struct configfs_attribute *a, | |||
| 714 | static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, | 723 | static ssize_t store_node(struct config_item *i, struct configfs_attribute *a, |
| 715 | const char *buf, size_t len) | 724 | const char *buf, size_t len) |
| 716 | { | 725 | { |
| 717 | struct node *nd = to_node(i); | 726 | struct dlm_node *nd = to_node(i); |
| 718 | struct node_attribute *nda = | 727 | struct node_attribute *nda = |
| 719 | container_of(a, struct node_attribute, attr); | 728 | container_of(a, struct node_attribute, attr); |
| 720 | return nda->store ? nda->store(nd, buf, len) : -EINVAL; | 729 | return nda->store ? nda->store(nd, buf, len) : -EINVAL; |
| 721 | } | 730 | } |
| 722 | 731 | ||
| 723 | static ssize_t node_nodeid_read(struct node *nd, char *buf) | 732 | static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf) |
| 724 | { | 733 | { |
| 725 | return sprintf(buf, "%d\n", nd->nodeid); | 734 | return sprintf(buf, "%d\n", nd->nodeid); |
| 726 | } | 735 | } |
| 727 | 736 | ||
| 728 | static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len) | 737 | static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf, |
| 738 | size_t len) | ||
| 729 | { | 739 | { |
| 730 | nd->nodeid = simple_strtol(buf, NULL, 0); | 740 | nd->nodeid = simple_strtol(buf, NULL, 0); |
| 731 | return len; | 741 | return len; |
| 732 | } | 742 | } |
| 733 | 743 | ||
| 734 | static ssize_t node_weight_read(struct node *nd, char *buf) | 744 | static ssize_t node_weight_read(struct dlm_node *nd, char *buf) |
| 735 | { | 745 | { |
| 736 | return sprintf(buf, "%d\n", nd->weight); | 746 | return sprintf(buf, "%d\n", nd->weight); |
| 737 | } | 747 | } |
| 738 | 748 | ||
| 739 | static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len) | 749 | static ssize_t node_weight_write(struct dlm_node *nd, const char *buf, |
| 750 | size_t len) | ||
| 740 | { | 751 | { |
| 741 | nd->weight = simple_strtol(buf, NULL, 0); | 752 | nd->weight = simple_strtol(buf, NULL, 0); |
| 742 | return len; | 753 | return len; |
| @@ -746,7 +757,7 @@ static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len) | |||
| 746 | * Functions for the dlm to get the info that's been configured | 757 | * Functions for the dlm to get the info that's been configured |
| 747 | */ | 758 | */ |
| 748 | 759 | ||
| 749 | static struct space *get_space(char *name) | 760 | static struct dlm_space *get_space(char *name) |
| 750 | { | 761 | { |
| 751 | struct config_item *i; | 762 | struct config_item *i; |
| 752 | 763 | ||
| @@ -760,15 +771,15 @@ static struct space *get_space(char *name) | |||
| 760 | return to_space(i); | 771 | return to_space(i); |
| 761 | } | 772 | } |
| 762 | 773 | ||
| 763 | static void put_space(struct space *sp) | 774 | static void put_space(struct dlm_space *sp) |
| 764 | { | 775 | { |
| 765 | config_item_put(&sp->group.cg_item); | 776 | config_item_put(&sp->group.cg_item); |
| 766 | } | 777 | } |
| 767 | 778 | ||
| 768 | static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr) | 779 | static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr) |
| 769 | { | 780 | { |
| 770 | struct config_item *i; | 781 | struct config_item *i; |
| 771 | struct comm *cm = NULL; | 782 | struct dlm_comm *cm = NULL; |
| 772 | int found = 0; | 783 | int found = 0; |
| 773 | 784 | ||
| 774 | if (!comm_list) | 785 | if (!comm_list) |
| @@ -801,7 +812,7 @@ static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr) | |||
| 801 | return cm; | 812 | return cm; |
| 802 | } | 813 | } |
| 803 | 814 | ||
| 804 | static void put_comm(struct comm *cm) | 815 | static void put_comm(struct dlm_comm *cm) |
| 805 | { | 816 | { |
| 806 | config_item_put(&cm->item); | 817 | config_item_put(&cm->item); |
| 807 | } | 818 | } |
| @@ -810,8 +821,8 @@ static void put_comm(struct comm *cm) | |||
| 810 | int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, | 821 | int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, |
| 811 | int **new_out, int *new_count_out) | 822 | int **new_out, int *new_count_out) |
| 812 | { | 823 | { |
| 813 | struct space *sp; | 824 | struct dlm_space *sp; |
| 814 | struct node *nd; | 825 | struct dlm_node *nd; |
| 815 | int i = 0, rv = 0, ids_count = 0, new_count = 0; | 826 | int i = 0, rv = 0, ids_count = 0, new_count = 0; |
| 816 | int *ids, *new; | 827 | int *ids, *new; |
| 817 | 828 | ||
| @@ -874,8 +885,8 @@ int dlm_nodeid_list(char *lsname, int **ids_out, int *ids_count_out, | |||
| 874 | 885 | ||
| 875 | int dlm_node_weight(char *lsname, int nodeid) | 886 | int dlm_node_weight(char *lsname, int nodeid) |
| 876 | { | 887 | { |
| 877 | struct space *sp; | 888 | struct dlm_space *sp; |
| 878 | struct node *nd; | 889 | struct dlm_node *nd; |
| 879 | int w = -EEXIST; | 890 | int w = -EEXIST; |
| 880 | 891 | ||
| 881 | sp = get_space(lsname); | 892 | sp = get_space(lsname); |
| @@ -897,7 +908,7 @@ int dlm_node_weight(char *lsname, int nodeid) | |||
| 897 | 908 | ||
| 898 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr) | 909 | int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr) |
| 899 | { | 910 | { |
| 900 | struct comm *cm = get_comm(nodeid, NULL); | 911 | struct dlm_comm *cm = get_comm(nodeid, NULL); |
| 901 | if (!cm) | 912 | if (!cm) |
| 902 | return -EEXIST; | 913 | return -EEXIST; |
| 903 | if (!cm->addr_count) | 914 | if (!cm->addr_count) |
| @@ -909,7 +920,7 @@ int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr) | |||
| 909 | 920 | ||
| 910 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid) | 921 | int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid) |
| 911 | { | 922 | { |
| 912 | struct comm *cm = get_comm(0, addr); | 923 | struct dlm_comm *cm = get_comm(0, addr); |
| 913 | if (!cm) | 924 | if (!cm) |
| 914 | return -EEXIST; | 925 | return -EEXIST; |
| 915 | *nodeid = cm->nodeid; | 926 | *nodeid = cm->nodeid; |
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 2d3d1027ce2b..724ddac91538 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
| @@ -363,6 +363,7 @@ static int search_rsb_list(struct list_head *head, char *name, int len, | |||
| 363 | if (len == r->res_length && !memcmp(name, r->res_name, len)) | 363 | if (len == r->res_length && !memcmp(name, r->res_name, len)) |
| 364 | goto found; | 364 | goto found; |
| 365 | } | 365 | } |
| 366 | *r_ret = NULL; | ||
| 366 | return -EBADR; | 367 | return -EBADR; |
| 367 | 368 | ||
| 368 | found: | 369 | found: |
| @@ -1782,7 +1783,8 @@ static void grant_pending_locks(struct dlm_rsb *r) | |||
| 1782 | 1783 | ||
| 1783 | list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) { | 1784 | list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) { |
| 1784 | if (lkb->lkb_bastfn && lock_requires_bast(lkb, high, cw)) { | 1785 | if (lkb->lkb_bastfn && lock_requires_bast(lkb, high, cw)) { |
| 1785 | if (cw && high == DLM_LOCK_PR) | 1786 | if (cw && high == DLM_LOCK_PR && |
| 1787 | lkb->lkb_grmode == DLM_LOCK_PR) | ||
| 1786 | queue_bast(r, lkb, DLM_LOCK_CW); | 1788 | queue_bast(r, lkb, DLM_LOCK_CW); |
| 1787 | else | 1789 | else |
| 1788 | queue_bast(r, lkb, high); | 1790 | queue_bast(r, lkb, high); |
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 637018c891ef..3962262f991a 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
| @@ -891,8 +891,10 @@ static void tcp_connect_to_sock(struct connection *con) | |||
| 891 | goto out_err; | 891 | goto out_err; |
| 892 | 892 | ||
| 893 | memset(&saddr, 0, sizeof(saddr)); | 893 | memset(&saddr, 0, sizeof(saddr)); |
| 894 | if (dlm_nodeid_to_addr(con->nodeid, &saddr)) | 894 | if (dlm_nodeid_to_addr(con->nodeid, &saddr)) { |
| 895 | sock_release(sock); | ||
| 895 | goto out_err; | 896 | goto out_err; |
| 897 | } | ||
| 896 | 898 | ||
| 897 | sock->sk->sk_user_data = con; | 899 | sock->sk->sk_user_data = con; |
| 898 | con->rx_action = receive_from_sock; | 900 | con->rx_action = receive_from_sock; |
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 78878c5781ca..eba87ff3177b 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c | |||
| @@ -116,7 +116,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, | |||
| 116 | if (xop->callback == NULL) | 116 | if (xop->callback == NULL) |
| 117 | wait_event(recv_wq, (op->done != 0)); | 117 | wait_event(recv_wq, (op->done != 0)); |
| 118 | else { | 118 | else { |
| 119 | rv = -EINPROGRESS; | 119 | rv = FILE_LOCK_DEFERRED; |
| 120 | goto out; | 120 | goto out; |
| 121 | } | 121 | } |
| 122 | 122 | ||
diff --git a/fs/dlm/user.c b/fs/dlm/user.c index f976f303c196..34f14a14fb4e 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c | |||
| @@ -527,8 +527,10 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |||
| 527 | k32buf = (struct dlm_write_request32 *)kbuf; | 527 | k32buf = (struct dlm_write_request32 *)kbuf; |
| 528 | kbuf = kmalloc(count + 1 + (sizeof(struct dlm_write_request) - | 528 | kbuf = kmalloc(count + 1 + (sizeof(struct dlm_write_request) - |
| 529 | sizeof(struct dlm_write_request32)), GFP_KERNEL); | 529 | sizeof(struct dlm_write_request32)), GFP_KERNEL); |
| 530 | if (!kbuf) | 530 | if (!kbuf) { |
| 531 | kfree(k32buf); | ||
| 531 | return -ENOMEM; | 532 | return -ENOMEM; |
| 533 | } | ||
| 532 | 534 | ||
| 533 | if (proc) | 535 | if (proc) |
| 534 | set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); | 536 | set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags); |
| @@ -539,8 +541,10 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |||
| 539 | 541 | ||
| 540 | /* do we really need this? can a write happen after a close? */ | 542 | /* do we really need this? can a write happen after a close? */ |
| 541 | if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) && | 543 | if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) && |
| 542 | test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags)) | 544 | (proc && test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))) { |
| 543 | return -EINVAL; | 545 | error = -EINVAL; |
| 546 | goto out_free; | ||
| 547 | } | ||
| 544 | 548 | ||
| 545 | sigfillset(&allsigs); | 549 | sigfillset(&allsigs); |
| 546 | sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); | 550 | sigprocmask(SIG_BLOCK, &allsigs, &tmpsig); |
diff --git a/fs/dquot.c b/fs/dquot.c index 5ac77da19959..8ec4d6cc7633 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
| @@ -562,6 +562,8 @@ static struct shrinker dqcache_shrinker = { | |||
| 562 | */ | 562 | */ |
| 563 | static void dqput(struct dquot *dquot) | 563 | static void dqput(struct dquot *dquot) |
| 564 | { | 564 | { |
| 565 | int ret; | ||
| 566 | |||
| 565 | if (!dquot) | 567 | if (!dquot) |
| 566 | return; | 568 | return; |
| 567 | #ifdef __DQUOT_PARANOIA | 569 | #ifdef __DQUOT_PARANOIA |
| @@ -594,7 +596,19 @@ we_slept: | |||
| 594 | if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_dirty(dquot)) { | 596 | if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_dirty(dquot)) { |
| 595 | spin_unlock(&dq_list_lock); | 597 | spin_unlock(&dq_list_lock); |
| 596 | /* Commit dquot before releasing */ | 598 | /* Commit dquot before releasing */ |
| 597 | dquot->dq_sb->dq_op->write_dquot(dquot); | 599 | ret = dquot->dq_sb->dq_op->write_dquot(dquot); |
| 600 | if (ret < 0) { | ||
| 601 | printk(KERN_ERR "VFS: cannot write quota structure on " | ||
| 602 | "device %s (error %d). Quota may get out of " | ||
| 603 | "sync!\n", dquot->dq_sb->s_id, ret); | ||
| 604 | /* | ||
| 605 | * We clear dirty bit anyway, so that we avoid | ||
| 606 | * infinite loop here | ||
| 607 | */ | ||
| 608 | spin_lock(&dq_list_lock); | ||
| 609 | clear_dquot_dirty(dquot); | ||
| 610 | spin_unlock(&dq_list_lock); | ||
| 611 | } | ||
| 598 | goto we_slept; | 612 | goto we_slept; |
| 599 | } | 613 | } |
| 600 | /* Clear flag in case dquot was inactive (something bad happened) */ | 614 | /* Clear flag in case dquot was inactive (something bad happened) */ |
| @@ -875,7 +889,10 @@ static void print_warning(struct dquot *dquot, const int warntype) | |||
| 875 | char *msg = NULL; | 889 | char *msg = NULL; |
| 876 | struct tty_struct *tty; | 890 | struct tty_struct *tty; |
| 877 | 891 | ||
| 878 | if (!need_print_warning(dquot)) | 892 | if (warntype == QUOTA_NL_IHARDBELOW || |
| 893 | warntype == QUOTA_NL_ISOFTBELOW || | ||
| 894 | warntype == QUOTA_NL_BHARDBELOW || | ||
| 895 | warntype == QUOTA_NL_BSOFTBELOW || !need_print_warning(dquot)) | ||
| 879 | return; | 896 | return; |
| 880 | 897 | ||
| 881 | mutex_lock(&tty_mutex); | 898 | mutex_lock(&tty_mutex); |
| @@ -1083,6 +1100,35 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war | |||
| 1083 | return QUOTA_OK; | 1100 | return QUOTA_OK; |
| 1084 | } | 1101 | } |
| 1085 | 1102 | ||
| 1103 | static int info_idq_free(struct dquot *dquot, ulong inodes) | ||
| 1104 | { | ||
| 1105 | if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || | ||
| 1106 | dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) | ||
| 1107 | return QUOTA_NL_NOWARN; | ||
| 1108 | |||
| 1109 | if (dquot->dq_dqb.dqb_curinodes - inodes <= dquot->dq_dqb.dqb_isoftlimit) | ||
| 1110 | return QUOTA_NL_ISOFTBELOW; | ||
| 1111 | if (dquot->dq_dqb.dqb_curinodes >= dquot->dq_dqb.dqb_ihardlimit && | ||
| 1112 | dquot->dq_dqb.dqb_curinodes - inodes < dquot->dq_dqb.dqb_ihardlimit) | ||
| 1113 | return QUOTA_NL_IHARDBELOW; | ||
| 1114 | return QUOTA_NL_NOWARN; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | static int info_bdq_free(struct dquot *dquot, qsize_t space) | ||
| 1118 | { | ||
| 1119 | if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || | ||
| 1120 | toqb(dquot->dq_dqb.dqb_curspace) <= dquot->dq_dqb.dqb_bsoftlimit) | ||
| 1121 | return QUOTA_NL_NOWARN; | ||
| 1122 | |||
| 1123 | if (toqb(dquot->dq_dqb.dqb_curspace - space) <= | ||
| 1124 | dquot->dq_dqb.dqb_bsoftlimit) | ||
| 1125 | return QUOTA_NL_BSOFTBELOW; | ||
| 1126 | if (toqb(dquot->dq_dqb.dqb_curspace) >= dquot->dq_dqb.dqb_bhardlimit && | ||
| 1127 | toqb(dquot->dq_dqb.dqb_curspace - space) < | ||
| 1128 | dquot->dq_dqb.dqb_bhardlimit) | ||
| 1129 | return QUOTA_NL_BHARDBELOW; | ||
| 1130 | return QUOTA_NL_NOWARN; | ||
| 1131 | } | ||
| 1086 | /* | 1132 | /* |
| 1087 | * Initialize quota pointers in inode | 1133 | * Initialize quota pointers in inode |
| 1088 | * Transaction must be started at entry | 1134 | * Transaction must be started at entry |
| @@ -1139,6 +1185,28 @@ int dquot_drop(struct inode *inode) | |||
| 1139 | return 0; | 1185 | return 0; |
| 1140 | } | 1186 | } |
| 1141 | 1187 | ||
| 1188 | /* Wrapper to remove references to quota structures from inode */ | ||
| 1189 | void vfs_dq_drop(struct inode *inode) | ||
| 1190 | { | ||
| 1191 | /* Here we can get arbitrary inode from clear_inode() so we have | ||
| 1192 | * to be careful. OTOH we don't need locking as quota operations | ||
| 1193 | * are allowed to change only at mount time */ | ||
| 1194 | if (!IS_NOQUOTA(inode) && inode->i_sb && inode->i_sb->dq_op | ||
| 1195 | && inode->i_sb->dq_op->drop) { | ||
| 1196 | int cnt; | ||
| 1197 | /* Test before calling to rule out calls from proc and such | ||
| 1198 | * where we are not allowed to block. Note that this is | ||
| 1199 | * actually reliable test even without the lock - the caller | ||
| 1200 | * must assure that nobody can come after the DQUOT_DROP and | ||
| 1201 | * add quota pointers back anyway */ | ||
| 1202 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | ||
| 1203 | if (inode->i_dquot[cnt] != NODQUOT) | ||
| 1204 | break; | ||
| 1205 | if (cnt < MAXQUOTAS) | ||
| 1206 | inode->i_sb->dq_op->drop(inode); | ||
| 1207 | } | ||
| 1208 | } | ||
| 1209 | |||
| 1142 | /* | 1210 | /* |
| 1143 | * Following four functions update i_blocks+i_bytes fields and | 1211 | * Following four functions update i_blocks+i_bytes fields and |
| 1144 | * quota information (together with appropriate checks) | 1212 | * quota information (together with appropriate checks) |
| @@ -1248,6 +1316,7 @@ warn_put_all: | |||
| 1248 | int dquot_free_space(struct inode *inode, qsize_t number) | 1316 | int dquot_free_space(struct inode *inode, qsize_t number) |
| 1249 | { | 1317 | { |
| 1250 | unsigned int cnt; | 1318 | unsigned int cnt; |
| 1319 | char warntype[MAXQUOTAS]; | ||
| 1251 | 1320 | ||
| 1252 | /* First test before acquiring mutex - solves deadlocks when we | 1321 | /* First test before acquiring mutex - solves deadlocks when we |
| 1253 | * re-enter the quota code and are already holding the mutex */ | 1322 | * re-enter the quota code and are already holding the mutex */ |
| @@ -1256,6 +1325,7 @@ out_sub: | |||
| 1256 | inode_sub_bytes(inode, number); | 1325 | inode_sub_bytes(inode, number); |
| 1257 | return QUOTA_OK; | 1326 | return QUOTA_OK; |
| 1258 | } | 1327 | } |
| 1328 | |||
| 1259 | down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1329 | down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); |
| 1260 | /* Now recheck reliably when holding dqptr_sem */ | 1330 | /* Now recheck reliably when holding dqptr_sem */ |
| 1261 | if (IS_NOQUOTA(inode)) { | 1331 | if (IS_NOQUOTA(inode)) { |
| @@ -1266,6 +1336,7 @@ out_sub: | |||
| 1266 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1336 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
| 1267 | if (inode->i_dquot[cnt] == NODQUOT) | 1337 | if (inode->i_dquot[cnt] == NODQUOT) |
| 1268 | continue; | 1338 | continue; |
| 1339 | warntype[cnt] = info_bdq_free(inode->i_dquot[cnt], number); | ||
| 1269 | dquot_decr_space(inode->i_dquot[cnt], number); | 1340 | dquot_decr_space(inode->i_dquot[cnt], number); |
| 1270 | } | 1341 | } |
| 1271 | inode_sub_bytes(inode, number); | 1342 | inode_sub_bytes(inode, number); |
| @@ -1274,6 +1345,7 @@ out_sub: | |||
| 1274 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | 1345 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) |
| 1275 | if (inode->i_dquot[cnt]) | 1346 | if (inode->i_dquot[cnt]) |
| 1276 | mark_dquot_dirty(inode->i_dquot[cnt]); | 1347 | mark_dquot_dirty(inode->i_dquot[cnt]); |
| 1348 | flush_warnings(inode->i_dquot, warntype); | ||
| 1277 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1349 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); |
| 1278 | return QUOTA_OK; | 1350 | return QUOTA_OK; |
| 1279 | } | 1351 | } |
| @@ -1284,11 +1356,13 @@ out_sub: | |||
| 1284 | int dquot_free_inode(const struct inode *inode, unsigned long number) | 1356 | int dquot_free_inode(const struct inode *inode, unsigned long number) |
| 1285 | { | 1357 | { |
| 1286 | unsigned int cnt; | 1358 | unsigned int cnt; |
| 1359 | char warntype[MAXQUOTAS]; | ||
| 1287 | 1360 | ||
| 1288 | /* First test before acquiring mutex - solves deadlocks when we | 1361 | /* First test before acquiring mutex - solves deadlocks when we |
| 1289 | * re-enter the quota code and are already holding the mutex */ | 1362 | * re-enter the quota code and are already holding the mutex */ |
| 1290 | if (IS_NOQUOTA(inode)) | 1363 | if (IS_NOQUOTA(inode)) |
| 1291 | return QUOTA_OK; | 1364 | return QUOTA_OK; |
| 1365 | |||
| 1292 | down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1366 | down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); |
| 1293 | /* Now recheck reliably when holding dqptr_sem */ | 1367 | /* Now recheck reliably when holding dqptr_sem */ |
| 1294 | if (IS_NOQUOTA(inode)) { | 1368 | if (IS_NOQUOTA(inode)) { |
| @@ -1299,6 +1373,7 @@ int dquot_free_inode(const struct inode *inode, unsigned long number) | |||
| 1299 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1373 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
| 1300 | if (inode->i_dquot[cnt] == NODQUOT) | 1374 | if (inode->i_dquot[cnt] == NODQUOT) |
| 1301 | continue; | 1375 | continue; |
| 1376 | warntype[cnt] = info_idq_free(inode->i_dquot[cnt], number); | ||
| 1302 | dquot_decr_inodes(inode->i_dquot[cnt], number); | 1377 | dquot_decr_inodes(inode->i_dquot[cnt], number); |
| 1303 | } | 1378 | } |
| 1304 | spin_unlock(&dq_data_lock); | 1379 | spin_unlock(&dq_data_lock); |
| @@ -1306,6 +1381,7 @@ int dquot_free_inode(const struct inode *inode, unsigned long number) | |||
| 1306 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | 1381 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) |
| 1307 | if (inode->i_dquot[cnt]) | 1382 | if (inode->i_dquot[cnt]) |
| 1308 | mark_dquot_dirty(inode->i_dquot[cnt]); | 1383 | mark_dquot_dirty(inode->i_dquot[cnt]); |
| 1384 | flush_warnings(inode->i_dquot, warntype); | ||
| 1309 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1385 | up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); |
| 1310 | return QUOTA_OK; | 1386 | return QUOTA_OK; |
| 1311 | } | 1387 | } |
| @@ -1323,7 +1399,8 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) | |||
| 1323 | struct dquot *transfer_to[MAXQUOTAS]; | 1399 | struct dquot *transfer_to[MAXQUOTAS]; |
| 1324 | int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, | 1400 | int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, |
| 1325 | chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid; | 1401 | chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid; |
| 1326 | char warntype[MAXQUOTAS]; | 1402 | char warntype_to[MAXQUOTAS]; |
| 1403 | char warntype_from_inodes[MAXQUOTAS], warntype_from_space[MAXQUOTAS]; | ||
| 1327 | 1404 | ||
| 1328 | /* First test before acquiring mutex - solves deadlocks when we | 1405 | /* First test before acquiring mutex - solves deadlocks when we |
| 1329 | * re-enter the quota code and are already holding the mutex */ | 1406 | * re-enter the quota code and are already holding the mutex */ |
| @@ -1332,7 +1409,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) | |||
| 1332 | /* Clear the arrays */ | 1409 | /* Clear the arrays */ |
| 1333 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1410 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
| 1334 | transfer_to[cnt] = transfer_from[cnt] = NODQUOT; | 1411 | transfer_to[cnt] = transfer_from[cnt] = NODQUOT; |
| 1335 | warntype[cnt] = QUOTA_NL_NOWARN; | 1412 | warntype_to[cnt] = QUOTA_NL_NOWARN; |
| 1336 | } | 1413 | } |
| 1337 | down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); | 1414 | down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); |
| 1338 | /* Now recheck reliably when holding dqptr_sem */ | 1415 | /* Now recheck reliably when holding dqptr_sem */ |
| @@ -1364,8 +1441,9 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) | |||
| 1364 | if (transfer_to[cnt] == NODQUOT) | 1441 | if (transfer_to[cnt] == NODQUOT) |
| 1365 | continue; | 1442 | continue; |
| 1366 | transfer_from[cnt] = inode->i_dquot[cnt]; | 1443 | transfer_from[cnt] = inode->i_dquot[cnt]; |
| 1367 | if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA || | 1444 | if (check_idq(transfer_to[cnt], 1, warntype_to + cnt) == |
| 1368 | check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA) | 1445 | NO_QUOTA || check_bdq(transfer_to[cnt], space, 0, |
| 1446 | warntype_to + cnt) == NO_QUOTA) | ||
| 1369 | goto warn_put_all; | 1447 | goto warn_put_all; |
| 1370 | } | 1448 | } |
| 1371 | 1449 | ||
| @@ -1381,6 +1459,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr) | |||
| 1381 | 1459 | ||
| 1382 | /* Due to IO error we might not have transfer_from[] structure */ | 1460 | /* Due to IO error we might not have transfer_from[] structure */ |
| 1383 | if (transfer_from[cnt]) { | 1461 | if (transfer_from[cnt]) { |
| 1462 | warntype_from_inodes[cnt] = | ||
| 1463 | info_idq_free(transfer_from[cnt], 1); | ||
| 1464 | warntype_from_space[cnt] = | ||
| 1465 | info_bdq_free(transfer_from[cnt], space); | ||
| 1384 | dquot_decr_inodes(transfer_from[cnt], 1); | 1466 | dquot_decr_inodes(transfer_from[cnt], 1); |
| 1385 | dquot_decr_space(transfer_from[cnt], space); | 1467 | dquot_decr_space(transfer_from[cnt], space); |
| 1386 | } | 1468 | } |
| @@ -1400,7 +1482,9 @@ warn_put_all: | |||
| 1400 | if (transfer_to[cnt]) | 1482 | if (transfer_to[cnt]) |
| 1401 | mark_dquot_dirty(transfer_to[cnt]); | 1483 | mark_dquot_dirty(transfer_to[cnt]); |
| 1402 | } | 1484 | } |
| 1403 | flush_warnings(transfer_to, warntype); | 1485 | flush_warnings(transfer_to, warntype_to); |
| 1486 | flush_warnings(transfer_from, warntype_from_inodes); | ||
| 1487 | flush_warnings(transfer_from, warntype_from_space); | ||
| 1404 | 1488 | ||
| 1405 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | 1489 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
| 1406 | if (ret == QUOTA_OK && transfer_from[cnt] != NODQUOT) | 1490 | if (ret == QUOTA_OK && transfer_from[cnt] != NODQUOT) |
| @@ -1412,6 +1496,18 @@ warn_put_all: | |||
| 1412 | return ret; | 1496 | return ret; |
| 1413 | } | 1497 | } |
| 1414 | 1498 | ||
| 1499 | /* Wrapper for transferring ownership of an inode */ | ||
| 1500 | int vfs_dq_transfer(struct inode *inode, struct iattr *iattr) | ||
| 1501 | { | ||
| 1502 | if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) { | ||
| 1503 | vfs_dq_init(inode); | ||
| 1504 | if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) | ||
| 1505 | return 1; | ||
| 1506 | } | ||
| 1507 | return 0; | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | |||
| 1415 | /* | 1511 | /* |
| 1416 | * Write info of quota file to disk | 1512 | * Write info of quota file to disk |
| 1417 | */ | 1513 | */ |
| @@ -1697,6 +1793,21 @@ static int vfs_quota_on_remount(struct super_block *sb, int type) | |||
| 1697 | return ret; | 1793 | return ret; |
| 1698 | } | 1794 | } |
| 1699 | 1795 | ||
| 1796 | int vfs_quota_on_path(struct super_block *sb, int type, int format_id, | ||
| 1797 | struct path *path) | ||
| 1798 | { | ||
| 1799 | int error = security_quota_on(path->dentry); | ||
| 1800 | if (error) | ||
| 1801 | return error; | ||
| 1802 | /* Quota file not on the same filesystem? */ | ||
| 1803 | if (path->mnt->mnt_sb != sb) | ||
| 1804 | error = -EXDEV; | ||
| 1805 | else | ||
| 1806 | error = vfs_quota_on_inode(path->dentry->d_inode, type, | ||
| 1807 | format_id); | ||
| 1808 | return error; | ||
| 1809 | } | ||
| 1810 | |||
| 1700 | /* Actual function called from quotactl() */ | 1811 | /* Actual function called from quotactl() */ |
| 1701 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, | 1812 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, |
| 1702 | int remount) | 1813 | int remount) |
| @@ -1708,19 +1819,10 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, | |||
| 1708 | return vfs_quota_on_remount(sb, type); | 1819 | return vfs_quota_on_remount(sb, type); |
| 1709 | 1820 | ||
| 1710 | error = path_lookup(path, LOOKUP_FOLLOW, &nd); | 1821 | error = path_lookup(path, LOOKUP_FOLLOW, &nd); |
| 1711 | if (error < 0) | 1822 | if (!error) { |
| 1712 | return error; | 1823 | error = vfs_quota_on_path(sb, type, format_id, &nd.path); |
| 1713 | error = security_quota_on(nd.path.dentry); | 1824 | path_put(&nd.path); |
| 1714 | if (error) | 1825 | } |
| 1715 | goto out_path; | ||
| 1716 | /* Quota file not on the same filesystem? */ | ||
| 1717 | if (nd.path.mnt->mnt_sb != sb) | ||
| 1718 | error = -EXDEV; | ||
| 1719 | else | ||
| 1720 | error = vfs_quota_on_inode(nd.path.dentry->d_inode, type, | ||
| 1721 | format_id); | ||
| 1722 | out_path: | ||
| 1723 | path_put(&nd.path); | ||
| 1724 | return error; | 1826 | return error; |
| 1725 | } | 1827 | } |
| 1726 | 1828 | ||
| @@ -1752,6 +1854,22 @@ out: | |||
| 1752 | return error; | 1854 | return error; |
| 1753 | } | 1855 | } |
| 1754 | 1856 | ||
| 1857 | /* Wrapper to turn on quotas when remounting rw */ | ||
| 1858 | int vfs_dq_quota_on_remount(struct super_block *sb) | ||
| 1859 | { | ||
| 1860 | int cnt; | ||
| 1861 | int ret = 0, err; | ||
| 1862 | |||
| 1863 | if (!sb->s_qcop || !sb->s_qcop->quota_on) | ||
| 1864 | return -ENOSYS; | ||
| 1865 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | ||
| 1866 | err = sb->s_qcop->quota_on(sb, cnt, 0, NULL, 1); | ||
| 1867 | if (err < 0 && !ret) | ||
| 1868 | ret = err; | ||
| 1869 | } | ||
| 1870 | return ret; | ||
| 1871 | } | ||
| 1872 | |||
| 1755 | /* Generic routine for getting common part of quota structure */ | 1873 | /* Generic routine for getting common part of quota structure */ |
| 1756 | static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) | 1874 | static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di) |
| 1757 | { | 1875 | { |
| @@ -2073,6 +2191,7 @@ EXPORT_SYMBOL(unregister_quota_format); | |||
| 2073 | EXPORT_SYMBOL(dqstats); | 2191 | EXPORT_SYMBOL(dqstats); |
| 2074 | EXPORT_SYMBOL(dq_data_lock); | 2192 | EXPORT_SYMBOL(dq_data_lock); |
| 2075 | EXPORT_SYMBOL(vfs_quota_on); | 2193 | EXPORT_SYMBOL(vfs_quota_on); |
| 2194 | EXPORT_SYMBOL(vfs_quota_on_path); | ||
| 2076 | EXPORT_SYMBOL(vfs_quota_on_mount); | 2195 | EXPORT_SYMBOL(vfs_quota_on_mount); |
| 2077 | EXPORT_SYMBOL(vfs_quota_off); | 2196 | EXPORT_SYMBOL(vfs_quota_off); |
| 2078 | EXPORT_SYMBOL(vfs_quota_sync); | 2197 | EXPORT_SYMBOL(vfs_quota_sync); |
| @@ -2087,8 +2206,11 @@ EXPORT_SYMBOL(dquot_release); | |||
| 2087 | EXPORT_SYMBOL(dquot_mark_dquot_dirty); | 2206 | EXPORT_SYMBOL(dquot_mark_dquot_dirty); |
| 2088 | EXPORT_SYMBOL(dquot_initialize); | 2207 | EXPORT_SYMBOL(dquot_initialize); |
| 2089 | EXPORT_SYMBOL(dquot_drop); | 2208 | EXPORT_SYMBOL(dquot_drop); |
| 2209 | EXPORT_SYMBOL(vfs_dq_drop); | ||
| 2090 | EXPORT_SYMBOL(dquot_alloc_space); | 2210 | EXPORT_SYMBOL(dquot_alloc_space); |
| 2091 | EXPORT_SYMBOL(dquot_alloc_inode); | 2211 | EXPORT_SYMBOL(dquot_alloc_inode); |
| 2092 | EXPORT_SYMBOL(dquot_free_space); | 2212 | EXPORT_SYMBOL(dquot_free_space); |
| 2093 | EXPORT_SYMBOL(dquot_free_inode); | 2213 | EXPORT_SYMBOL(dquot_free_inode); |
| 2094 | EXPORT_SYMBOL(dquot_transfer); | 2214 | EXPORT_SYMBOL(dquot_transfer); |
| 2215 | EXPORT_SYMBOL(vfs_dq_transfer); | ||
| 2216 | EXPORT_SYMBOL(vfs_dq_quota_on_remount); | ||
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 7b99917ffadc..06db79d05c12 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c | |||
| @@ -475,8 +475,8 @@ int ecryptfs_encrypt_page(struct page *page) | |||
| 475 | { | 475 | { |
| 476 | struct inode *ecryptfs_inode; | 476 | struct inode *ecryptfs_inode; |
| 477 | struct ecryptfs_crypt_stat *crypt_stat; | 477 | struct ecryptfs_crypt_stat *crypt_stat; |
| 478 | char *enc_extent_virt = NULL; | 478 | char *enc_extent_virt; |
| 479 | struct page *enc_extent_page; | 479 | struct page *enc_extent_page = NULL; |
| 480 | loff_t extent_offset; | 480 | loff_t extent_offset; |
| 481 | int rc = 0; | 481 | int rc = 0; |
| 482 | 482 | ||
| @@ -492,14 +492,14 @@ int ecryptfs_encrypt_page(struct page *page) | |||
| 492 | page->index); | 492 | page->index); |
| 493 | goto out; | 493 | goto out; |
| 494 | } | 494 | } |
| 495 | enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); | 495 | enc_extent_page = alloc_page(GFP_USER); |
| 496 | if (!enc_extent_virt) { | 496 | if (!enc_extent_page) { |
| 497 | rc = -ENOMEM; | 497 | rc = -ENOMEM; |
| 498 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " | 498 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " |
| 499 | "encrypted extent\n"); | 499 | "encrypted extent\n"); |
| 500 | goto out; | 500 | goto out; |
| 501 | } | 501 | } |
| 502 | enc_extent_page = virt_to_page(enc_extent_virt); | 502 | enc_extent_virt = kmap(enc_extent_page); |
| 503 | for (extent_offset = 0; | 503 | for (extent_offset = 0; |
| 504 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); | 504 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); |
| 505 | extent_offset++) { | 505 | extent_offset++) { |
| @@ -527,7 +527,10 @@ int ecryptfs_encrypt_page(struct page *page) | |||
| 527 | } | 527 | } |
| 528 | } | 528 | } |
| 529 | out: | 529 | out: |
| 530 | kfree(enc_extent_virt); | 530 | if (enc_extent_page) { |
| 531 | kunmap(enc_extent_page); | ||
| 532 | __free_page(enc_extent_page); | ||
| 533 | } | ||
| 531 | return rc; | 534 | return rc; |
| 532 | } | 535 | } |
| 533 | 536 | ||
| @@ -609,8 +612,8 @@ int ecryptfs_decrypt_page(struct page *page) | |||
| 609 | { | 612 | { |
| 610 | struct inode *ecryptfs_inode; | 613 | struct inode *ecryptfs_inode; |
| 611 | struct ecryptfs_crypt_stat *crypt_stat; | 614 | struct ecryptfs_crypt_stat *crypt_stat; |
| 612 | char *enc_extent_virt = NULL; | 615 | char *enc_extent_virt; |
| 613 | struct page *enc_extent_page; | 616 | struct page *enc_extent_page = NULL; |
| 614 | unsigned long extent_offset; | 617 | unsigned long extent_offset; |
| 615 | int rc = 0; | 618 | int rc = 0; |
| 616 | 619 | ||
| @@ -627,14 +630,14 @@ int ecryptfs_decrypt_page(struct page *page) | |||
| 627 | page->index); | 630 | page->index); |
| 628 | goto out; | 631 | goto out; |
| 629 | } | 632 | } |
| 630 | enc_extent_virt = kmalloc(PAGE_CACHE_SIZE, GFP_USER); | 633 | enc_extent_page = alloc_page(GFP_USER); |
| 631 | if (!enc_extent_virt) { | 634 | if (!enc_extent_page) { |
| 632 | rc = -ENOMEM; | 635 | rc = -ENOMEM; |
| 633 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " | 636 | ecryptfs_printk(KERN_ERR, "Error allocating memory for " |
| 634 | "encrypted extent\n"); | 637 | "encrypted extent\n"); |
| 635 | goto out; | 638 | goto out; |
| 636 | } | 639 | } |
| 637 | enc_extent_page = virt_to_page(enc_extent_virt); | 640 | enc_extent_virt = kmap(enc_extent_page); |
| 638 | for (extent_offset = 0; | 641 | for (extent_offset = 0; |
| 639 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); | 642 | extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size); |
| 640 | extent_offset++) { | 643 | extent_offset++) { |
| @@ -662,7 +665,10 @@ int ecryptfs_decrypt_page(struct page *page) | |||
| 662 | } | 665 | } |
| 663 | } | 666 | } |
| 664 | out: | 667 | out: |
| 665 | kfree(enc_extent_virt); | 668 | if (enc_extent_page) { |
| 669 | kunmap(enc_extent_page); | ||
| 670 | __free_page(enc_extent_page); | ||
| 671 | } | ||
| 666 | return rc; | 672 | return rc; |
| 667 | } | 673 | } |
| 668 | 674 | ||
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index d755455e3bff..89209f00f9c7 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -465,7 +465,6 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 465 | int rc; | 465 | int rc; |
| 466 | struct dentry *lower_dentry; | 466 | struct dentry *lower_dentry; |
| 467 | struct dentry *lower_dir_dentry; | 467 | struct dentry *lower_dir_dentry; |
| 468 | umode_t mode; | ||
| 469 | char *encoded_symname; | 468 | char *encoded_symname; |
| 470 | int encoded_symlen; | 469 | int encoded_symlen; |
| 471 | struct ecryptfs_crypt_stat *crypt_stat = NULL; | 470 | struct ecryptfs_crypt_stat *crypt_stat = NULL; |
| @@ -473,7 +472,6 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 473 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 472 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 474 | dget(lower_dentry); | 473 | dget(lower_dentry); |
| 475 | lower_dir_dentry = lock_parent(lower_dentry); | 474 | lower_dir_dentry = lock_parent(lower_dentry); |
| 476 | mode = S_IALLUGO; | ||
| 477 | encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname, | 475 | encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname, |
| 478 | strlen(symname), | 476 | strlen(symname), |
| 479 | &encoded_symname); | 477 | &encoded_symname); |
| @@ -482,7 +480,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 482 | goto out_lock; | 480 | goto out_lock; |
| 483 | } | 481 | } |
| 484 | rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, | 482 | rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry, |
| 485 | encoded_symname, mode); | 483 | encoded_symname); |
| 486 | kfree(encoded_symname); | 484 | kfree(encoded_symname); |
| 487 | if (rc || !lower_dentry->d_inode) | 485 | if (rc || !lower_dentry->d_inode) |
| 488 | goto out_lock; | 486 | goto out_lock; |
| @@ -830,22 +828,9 @@ out: | |||
| 830 | } | 828 | } |
| 831 | 829 | ||
| 832 | static int | 830 | static int |
| 833 | ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd) | 831 | ecryptfs_permission(struct inode *inode, int mask) |
| 834 | { | 832 | { |
| 835 | int rc; | 833 | return inode_permission(ecryptfs_inode_to_lower(inode), mask); |
| 836 | |||
| 837 | if (nd) { | ||
| 838 | struct vfsmount *vfsmnt_save = nd->path.mnt; | ||
| 839 | struct dentry *dentry_save = nd->path.dentry; | ||
| 840 | |||
| 841 | nd->path.mnt = ecryptfs_dentry_to_lower_mnt(nd->path.dentry); | ||
| 842 | nd->path.dentry = ecryptfs_dentry_to_lower(nd->path.dentry); | ||
| 843 | rc = permission(ecryptfs_inode_to_lower(inode), mask, nd); | ||
| 844 | nd->path.mnt = vfsmnt_save; | ||
| 845 | nd->path.dentry = dentry_save; | ||
| 846 | } else | ||
| 847 | rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL); | ||
| 848 | return rc; | ||
| 849 | } | 834 | } |
| 850 | 835 | ||
| 851 | /** | 836 | /** |
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 6f403cfba14f..448dfd597b5f 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
| @@ -578,7 +578,7 @@ static struct file_system_type ecryptfs_fs_type = { | |||
| 578 | * Initializes the ecryptfs_inode_info_cache when it is created | 578 | * Initializes the ecryptfs_inode_info_cache when it is created |
| 579 | */ | 579 | */ |
| 580 | static void | 580 | static void |
| 581 | inode_info_init_once(struct kmem_cache *cachep, void *vptr) | 581 | inode_info_init_once(void *vptr) |
| 582 | { | 582 | { |
| 583 | struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr; | 583 | struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr; |
| 584 | 584 | ||
| @@ -589,7 +589,7 @@ static struct ecryptfs_cache_info { | |||
| 589 | struct kmem_cache **cache; | 589 | struct kmem_cache **cache; |
| 590 | const char *name; | 590 | const char *name; |
| 591 | size_t size; | 591 | size_t size; |
| 592 | void (*ctor)(struct kmem_cache *cache, void *obj); | 592 | void (*ctor)(void *obj); |
| 593 | } ecryptfs_cache_infos[] = { | 593 | } ecryptfs_cache_infos[] = { |
| 594 | { | 594 | { |
| 595 | .cache = &ecryptfs_auth_tok_list_item_cache, | 595 | .cache = &ecryptfs_auth_tok_list_item_cache, |
diff --git a/fs/efs/namei.c b/fs/efs/namei.c index 3a404e7fad53..291abb11e20e 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c | |||
| @@ -74,8 +74,7 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei | |||
| 74 | } | 74 | } |
| 75 | unlock_kernel(); | 75 | unlock_kernel(); |
| 76 | 76 | ||
| 77 | d_add(dentry, inode); | 77 | return d_splice_alias(inode, dentry); |
| 78 | return NULL; | ||
| 79 | } | 78 | } |
| 80 | 79 | ||
| 81 | static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino, | 80 | static struct inode *efs_nfs_get_inode(struct super_block *sb, u64 ino, |
diff --git a/fs/efs/super.c b/fs/efs/super.c index d733531b55e2..567b134fa1f1 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c | |||
| @@ -70,7 +70,7 @@ static void efs_destroy_inode(struct inode *inode) | |||
| 70 | kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); | 70 | kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static void init_once(struct kmem_cache *cachep, void *foo) | 73 | static void init_once(void *foo) |
| 74 | { | 74 | { |
| 75 | struct efs_inode_info *ei = (struct efs_inode_info *) foo; | 75 | struct efs_inode_info *ei = (struct efs_inode_info *) foo; |
| 76 | 76 | ||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 0c87474f7917..7cc0eb756b55 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
| @@ -1041,10 +1041,7 @@ retry: | |||
| 1041 | } | 1041 | } |
| 1042 | 1042 | ||
| 1043 | /* | 1043 | /* |
| 1044 | * It opens an eventpoll file descriptor. The "size" parameter is there | 1044 | * Open an eventpoll file descriptor. |
| 1045 | * for historical reasons, when epoll was using an hash instead of an | ||
| 1046 | * RB tree. With the current implementation, the "size" parameter is ignored | ||
| 1047 | * (besides sanity checks). | ||
| 1048 | */ | 1045 | */ |
| 1049 | asmlinkage long sys_epoll_create1(int flags) | 1046 | asmlinkage long sys_epoll_create1(int flags) |
| 1050 | { | 1047 | { |
| @@ -25,10 +25,11 @@ | |||
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/file.h> | 26 | #include <linux/file.h> |
| 27 | #include <linux/fdtable.h> | 27 | #include <linux/fdtable.h> |
| 28 | #include <linux/mman.h> | 28 | #include <linux/mm.h> |
| 29 | #include <linux/stat.h> | 29 | #include <linux/stat.h> |
| 30 | #include <linux/fcntl.h> | 30 | #include <linux/fcntl.h> |
| 31 | #include <linux/smp_lock.h> | 31 | #include <linux/smp_lock.h> |
| 32 | #include <linux/swap.h> | ||
| 32 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 33 | #include <linux/init.h> | 34 | #include <linux/init.h> |
| 34 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
| @@ -37,20 +38,18 @@ | |||
| 37 | #include <linux/key.h> | 38 | #include <linux/key.h> |
| 38 | #include <linux/personality.h> | 39 | #include <linux/personality.h> |
| 39 | #include <linux/binfmts.h> | 40 | #include <linux/binfmts.h> |
| 40 | #include <linux/swap.h> | ||
| 41 | #include <linux/utsname.h> | 41 | #include <linux/utsname.h> |
| 42 | #include <linux/pid_namespace.h> | 42 | #include <linux/pid_namespace.h> |
| 43 | #include <linux/module.h> | 43 | #include <linux/module.h> |
| 44 | #include <linux/namei.h> | 44 | #include <linux/namei.h> |
| 45 | #include <linux/proc_fs.h> | 45 | #include <linux/proc_fs.h> |
| 46 | #include <linux/ptrace.h> | ||
| 47 | #include <linux/mount.h> | 46 | #include <linux/mount.h> |
| 48 | #include <linux/security.h> | 47 | #include <linux/security.h> |
| 49 | #include <linux/syscalls.h> | 48 | #include <linux/syscalls.h> |
| 50 | #include <linux/rmap.h> | ||
| 51 | #include <linux/tsacct_kern.h> | 49 | #include <linux/tsacct_kern.h> |
| 52 | #include <linux/cn_proc.h> | 50 | #include <linux/cn_proc.h> |
| 53 | #include <linux/audit.h> | 51 | #include <linux/audit.h> |
| 52 | #include <linux/tracehook.h> | ||
| 54 | 53 | ||
| 55 | #include <asm/uaccess.h> | 54 | #include <asm/uaccess.h> |
| 56 | #include <asm/mmu_context.h> | 55 | #include <asm/mmu_context.h> |
| @@ -108,11 +107,17 @@ static inline void put_binfmt(struct linux_binfmt * fmt) | |||
| 108 | */ | 107 | */ |
| 109 | asmlinkage long sys_uselib(const char __user * library) | 108 | asmlinkage long sys_uselib(const char __user * library) |
| 110 | { | 109 | { |
| 111 | struct file * file; | 110 | struct file *file; |
| 112 | struct nameidata nd; | 111 | struct nameidata nd; |
| 113 | int error; | 112 | char *tmp = getname(library); |
| 114 | 113 | int error = PTR_ERR(tmp); | |
| 115 | error = __user_path_lookup_open(library, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC); | 114 | |
| 115 | if (!IS_ERR(tmp)) { | ||
| 116 | error = path_lookup_open(AT_FDCWD, tmp, | ||
| 117 | LOOKUP_FOLLOW, &nd, | ||
| 118 | FMODE_READ|FMODE_EXEC); | ||
| 119 | putname(tmp); | ||
| 120 | } | ||
| 116 | if (error) | 121 | if (error) |
| 117 | goto out; | 122 | goto out; |
| 118 | 123 | ||
| @@ -120,7 +125,11 @@ asmlinkage long sys_uselib(const char __user * library) | |||
| 120 | if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) | 125 | if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) |
| 121 | goto exit; | 126 | goto exit; |
| 122 | 127 | ||
| 123 | error = vfs_permission(&nd, MAY_READ | MAY_EXEC); | 128 | error = -EACCES; |
| 129 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) | ||
| 130 | goto exit; | ||
| 131 | |||
| 132 | error = vfs_permission(&nd, MAY_READ | MAY_EXEC | MAY_OPEN); | ||
| 124 | if (error) | 133 | if (error) |
| 125 | goto exit; | 134 | goto exit; |
| 126 | 135 | ||
| @@ -658,38 +667,43 @@ EXPORT_SYMBOL(setup_arg_pages); | |||
| 658 | struct file *open_exec(const char *name) | 667 | struct file *open_exec(const char *name) |
| 659 | { | 668 | { |
| 660 | struct nameidata nd; | 669 | struct nameidata nd; |
| 661 | int err; | ||
| 662 | struct file *file; | 670 | struct file *file; |
| 671 | int err; | ||
| 663 | 672 | ||
| 664 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC); | 673 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, |
| 665 | file = ERR_PTR(err); | 674 | FMODE_READ|FMODE_EXEC); |
| 666 | 675 | if (err) | |
| 667 | if (!err) { | 676 | goto out; |
| 668 | struct inode *inode = nd.path.dentry->d_inode; | 677 | |
| 669 | file = ERR_PTR(-EACCES); | 678 | err = -EACCES; |
| 670 | if (S_ISREG(inode->i_mode)) { | 679 | if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) |
| 671 | int err = vfs_permission(&nd, MAY_EXEC); | 680 | goto out_path_put; |
| 672 | file = ERR_PTR(err); | 681 | |
| 673 | if (!err) { | 682 | if (nd.path.mnt->mnt_flags & MNT_NOEXEC) |
| 674 | file = nameidata_to_filp(&nd, | 683 | goto out_path_put; |
| 675 | O_RDONLY|O_LARGEFILE); | 684 | |
| 676 | if (!IS_ERR(file)) { | 685 | err = vfs_permission(&nd, MAY_EXEC | MAY_OPEN); |
| 677 | err = deny_write_access(file); | 686 | if (err) |
| 678 | if (err) { | 687 | goto out_path_put; |
| 679 | fput(file); | 688 | |
| 680 | file = ERR_PTR(err); | 689 | file = nameidata_to_filp(&nd, O_RDONLY|O_LARGEFILE); |
| 681 | } | 690 | if (IS_ERR(file)) |
| 682 | } | 691 | return file; |
| 683 | out: | 692 | |
| 684 | return file; | 693 | err = deny_write_access(file); |
| 685 | } | 694 | if (err) { |
| 686 | } | 695 | fput(file); |
| 687 | release_open_intent(&nd); | 696 | goto out; |
| 688 | path_put(&nd.path); | ||
| 689 | } | 697 | } |
| 690 | goto out; | ||
| 691 | } | ||
| 692 | 698 | ||
| 699 | return file; | ||
| 700 | |||
| 701 | out_path_put: | ||
| 702 | release_open_intent(&nd); | ||
| 703 | path_put(&nd.path); | ||
| 704 | out: | ||
| 705 | return ERR_PTR(err); | ||
| 706 | } | ||
| 693 | EXPORT_SYMBOL(open_exec); | 707 | EXPORT_SYMBOL(open_exec); |
| 694 | 708 | ||
| 695 | int kernel_read(struct file *file, unsigned long offset, | 709 | int kernel_read(struct file *file, unsigned long offset, |
| @@ -724,12 +738,10 @@ static int exec_mmap(struct mm_struct *mm) | |||
| 724 | * Make sure that if there is a core dump in progress | 738 | * Make sure that if there is a core dump in progress |
| 725 | * for the old mm, we get out and die instead of going | 739 | * for the old mm, we get out and die instead of going |
| 726 | * through with the exec. We must hold mmap_sem around | 740 | * through with the exec. We must hold mmap_sem around |
| 727 | * checking core_waiters and changing tsk->mm. The | 741 | * checking core_state and changing tsk->mm. |
| 728 | * core-inducing thread will increment core_waiters for | ||
| 729 | * each thread whose ->mm == old_mm. | ||
| 730 | */ | 742 | */ |
| 731 | down_read(&old_mm->mmap_sem); | 743 | down_read(&old_mm->mmap_sem); |
| 732 | if (unlikely(old_mm->core_waiters)) { | 744 | if (unlikely(old_mm->core_state)) { |
| 733 | up_read(&old_mm->mmap_sem); | 745 | up_read(&old_mm->mmap_sem); |
| 734 | return -EINTR; | 746 | return -EINTR; |
| 735 | } | 747 | } |
| @@ -1075,13 +1087,8 @@ EXPORT_SYMBOL(prepare_binprm); | |||
| 1075 | 1087 | ||
| 1076 | static int unsafe_exec(struct task_struct *p) | 1088 | static int unsafe_exec(struct task_struct *p) |
| 1077 | { | 1089 | { |
| 1078 | int unsafe = 0; | 1090 | int unsafe = tracehook_unsafe_exec(p); |
| 1079 | if (p->ptrace & PT_PTRACED) { | 1091 | |
| 1080 | if (p->ptrace & PT_PTRACE_CAP) | ||
| 1081 | unsafe |= LSM_UNSAFE_PTRACE_CAP; | ||
| 1082 | else | ||
| 1083 | unsafe |= LSM_UNSAFE_PTRACE; | ||
| 1084 | } | ||
| 1085 | if (atomic_read(&p->fs->count) > 1 || | 1092 | if (atomic_read(&p->fs->count) > 1 || |
| 1086 | atomic_read(&p->files->count) > 1 || | 1093 | atomic_read(&p->files->count) > 1 || |
| 1087 | atomic_read(&p->sighand->count) > 1) | 1094 | atomic_read(&p->sighand->count) > 1) |
| @@ -1218,6 +1225,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) | |||
| 1218 | read_unlock(&binfmt_lock); | 1225 | read_unlock(&binfmt_lock); |
| 1219 | retval = fn(bprm, regs); | 1226 | retval = fn(bprm, regs); |
| 1220 | if (retval >= 0) { | 1227 | if (retval >= 0) { |
| 1228 | tracehook_report_exec(fmt, bprm, regs); | ||
| 1221 | put_binfmt(fmt); | 1229 | put_binfmt(fmt); |
| 1222 | allow_write_access(bprm->file); | 1230 | allow_write_access(bprm->file); |
| 1223 | if (bprm->file) | 1231 | if (bprm->file) |
| @@ -1328,6 +1336,7 @@ int do_execve(char * filename, | |||
| 1328 | if (retval < 0) | 1336 | if (retval < 0) |
| 1329 | goto out; | 1337 | goto out; |
| 1330 | 1338 | ||
| 1339 | current->flags &= ~PF_KTHREAD; | ||
| 1331 | retval = search_binary_handler(bprm,regs); | 1340 | retval = search_binary_handler(bprm,regs); |
| 1332 | if (retval >= 0) { | 1341 | if (retval >= 0) { |
| 1333 | /* execve success */ | 1342 | /* execve success */ |
| @@ -1382,17 +1391,14 @@ EXPORT_SYMBOL(set_binfmt); | |||
| 1382 | * name into corename, which must have space for at least | 1391 | * name into corename, which must have space for at least |
| 1383 | * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. | 1392 | * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator. |
| 1384 | */ | 1393 | */ |
| 1385 | static int format_corename(char *corename, const char *pattern, long signr) | 1394 | static int format_corename(char *corename, int nr_threads, long signr) |
| 1386 | { | 1395 | { |
| 1387 | const char *pat_ptr = pattern; | 1396 | const char *pat_ptr = core_pattern; |
| 1397 | int ispipe = (*pat_ptr == '|'); | ||
| 1388 | char *out_ptr = corename; | 1398 | char *out_ptr = corename; |
| 1389 | char *const out_end = corename + CORENAME_MAX_SIZE; | 1399 | char *const out_end = corename + CORENAME_MAX_SIZE; |
| 1390 | int rc; | 1400 | int rc; |
| 1391 | int pid_in_pattern = 0; | 1401 | int pid_in_pattern = 0; |
| 1392 | int ispipe = 0; | ||
| 1393 | |||
| 1394 | if (*pattern == '|') | ||
| 1395 | ispipe = 1; | ||
| 1396 | 1402 | ||
| 1397 | /* Repeat as long as we have more pattern to process and more output | 1403 | /* Repeat as long as we have more pattern to process and more output |
| 1398 | space */ | 1404 | space */ |
| @@ -1493,7 +1499,7 @@ static int format_corename(char *corename, const char *pattern, long signr) | |||
| 1493 | * and core_uses_pid is set, then .%pid will be appended to | 1499 | * and core_uses_pid is set, then .%pid will be appended to |
| 1494 | * the filename. Do not do this for piped commands. */ | 1500 | * the filename. Do not do this for piped commands. */ |
| 1495 | if (!ispipe && !pid_in_pattern | 1501 | if (!ispipe && !pid_in_pattern |
| 1496 | && (core_uses_pid || atomic_read(¤t->mm->mm_users) != 1)) { | 1502 | && (core_uses_pid || nr_threads)) { |
| 1497 | rc = snprintf(out_ptr, out_end - out_ptr, | 1503 | rc = snprintf(out_ptr, out_end - out_ptr, |
| 1498 | ".%d", task_tgid_vnr(current)); | 1504 | ".%d", task_tgid_vnr(current)); |
| 1499 | if (rc > out_end - out_ptr) | 1505 | if (rc > out_end - out_ptr) |
| @@ -1505,9 +1511,10 @@ out: | |||
| 1505 | return ispipe; | 1511 | return ispipe; |
| 1506 | } | 1512 | } |
| 1507 | 1513 | ||
| 1508 | static void zap_process(struct task_struct *start) | 1514 | static int zap_process(struct task_struct *start) |
| 1509 | { | 1515 | { |
| 1510 | struct task_struct *t; | 1516 | struct task_struct *t; |
| 1517 | int nr = 0; | ||
| 1511 | 1518 | ||
| 1512 | start->signal->flags = SIGNAL_GROUP_EXIT; | 1519 | start->signal->flags = SIGNAL_GROUP_EXIT; |
| 1513 | start->signal->group_stop_count = 0; | 1520 | start->signal->group_stop_count = 0; |
| @@ -1515,72 +1522,99 @@ static void zap_process(struct task_struct *start) | |||
| 1515 | t = start; | 1522 | t = start; |
| 1516 | do { | 1523 | do { |
| 1517 | if (t != current && t->mm) { | 1524 | if (t != current && t->mm) { |
| 1518 | t->mm->core_waiters++; | ||
| 1519 | sigaddset(&t->pending.signal, SIGKILL); | 1525 | sigaddset(&t->pending.signal, SIGKILL); |
| 1520 | signal_wake_up(t, 1); | 1526 | signal_wake_up(t, 1); |
| 1527 | nr++; | ||
| 1521 | } | 1528 | } |
| 1522 | } while ((t = next_thread(t)) != start); | 1529 | } while_each_thread(start, t); |
| 1530 | |||
| 1531 | return nr; | ||
| 1523 | } | 1532 | } |
| 1524 | 1533 | ||
| 1525 | static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | 1534 | static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, |
| 1526 | int exit_code) | 1535 | struct core_state *core_state, int exit_code) |
| 1527 | { | 1536 | { |
| 1528 | struct task_struct *g, *p; | 1537 | struct task_struct *g, *p; |
| 1529 | unsigned long flags; | 1538 | unsigned long flags; |
| 1530 | int err = -EAGAIN; | 1539 | int nr = -EAGAIN; |
| 1531 | 1540 | ||
| 1532 | spin_lock_irq(&tsk->sighand->siglock); | 1541 | spin_lock_irq(&tsk->sighand->siglock); |
| 1533 | if (!signal_group_exit(tsk->signal)) { | 1542 | if (!signal_group_exit(tsk->signal)) { |
| 1543 | mm->core_state = core_state; | ||
| 1534 | tsk->signal->group_exit_code = exit_code; | 1544 | tsk->signal->group_exit_code = exit_code; |
| 1535 | zap_process(tsk); | 1545 | nr = zap_process(tsk); |
| 1536 | err = 0; | ||
| 1537 | } | 1546 | } |
| 1538 | spin_unlock_irq(&tsk->sighand->siglock); | 1547 | spin_unlock_irq(&tsk->sighand->siglock); |
| 1539 | if (err) | 1548 | if (unlikely(nr < 0)) |
| 1540 | return err; | 1549 | return nr; |
| 1541 | 1550 | ||
| 1542 | if (atomic_read(&mm->mm_users) == mm->core_waiters + 1) | 1551 | if (atomic_read(&mm->mm_users) == nr + 1) |
| 1543 | goto done; | 1552 | goto done; |
| 1544 | 1553 | /* | |
| 1554 | * We should find and kill all tasks which use this mm, and we should | ||
| 1555 | * count them correctly into ->nr_threads. We don't take tasklist | ||
| 1556 | * lock, but this is safe wrt: | ||
| 1557 | * | ||
| 1558 | * fork: | ||
| 1559 | * None of sub-threads can fork after zap_process(leader). All | ||
| 1560 | * processes which were created before this point should be | ||
| 1561 | * visible to zap_threads() because copy_process() adds the new | ||
| 1562 | * process to the tail of init_task.tasks list, and lock/unlock | ||
| 1563 | * of ->siglock provides a memory barrier. | ||
| 1564 | * | ||
| 1565 | * do_exit: | ||
| 1566 | * The caller holds mm->mmap_sem. This means that the task which | ||
| 1567 | * uses this mm can't pass exit_mm(), so it can't exit or clear | ||
| 1568 | * its ->mm. | ||
| 1569 | * | ||
| 1570 | * de_thread: | ||
| 1571 | * It does list_replace_rcu(&leader->tasks, ¤t->tasks), | ||
| 1572 | * we must see either old or new leader, this does not matter. | ||
| 1573 | * However, it can change p->sighand, so lock_task_sighand(p) | ||
| 1574 | * must be used. Since p->mm != NULL and we hold ->mmap_sem | ||
| 1575 | * it can't fail. | ||
| 1576 | * | ||
| 1577 | * Note also that "g" can be the old leader with ->mm == NULL | ||
| 1578 | * and already unhashed and thus removed from ->thread_group. | ||
| 1579 | * This is OK, __unhash_process()->list_del_rcu() does not | ||
| 1580 | * clear the ->next pointer, we will find the new leader via | ||
| 1581 | * next_thread(). | ||
| 1582 | */ | ||
| 1545 | rcu_read_lock(); | 1583 | rcu_read_lock(); |
| 1546 | for_each_process(g) { | 1584 | for_each_process(g) { |
| 1547 | if (g == tsk->group_leader) | 1585 | if (g == tsk->group_leader) |
| 1548 | continue; | 1586 | continue; |
| 1549 | 1587 | if (g->flags & PF_KTHREAD) | |
| 1588 | continue; | ||
| 1550 | p = g; | 1589 | p = g; |
| 1551 | do { | 1590 | do { |
| 1552 | if (p->mm) { | 1591 | if (p->mm) { |
| 1553 | if (p->mm == mm) { | 1592 | if (unlikely(p->mm == mm)) { |
| 1554 | /* | ||
| 1555 | * p->sighand can't disappear, but | ||
| 1556 | * may be changed by de_thread() | ||
| 1557 | */ | ||
| 1558 | lock_task_sighand(p, &flags); | 1593 | lock_task_sighand(p, &flags); |
| 1559 | zap_process(p); | 1594 | nr += zap_process(p); |
| 1560 | unlock_task_sighand(p, &flags); | 1595 | unlock_task_sighand(p, &flags); |
| 1561 | } | 1596 | } |
| 1562 | break; | 1597 | break; |
| 1563 | } | 1598 | } |
| 1564 | } while ((p = next_thread(p)) != g); | 1599 | } while_each_thread(g, p); |
| 1565 | } | 1600 | } |
| 1566 | rcu_read_unlock(); | 1601 | rcu_read_unlock(); |
| 1567 | done: | 1602 | done: |
| 1568 | return mm->core_waiters; | 1603 | atomic_set(&core_state->nr_threads, nr); |
| 1604 | return nr; | ||
| 1569 | } | 1605 | } |
| 1570 | 1606 | ||
| 1571 | static int coredump_wait(int exit_code) | 1607 | static int coredump_wait(int exit_code, struct core_state *core_state) |
| 1572 | { | 1608 | { |
| 1573 | struct task_struct *tsk = current; | 1609 | struct task_struct *tsk = current; |
| 1574 | struct mm_struct *mm = tsk->mm; | 1610 | struct mm_struct *mm = tsk->mm; |
| 1575 | struct completion startup_done; | ||
| 1576 | struct completion *vfork_done; | 1611 | struct completion *vfork_done; |
| 1577 | int core_waiters; | 1612 | int core_waiters; |
| 1578 | 1613 | ||
| 1579 | init_completion(&mm->core_done); | 1614 | init_completion(&core_state->startup); |
| 1580 | init_completion(&startup_done); | 1615 | core_state->dumper.task = tsk; |
| 1581 | mm->core_startup_done = &startup_done; | 1616 | core_state->dumper.next = NULL; |
| 1582 | 1617 | core_waiters = zap_threads(tsk, mm, core_state, exit_code); | |
| 1583 | core_waiters = zap_threads(tsk, mm, exit_code); | ||
| 1584 | up_write(&mm->mmap_sem); | 1618 | up_write(&mm->mmap_sem); |
| 1585 | 1619 | ||
| 1586 | if (unlikely(core_waiters < 0)) | 1620 | if (unlikely(core_waiters < 0)) |
| @@ -1597,12 +1631,32 @@ static int coredump_wait(int exit_code) | |||
| 1597 | } | 1631 | } |
| 1598 | 1632 | ||
| 1599 | if (core_waiters) | 1633 | if (core_waiters) |
| 1600 | wait_for_completion(&startup_done); | 1634 | wait_for_completion(&core_state->startup); |
| 1601 | fail: | 1635 | fail: |
| 1602 | BUG_ON(mm->core_waiters); | ||
| 1603 | return core_waiters; | 1636 | return core_waiters; |
| 1604 | } | 1637 | } |
| 1605 | 1638 | ||
| 1639 | static void coredump_finish(struct mm_struct *mm) | ||
| 1640 | { | ||
| 1641 | struct core_thread *curr, *next; | ||
| 1642 | struct task_struct *task; | ||
| 1643 | |||
| 1644 | next = mm->core_state->dumper.next; | ||
| 1645 | while ((curr = next) != NULL) { | ||
| 1646 | next = curr->next; | ||
| 1647 | task = curr->task; | ||
| 1648 | /* | ||
| 1649 | * see exit_mm(), curr->task must not see | ||
| 1650 | * ->task == NULL before we read ->next. | ||
| 1651 | */ | ||
| 1652 | smp_mb(); | ||
| 1653 | curr->task = NULL; | ||
| 1654 | wake_up_process(task); | ||
| 1655 | } | ||
| 1656 | |||
| 1657 | mm->core_state = NULL; | ||
| 1658 | } | ||
| 1659 | |||
| 1606 | /* | 1660 | /* |
| 1607 | * set_dumpable converts traditional three-value dumpable to two flags and | 1661 | * set_dumpable converts traditional three-value dumpable to two flags and |
| 1608 | * stores them into mm->flags. It modifies lower two bits of mm->flags, but | 1662 | * stores them into mm->flags. It modifies lower two bits of mm->flags, but |
| @@ -1654,6 +1708,7 @@ int get_dumpable(struct mm_struct *mm) | |||
| 1654 | 1708 | ||
| 1655 | int do_coredump(long signr, int exit_code, struct pt_regs * regs) | 1709 | int do_coredump(long signr, int exit_code, struct pt_regs * regs) |
| 1656 | { | 1710 | { |
| 1711 | struct core_state core_state; | ||
| 1657 | char corename[CORENAME_MAX_SIZE + 1]; | 1712 | char corename[CORENAME_MAX_SIZE + 1]; |
| 1658 | struct mm_struct *mm = current->mm; | 1713 | struct mm_struct *mm = current->mm; |
| 1659 | struct linux_binfmt * binfmt; | 1714 | struct linux_binfmt * binfmt; |
| @@ -1677,7 +1732,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1677 | /* | 1732 | /* |
| 1678 | * If another thread got here first, or we are not dumpable, bail out. | 1733 | * If another thread got here first, or we are not dumpable, bail out. |
| 1679 | */ | 1734 | */ |
| 1680 | if (mm->core_waiters || !get_dumpable(mm)) { | 1735 | if (mm->core_state || !get_dumpable(mm)) { |
| 1681 | up_write(&mm->mmap_sem); | 1736 | up_write(&mm->mmap_sem); |
| 1682 | goto fail; | 1737 | goto fail; |
| 1683 | } | 1738 | } |
| @@ -1692,7 +1747,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1692 | current->fsuid = 0; /* Dump root private */ | 1747 | current->fsuid = 0; /* Dump root private */ |
| 1693 | } | 1748 | } |
| 1694 | 1749 | ||
| 1695 | retval = coredump_wait(exit_code); | 1750 | retval = coredump_wait(exit_code, &core_state); |
| 1696 | if (retval < 0) | 1751 | if (retval < 0) |
| 1697 | goto fail; | 1752 | goto fail; |
| 1698 | 1753 | ||
| @@ -1707,7 +1762,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) | |||
| 1707 | * uses lock_kernel() | 1762 | * uses lock_kernel() |
| 1708 | */ | 1763 | */ |
| 1709 | lock_kernel(); | 1764 | lock_kernel(); |
| 1710 | ispipe = format_corename(corename, core_pattern, signr); | 1765 | ispipe = format_corename(corename, retval, signr); |
| 1711 | unlock_kernel(); | 1766 | unlock_kernel(); |
| 1712 | /* | 1767 | /* |
| 1713 | * Don't bother to check the RLIMIT_CORE value if core_pattern points | 1768 | * Don't bother to check the RLIMIT_CORE value if core_pattern points |
| @@ -1786,7 +1841,7 @@ fail_unlock: | |||
| 1786 | argv_free(helper_argv); | 1841 | argv_free(helper_argv); |
| 1787 | 1842 | ||
| 1788 | current->fsuid = fsuid; | 1843 | current->fsuid = fsuid; |
| 1789 | complete_all(&mm->core_done); | 1844 | coredump_finish(mm); |
| 1790 | fail: | 1845 | fail: |
| 1791 | return retval; | 1846 | return retval; |
| 1792 | } | 1847 | } |
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index e58669e1b87c..ae8c4f850b27 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
| @@ -294,7 +294,7 @@ ext2_check_acl(struct inode *inode, int mask) | |||
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | int | 296 | int |
| 297 | ext2_permission(struct inode *inode, int mask, struct nameidata *nd) | 297 | ext2_permission(struct inode *inode, int mask) |
| 298 | { | 298 | { |
| 299 | return generic_permission(inode, mask, ext2_check_acl); | 299 | return generic_permission(inode, mask, ext2_check_acl); |
| 300 | } | 300 | } |
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index 0bde85bafe38..b42cf578554b 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h | |||
| @@ -58,7 +58,7 @@ static inline int ext2_acl_count(size_t size) | |||
| 58 | #define EXT2_ACL_NOT_CACHED ((void *)-1) | 58 | #define EXT2_ACL_NOT_CACHED ((void *)-1) |
| 59 | 59 | ||
| 60 | /* acl.c */ | 60 | /* acl.c */ |
| 61 | extern int ext2_permission (struct inode *, int, struct nameidata *); | 61 | extern int ext2_permission (struct inode *, int); |
| 62 | extern int ext2_acl_chmod (struct inode *); | 62 | extern int ext2_acl_chmod (struct inode *); |
| 63 | extern int ext2_init_acl (struct inode *, struct inode *); | 63 | extern int ext2_init_acl (struct inode *, struct inode *); |
| 64 | 64 | ||
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 384fc0d1dd74..991d6dfeb51f 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
| @@ -791,6 +791,7 @@ const struct address_space_operations ext2_aops = { | |||
| 791 | .direct_IO = ext2_direct_IO, | 791 | .direct_IO = ext2_direct_IO, |
| 792 | .writepages = ext2_writepages, | 792 | .writepages = ext2_writepages, |
| 793 | .migratepage = buffer_migrate_page, | 793 | .migratepage = buffer_migrate_page, |
| 794 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 794 | }; | 795 | }; |
| 795 | 796 | ||
| 796 | const struct address_space_operations ext2_aops_xip = { | 797 | const struct address_space_operations ext2_aops_xip = { |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index ef50cbc792db..fd88c7b43e66 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
| 32 | #include <linux/mount.h> | 32 | #include <linux/mount.h> |
| 33 | #include <linux/log2.h> | 33 | #include <linux/log2.h> |
| 34 | #include <linux/quotaops.h> | ||
| 34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
| 35 | #include "ext2.h" | 36 | #include "ext2.h" |
| 36 | #include "xattr.h" | 37 | #include "xattr.h" |
| @@ -158,7 +159,7 @@ static void ext2_destroy_inode(struct inode *inode) | |||
| 158 | kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); | 159 | kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); |
| 159 | } | 160 | } |
| 160 | 161 | ||
| 161 | static void init_once(struct kmem_cache * cachep, void *foo) | 162 | static void init_once(void *foo) |
| 162 | { | 163 | { |
| 163 | struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; | 164 | struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; |
| 164 | 165 | ||
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c index eaa23d2d5213..70c0dbdcdcb7 100644 --- a/fs/ext2/xattr_security.c +++ b/fs/ext2/xattr_security.c | |||
| @@ -14,7 +14,7 @@ static size_t | |||
| 14 | ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size, | 14 | ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size, |
| 15 | const char *name, size_t name_len) | 15 | const char *name, size_t name_len) |
| 16 | { | 16 | { |
| 17 | const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; | 17 | const int prefix_len = XATTR_SECURITY_PREFIX_LEN; |
| 18 | const size_t total_len = prefix_len + name_len + 1; | 18 | const size_t total_len = prefix_len + name_len + 1; |
| 19 | 19 | ||
| 20 | if (list && total_len <= list_size) { | 20 | if (list && total_len <= list_size) { |
diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c index 83ee149f353d..e8219f8eae9f 100644 --- a/fs/ext2/xattr_trusted.c +++ b/fs/ext2/xattr_trusted.c | |||
| @@ -12,13 +12,11 @@ | |||
| 12 | #include <linux/ext2_fs.h> | 12 | #include <linux/ext2_fs.h> |
| 13 | #include "xattr.h" | 13 | #include "xattr.h" |
| 14 | 14 | ||
| 15 | #define XATTR_TRUSTED_PREFIX "trusted." | ||
| 16 | |||
| 17 | static size_t | 15 | static size_t |
| 18 | ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, | 16 | ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, |
| 19 | const char *name, size_t name_len) | 17 | const char *name, size_t name_len) |
| 20 | { | 18 | { |
| 21 | const int prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1; | 19 | const int prefix_len = XATTR_TRUSTED_PREFIX_LEN; |
| 22 | const size_t total_len = prefix_len + name_len + 1; | 20 | const size_t total_len = prefix_len + name_len + 1; |
| 23 | 21 | ||
| 24 | if (!capable(CAP_SYS_ADMIN)) | 22 | if (!capable(CAP_SYS_ADMIN)) |
diff --git a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c index f383e7c3a7b5..92495d28c62f 100644 --- a/fs/ext2/xattr_user.c +++ b/fs/ext2/xattr_user.c | |||
| @@ -11,13 +11,11 @@ | |||
| 11 | #include "ext2.h" | 11 | #include "ext2.h" |
| 12 | #include "xattr.h" | 12 | #include "xattr.h" |
| 13 | 13 | ||
| 14 | #define XATTR_USER_PREFIX "user." | ||
| 15 | |||
| 16 | static size_t | 14 | static size_t |
| 17 | ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size, | 15 | ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size, |
| 18 | const char *name, size_t name_len) | 16 | const char *name, size_t name_len) |
| 19 | { | 17 | { |
| 20 | const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1; | 18 | const size_t prefix_len = XATTR_USER_PREFIX_LEN; |
| 21 | const size_t total_len = prefix_len + name_len + 1; | 19 | const size_t total_len = prefix_len + name_len + 1; |
| 22 | 20 | ||
| 23 | if (!test_opt(inode->i_sb, XATTR_USER)) | 21 | if (!test_opt(inode->i_sb, XATTR_USER)) |
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index a754d1848173..b60bb241880c 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
| @@ -299,7 +299,7 @@ ext3_check_acl(struct inode *inode, int mask) | |||
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | int | 301 | int |
| 302 | ext3_permission(struct inode *inode, int mask, struct nameidata *nd) | 302 | ext3_permission(struct inode *inode, int mask) |
| 303 | { | 303 | { |
| 304 | return generic_permission(inode, mask, ext3_check_acl); | 304 | return generic_permission(inode, mask, ext3_check_acl); |
| 305 | } | 305 | } |
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 0d1e6279cbfd..42da16b8cac0 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h | |||
| @@ -58,7 +58,7 @@ static inline int ext3_acl_count(size_t size) | |||
| 58 | #define EXT3_ACL_NOT_CACHED ((void *)-1) | 58 | #define EXT3_ACL_NOT_CACHED ((void *)-1) |
| 59 | 59 | ||
| 60 | /* acl.c */ | 60 | /* acl.c */ |
| 61 | extern int ext3_permission (struct inode *, int, struct nameidata *); | 61 | extern int ext3_permission (struct inode *, int); |
| 62 | extern int ext3_acl_chmod (struct inode *); | 62 | extern int ext3_acl_chmod (struct inode *); |
| 63 | extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); | 63 | extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); |
| 64 | 64 | ||
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 8ca3bfd72427..2eea96ec78ed 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c | |||
| @@ -272,7 +272,7 @@ static void free_rb_tree_fname(struct rb_root *root) | |||
| 272 | 272 | ||
| 273 | while (n) { | 273 | while (n) { |
| 274 | /* Do the node's children first */ | 274 | /* Do the node's children first */ |
| 275 | if ((n)->rb_left) { | 275 | if (n->rb_left) { |
| 276 | n = n->rb_left; | 276 | n = n->rb_left; |
| 277 | continue; | 277 | continue; |
| 278 | } | 278 | } |
| @@ -301,24 +301,18 @@ static void free_rb_tree_fname(struct rb_root *root) | |||
| 301 | parent->rb_right = NULL; | 301 | parent->rb_right = NULL; |
| 302 | n = parent; | 302 | n = parent; |
| 303 | } | 303 | } |
| 304 | root->rb_node = NULL; | ||
| 305 | } | 304 | } |
| 306 | 305 | ||
| 307 | 306 | ||
| 308 | static struct dir_private_info *create_dir_info(loff_t pos) | 307 | static struct dir_private_info *ext3_htree_create_dir_info(loff_t pos) |
| 309 | { | 308 | { |
| 310 | struct dir_private_info *p; | 309 | struct dir_private_info *p; |
| 311 | 310 | ||
| 312 | p = kmalloc(sizeof(struct dir_private_info), GFP_KERNEL); | 311 | p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL); |
| 313 | if (!p) | 312 | if (!p) |
| 314 | return NULL; | 313 | return NULL; |
| 315 | p->root.rb_node = NULL; | ||
| 316 | p->curr_node = NULL; | ||
| 317 | p->extra_fname = NULL; | ||
| 318 | p->last_pos = 0; | ||
| 319 | p->curr_hash = pos2maj_hash(pos); | 314 | p->curr_hash = pos2maj_hash(pos); |
| 320 | p->curr_minor_hash = pos2min_hash(pos); | 315 | p->curr_minor_hash = pos2min_hash(pos); |
| 321 | p->next_hash = 0; | ||
| 322 | return p; | 316 | return p; |
| 323 | } | 317 | } |
| 324 | 318 | ||
| @@ -433,7 +427,7 @@ static int ext3_dx_readdir(struct file * filp, | |||
| 433 | int ret; | 427 | int ret; |
| 434 | 428 | ||
| 435 | if (!info) { | 429 | if (!info) { |
| 436 | info = create_dir_info(filp->f_pos); | 430 | info = ext3_htree_create_dir_info(filp->f_pos); |
| 437 | if (!info) | 431 | if (!info) |
| 438 | return -ENOMEM; | 432 | return -ENOMEM; |
| 439 | filp->private_data = info; | 433 | filp->private_data = info; |
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 77126821b2e9..47b678d73e7a 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c | |||
| @@ -669,6 +669,14 @@ struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) | |||
| 669 | if (IS_ERR(inode)) | 669 | if (IS_ERR(inode)) |
| 670 | goto iget_failed; | 670 | goto iget_failed; |
| 671 | 671 | ||
| 672 | /* | ||
| 673 | * If the orphans has i_nlinks > 0 then it should be able to be | ||
| 674 | * truncated, otherwise it won't be removed from the orphan list | ||
| 675 | * during processing and an infinite loop will result. | ||
| 676 | */ | ||
| 677 | if (inode->i_nlink && !ext3_can_truncate(inode)) | ||
| 678 | goto bad_orphan; | ||
| 679 | |||
| 672 | if (NEXT_ORPHAN(inode) > max_ino) | 680 | if (NEXT_ORPHAN(inode) > max_ino) |
| 673 | goto bad_orphan; | 681 | goto bad_orphan; |
| 674 | brelse(bitmap_bh); | 682 | brelse(bitmap_bh); |
| @@ -690,6 +698,7 @@ bad_orphan: | |||
| 690 | printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n", | 698 | printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n", |
| 691 | NEXT_ORPHAN(inode)); | 699 | NEXT_ORPHAN(inode)); |
| 692 | printk(KERN_NOTICE "max_ino=%lu\n", max_ino); | 700 | printk(KERN_NOTICE "max_ino=%lu\n", max_ino); |
| 701 | printk(KERN_NOTICE "i_nlink=%u\n", inode->i_nlink); | ||
| 693 | /* Avoid freeing blocks if we got a bad deleted inode */ | 702 | /* Avoid freeing blocks if we got a bad deleted inode */ |
| 694 | if (inode->i_nlink == 0) | 703 | if (inode->i_nlink == 0) |
| 695 | inode->i_blocks = 0; | 704 | inode->i_blocks = 0; |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 6ae4ecf3ce40..507d8689b111 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
| @@ -1767,44 +1767,47 @@ static int ext3_journalled_set_page_dirty(struct page *page) | |||
| 1767 | } | 1767 | } |
| 1768 | 1768 | ||
| 1769 | static const struct address_space_operations ext3_ordered_aops = { | 1769 | static const struct address_space_operations ext3_ordered_aops = { |
| 1770 | .readpage = ext3_readpage, | 1770 | .readpage = ext3_readpage, |
| 1771 | .readpages = ext3_readpages, | 1771 | .readpages = ext3_readpages, |
| 1772 | .writepage = ext3_ordered_writepage, | 1772 | .writepage = ext3_ordered_writepage, |
| 1773 | .sync_page = block_sync_page, | 1773 | .sync_page = block_sync_page, |
| 1774 | .write_begin = ext3_write_begin, | 1774 | .write_begin = ext3_write_begin, |
| 1775 | .write_end = ext3_ordered_write_end, | 1775 | .write_end = ext3_ordered_write_end, |
| 1776 | .bmap = ext3_bmap, | 1776 | .bmap = ext3_bmap, |
| 1777 | .invalidatepage = ext3_invalidatepage, | 1777 | .invalidatepage = ext3_invalidatepage, |
| 1778 | .releasepage = ext3_releasepage, | 1778 | .releasepage = ext3_releasepage, |
| 1779 | .direct_IO = ext3_direct_IO, | 1779 | .direct_IO = ext3_direct_IO, |
| 1780 | .migratepage = buffer_migrate_page, | 1780 | .migratepage = buffer_migrate_page, |
| 1781 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 1781 | }; | 1782 | }; |
| 1782 | 1783 | ||
| 1783 | static const struct address_space_operations ext3_writeback_aops = { | 1784 | static const struct address_space_operations ext3_writeback_aops = { |
| 1784 | .readpage = ext3_readpage, | 1785 | .readpage = ext3_readpage, |
| 1785 | .readpages = ext3_readpages, | 1786 | .readpages = ext3_readpages, |
| 1786 | .writepage = ext3_writeback_writepage, | 1787 | .writepage = ext3_writeback_writepage, |
| 1787 | .sync_page = block_sync_page, | 1788 | .sync_page = block_sync_page, |
| 1788 | .write_begin = ext3_write_begin, | 1789 | .write_begin = ext3_write_begin, |
| 1789 | .write_end = ext3_writeback_write_end, | 1790 | .write_end = ext3_writeback_write_end, |
| 1790 | .bmap = ext3_bmap, | 1791 | .bmap = ext3_bmap, |
| 1791 | .invalidatepage = ext3_invalidatepage, | 1792 | .invalidatepage = ext3_invalidatepage, |
| 1792 | .releasepage = ext3_releasepage, | 1793 | .releasepage = ext3_releasepage, |
| 1793 | .direct_IO = ext3_direct_IO, | 1794 | .direct_IO = ext3_direct_IO, |
| 1794 | .migratepage = buffer_migrate_page, | 1795 | .migratepage = buffer_migrate_page, |
| 1796 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 1795 | }; | 1797 | }; |
| 1796 | 1798 | ||
| 1797 | static const struct address_space_operations ext3_journalled_aops = { | 1799 | static const struct address_space_operations ext3_journalled_aops = { |
| 1798 | .readpage = ext3_readpage, | 1800 | .readpage = ext3_readpage, |
| 1799 | .readpages = ext3_readpages, | 1801 | .readpages = ext3_readpages, |
| 1800 | .writepage = ext3_journalled_writepage, | 1802 | .writepage = ext3_journalled_writepage, |
| 1801 | .sync_page = block_sync_page, | 1803 | .sync_page = block_sync_page, |
| 1802 | .write_begin = ext3_write_begin, | 1804 | .write_begin = ext3_write_begin, |
| 1803 | .write_end = ext3_journalled_write_end, | 1805 | .write_end = ext3_journalled_write_end, |
| 1804 | .set_page_dirty = ext3_journalled_set_page_dirty, | 1806 | .set_page_dirty = ext3_journalled_set_page_dirty, |
| 1805 | .bmap = ext3_bmap, | 1807 | .bmap = ext3_bmap, |
| 1806 | .invalidatepage = ext3_invalidatepage, | 1808 | .invalidatepage = ext3_invalidatepage, |
| 1807 | .releasepage = ext3_releasepage, | 1809 | .releasepage = ext3_releasepage, |
| 1810 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 1808 | }; | 1811 | }; |
| 1809 | 1812 | ||
| 1810 | void ext3_set_aops(struct inode *inode) | 1813 | void ext3_set_aops(struct inode *inode) |
| @@ -2127,7 +2130,21 @@ static void ext3_free_data(handle_t *handle, struct inode *inode, | |||
| 2127 | 2130 | ||
| 2128 | if (this_bh) { | 2131 | if (this_bh) { |
| 2129 | BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); | 2132 | BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); |
| 2130 | ext3_journal_dirty_metadata(handle, this_bh); | 2133 | |
| 2134 | /* | ||
| 2135 | * The buffer head should have an attached journal head at this | ||
| 2136 | * point. However, if the data is corrupted and an indirect | ||
| 2137 | * block pointed to itself, it would have been detached when | ||
| 2138 | * the block was cleared. Check for this instead of OOPSing. | ||
| 2139 | */ | ||
| 2140 | if (bh2jh(this_bh)) | ||
| 2141 | ext3_journal_dirty_metadata(handle, this_bh); | ||
| 2142 | else | ||
| 2143 | ext3_error(inode->i_sb, "ext3_free_data", | ||
| 2144 | "circular indirect block detected, " | ||
| 2145 | "inode=%lu, block=%llu", | ||
| 2146 | inode->i_ino, | ||
| 2147 | (unsigned long long)this_bh->b_blocknr); | ||
| 2131 | } | 2148 | } |
| 2132 | } | 2149 | } |
| 2133 | 2150 | ||
| @@ -2253,6 +2270,19 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
| 2253 | } | 2270 | } |
| 2254 | } | 2271 | } |
| 2255 | 2272 | ||
| 2273 | int ext3_can_truncate(struct inode *inode) | ||
| 2274 | { | ||
| 2275 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
| 2276 | return 0; | ||
| 2277 | if (S_ISREG(inode->i_mode)) | ||
| 2278 | return 1; | ||
| 2279 | if (S_ISDIR(inode->i_mode)) | ||
| 2280 | return 1; | ||
| 2281 | if (S_ISLNK(inode->i_mode)) | ||
| 2282 | return !ext3_inode_is_fast_symlink(inode); | ||
| 2283 | return 0; | ||
| 2284 | } | ||
| 2285 | |||
| 2256 | /* | 2286 | /* |
| 2257 | * ext3_truncate() | 2287 | * ext3_truncate() |
| 2258 | * | 2288 | * |
| @@ -2297,12 +2327,7 @@ void ext3_truncate(struct inode *inode) | |||
| 2297 | unsigned blocksize = inode->i_sb->s_blocksize; | 2327 | unsigned blocksize = inode->i_sb->s_blocksize; |
| 2298 | struct page *page; | 2328 | struct page *page; |
| 2299 | 2329 | ||
| 2300 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 2330 | if (!ext3_can_truncate(inode)) |
| 2301 | S_ISLNK(inode->i_mode))) | ||
| 2302 | return; | ||
| 2303 | if (ext3_inode_is_fast_symlink(inode)) | ||
| 2304 | return; | ||
| 2305 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
| 2306 | return; | 2331 | return; |
| 2307 | 2332 | ||
| 2308 | /* | 2333 | /* |
| @@ -2513,6 +2538,16 @@ static int __ext3_get_inode_loc(struct inode *inode, | |||
| 2513 | } | 2538 | } |
| 2514 | if (!buffer_uptodate(bh)) { | 2539 | if (!buffer_uptodate(bh)) { |
| 2515 | lock_buffer(bh); | 2540 | lock_buffer(bh); |
| 2541 | |||
| 2542 | /* | ||
| 2543 | * If the buffer has the write error flag, we have failed | ||
| 2544 | * to write out another inode in the same block. In this | ||
| 2545 | * case, we don't have to read the block because we may | ||
| 2546 | * read the old inode data successfully. | ||
| 2547 | */ | ||
| 2548 | if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) | ||
| 2549 | set_buffer_uptodate(bh); | ||
| 2550 | |||
| 2516 | if (buffer_uptodate(bh)) { | 2551 | if (buffer_uptodate(bh)) { |
| 2517 | /* someone brought it uptodate while we waited */ | 2552 | /* someone brought it uptodate while we waited */ |
| 2518 | unlock_buffer(bh); | 2553 | unlock_buffer(bh); |
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 0b8cf80154f1..de13e919cd81 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
| @@ -240,13 +240,13 @@ static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize) | |||
| 240 | { | 240 | { |
| 241 | unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) - | 241 | unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) - |
| 242 | EXT3_DIR_REC_LEN(2) - infosize; | 242 | EXT3_DIR_REC_LEN(2) - infosize; |
| 243 | return 0? 20: entry_space / sizeof(struct dx_entry); | 243 | return entry_space / sizeof(struct dx_entry); |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | static inline unsigned dx_node_limit (struct inode *dir) | 246 | static inline unsigned dx_node_limit (struct inode *dir) |
| 247 | { | 247 | { |
| 248 | unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0); | 248 | unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0); |
| 249 | return 0? 22: entry_space / sizeof(struct dx_entry); | 249 | return entry_space / sizeof(struct dx_entry); |
| 250 | } | 250 | } |
| 251 | 251 | ||
| 252 | /* | 252 | /* |
| @@ -991,19 +991,21 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, | |||
| 991 | de = (struct ext3_dir_entry_2 *) bh->b_data; | 991 | de = (struct ext3_dir_entry_2 *) bh->b_data; |
| 992 | top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize - | 992 | top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_blocksize - |
| 993 | EXT3_DIR_REC_LEN(0)); | 993 | EXT3_DIR_REC_LEN(0)); |
| 994 | for (; de < top; de = ext3_next_entry(de)) | 994 | for (; de < top; de = ext3_next_entry(de)) { |
| 995 | if (ext3_match (namelen, name, de)) { | 995 | int off = (block << EXT3_BLOCK_SIZE_BITS(sb)) |
| 996 | if (!ext3_check_dir_entry("ext3_find_entry", | 996 | + ((char *) de - bh->b_data); |
| 997 | dir, de, bh, | 997 | |
| 998 | (block<<EXT3_BLOCK_SIZE_BITS(sb)) | 998 | if (!ext3_check_dir_entry(__func__, dir, de, bh, off)) { |
| 999 | +((char *)de - bh->b_data))) { | 999 | brelse(bh); |
| 1000 | brelse (bh); | ||
| 1001 | *err = ERR_BAD_DX_DIR; | 1000 | *err = ERR_BAD_DX_DIR; |
| 1002 | goto errout; | 1001 | goto errout; |
| 1003 | } | 1002 | } |
| 1004 | *res_dir = de; | 1003 | |
| 1005 | dx_release (frames); | 1004 | if (ext3_match(namelen, name, de)) { |
| 1006 | return bh; | 1005 | *res_dir = de; |
| 1006 | dx_release(frames); | ||
| 1007 | return bh; | ||
| 1008 | } | ||
| 1007 | } | 1009 | } |
| 1008 | brelse (bh); | 1010 | brelse (bh); |
| 1009 | /* Check to see if we should continue to search */ | 1011 | /* Check to see if we should continue to search */ |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 2845425077e8..f38a5afc39a1 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -472,7 +472,7 @@ static void ext3_destroy_inode(struct inode *inode) | |||
| 472 | kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); | 472 | kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | static void init_once(struct kmem_cache * cachep, void *foo) | 475 | static void init_once(void *foo) |
| 476 | { | 476 | { |
| 477 | struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; | 477 | struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; |
| 478 | 478 | ||
| @@ -842,7 +842,7 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 842 | int data_opt = 0; | 842 | int data_opt = 0; |
| 843 | int option; | 843 | int option; |
| 844 | #ifdef CONFIG_QUOTA | 844 | #ifdef CONFIG_QUOTA |
| 845 | int qtype; | 845 | int qtype, qfmt; |
| 846 | char *qname; | 846 | char *qname; |
| 847 | #endif | 847 | #endif |
| 848 | 848 | ||
| @@ -1018,9 +1018,11 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1018 | case Opt_grpjquota: | 1018 | case Opt_grpjquota: |
| 1019 | qtype = GRPQUOTA; | 1019 | qtype = GRPQUOTA; |
| 1020 | set_qf_name: | 1020 | set_qf_name: |
| 1021 | if (sb_any_quota_enabled(sb)) { | 1021 | if ((sb_any_quota_enabled(sb) || |
| 1022 | sb_any_quota_suspended(sb)) && | ||
| 1023 | !sbi->s_qf_names[qtype]) { | ||
| 1022 | printk(KERN_ERR | 1024 | printk(KERN_ERR |
| 1023 | "EXT3-fs: Cannot change journalled " | 1025 | "EXT3-fs: Cannot change journaled " |
| 1024 | "quota options when quota turned on.\n"); | 1026 | "quota options when quota turned on.\n"); |
| 1025 | return 0; | 1027 | return 0; |
| 1026 | } | 1028 | } |
| @@ -1056,9 +1058,11 @@ set_qf_name: | |||
| 1056 | case Opt_offgrpjquota: | 1058 | case Opt_offgrpjquota: |
| 1057 | qtype = GRPQUOTA; | 1059 | qtype = GRPQUOTA; |
| 1058 | clear_qf_name: | 1060 | clear_qf_name: |
| 1059 | if (sb_any_quota_enabled(sb)) { | 1061 | if ((sb_any_quota_enabled(sb) || |
| 1062 | sb_any_quota_suspended(sb)) && | ||
| 1063 | sbi->s_qf_names[qtype]) { | ||
| 1060 | printk(KERN_ERR "EXT3-fs: Cannot change " | 1064 | printk(KERN_ERR "EXT3-fs: Cannot change " |
| 1061 | "journalled quota options when " | 1065 | "journaled quota options when " |
| 1062 | "quota turned on.\n"); | 1066 | "quota turned on.\n"); |
| 1063 | return 0; | 1067 | return 0; |
| 1064 | } | 1068 | } |
| @@ -1069,10 +1073,20 @@ clear_qf_name: | |||
| 1069 | sbi->s_qf_names[qtype] = NULL; | 1073 | sbi->s_qf_names[qtype] = NULL; |
| 1070 | break; | 1074 | break; |
| 1071 | case Opt_jqfmt_vfsold: | 1075 | case Opt_jqfmt_vfsold: |
| 1072 | sbi->s_jquota_fmt = QFMT_VFS_OLD; | 1076 | qfmt = QFMT_VFS_OLD; |
| 1073 | break; | 1077 | goto set_qf_format; |
| 1074 | case Opt_jqfmt_vfsv0: | 1078 | case Opt_jqfmt_vfsv0: |
| 1075 | sbi->s_jquota_fmt = QFMT_VFS_V0; | 1079 | qfmt = QFMT_VFS_V0; |
| 1080 | set_qf_format: | ||
| 1081 | if ((sb_any_quota_enabled(sb) || | ||
| 1082 | sb_any_quota_suspended(sb)) && | ||
| 1083 | sbi->s_jquota_fmt != qfmt) { | ||
| 1084 | printk(KERN_ERR "EXT3-fs: Cannot change " | ||
| 1085 | "journaled quota options when " | ||
| 1086 | "quota turned on.\n"); | ||
| 1087 | return 0; | ||
| 1088 | } | ||
| 1089 | sbi->s_jquota_fmt = qfmt; | ||
| 1076 | break; | 1090 | break; |
| 1077 | case Opt_quota: | 1091 | case Opt_quota: |
| 1078 | case Opt_usrquota: | 1092 | case Opt_usrquota: |
| @@ -1084,7 +1098,8 @@ clear_qf_name: | |||
| 1084 | set_opt(sbi->s_mount_opt, GRPQUOTA); | 1098 | set_opt(sbi->s_mount_opt, GRPQUOTA); |
| 1085 | break; | 1099 | break; |
| 1086 | case Opt_noquota: | 1100 | case Opt_noquota: |
| 1087 | if (sb_any_quota_enabled(sb)) { | 1101 | if (sb_any_quota_enabled(sb) || |
| 1102 | sb_any_quota_suspended(sb)) { | ||
| 1088 | printk(KERN_ERR "EXT3-fs: Cannot change quota " | 1103 | printk(KERN_ERR "EXT3-fs: Cannot change quota " |
| 1089 | "options when quota turned on.\n"); | 1104 | "options when quota turned on.\n"); |
| 1090 | return 0; | 1105 | return 0; |
| @@ -1169,14 +1184,14 @@ clear_qf_name: | |||
| 1169 | } | 1184 | } |
| 1170 | 1185 | ||
| 1171 | if (!sbi->s_jquota_fmt) { | 1186 | if (!sbi->s_jquota_fmt) { |
| 1172 | printk(KERN_ERR "EXT3-fs: journalled quota format " | 1187 | printk(KERN_ERR "EXT3-fs: journaled quota format " |
| 1173 | "not specified.\n"); | 1188 | "not specified.\n"); |
| 1174 | return 0; | 1189 | return 0; |
| 1175 | } | 1190 | } |
| 1176 | } else { | 1191 | } else { |
| 1177 | if (sbi->s_jquota_fmt) { | 1192 | if (sbi->s_jquota_fmt) { |
| 1178 | printk(KERN_ERR "EXT3-fs: journalled quota format " | 1193 | printk(KERN_ERR "EXT3-fs: journaled quota format " |
| 1179 | "specified with no journalling " | 1194 | "specified with no journaling " |
| 1180 | "enabled.\n"); | 1195 | "enabled.\n"); |
| 1181 | return 0; | 1196 | return 0; |
| 1182 | } | 1197 | } |
| @@ -1370,7 +1385,7 @@ static void ext3_orphan_cleanup (struct super_block * sb, | |||
| 1370 | int ret = ext3_quota_on_mount(sb, i); | 1385 | int ret = ext3_quota_on_mount(sb, i); |
| 1371 | if (ret < 0) | 1386 | if (ret < 0) |
| 1372 | printk(KERN_ERR | 1387 | printk(KERN_ERR |
| 1373 | "EXT3-fs: Cannot turn on journalled " | 1388 | "EXT3-fs: Cannot turn on journaled " |
| 1374 | "quota: error %d\n", ret); | 1389 | "quota: error %d\n", ret); |
| 1375 | } | 1390 | } |
| 1376 | } | 1391 | } |
| @@ -2712,7 +2727,7 @@ static int ext3_release_dquot(struct dquot *dquot) | |||
| 2712 | 2727 | ||
| 2713 | static int ext3_mark_dquot_dirty(struct dquot *dquot) | 2728 | static int ext3_mark_dquot_dirty(struct dquot *dquot) |
| 2714 | { | 2729 | { |
| 2715 | /* Are we journalling quotas? */ | 2730 | /* Are we journaling quotas? */ |
| 2716 | if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || | 2731 | if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || |
| 2717 | EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { | 2732 | EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { |
| 2718 | dquot_mark_dquot_dirty(dquot); | 2733 | dquot_mark_dquot_dirty(dquot); |
| @@ -2759,25 +2774,45 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2759 | 2774 | ||
| 2760 | if (!test_opt(sb, QUOTA)) | 2775 | if (!test_opt(sb, QUOTA)) |
| 2761 | return -EINVAL; | 2776 | return -EINVAL; |
| 2762 | /* Not journalling quota or remount? */ | 2777 | /* When remounting, no checks are needed and in fact, path is NULL */ |
| 2763 | if ((!EXT3_SB(sb)->s_qf_names[USRQUOTA] && | 2778 | if (remount) |
| 2764 | !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) || remount) | ||
| 2765 | return vfs_quota_on(sb, type, format_id, path, remount); | 2779 | return vfs_quota_on(sb, type, format_id, path, remount); |
| 2780 | |||
| 2766 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); | 2781 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); |
| 2767 | if (err) | 2782 | if (err) |
| 2768 | return err; | 2783 | return err; |
| 2784 | |||
| 2769 | /* Quotafile not on the same filesystem? */ | 2785 | /* Quotafile not on the same filesystem? */ |
| 2770 | if (nd.path.mnt->mnt_sb != sb) { | 2786 | if (nd.path.mnt->mnt_sb != sb) { |
| 2771 | path_put(&nd.path); | 2787 | path_put(&nd.path); |
| 2772 | return -EXDEV; | 2788 | return -EXDEV; |
| 2773 | } | 2789 | } |
| 2774 | /* Quotafile not in fs root? */ | 2790 | /* Journaling quota? */ |
| 2775 | if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) | 2791 | if (EXT3_SB(sb)->s_qf_names[type]) { |
| 2776 | printk(KERN_WARNING | 2792 | /* Quotafile not of fs root? */ |
| 2777 | "EXT3-fs: Quota file not on filesystem root. " | 2793 | if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) |
| 2778 | "Journalled quota will not work.\n"); | 2794 | printk(KERN_WARNING |
| 2795 | "EXT3-fs: Quota file not on filesystem root. " | ||
| 2796 | "Journaled quota will not work.\n"); | ||
| 2797 | } | ||
| 2798 | |||
| 2799 | /* | ||
| 2800 | * When we journal data on quota file, we have to flush journal to see | ||
| 2801 | * all updates to the file when we bypass pagecache... | ||
| 2802 | */ | ||
| 2803 | if (ext3_should_journal_data(nd.path.dentry->d_inode)) { | ||
| 2804 | /* | ||
| 2805 | * We don't need to lock updates but journal_flush() could | ||
| 2806 | * otherwise be livelocked... | ||
| 2807 | */ | ||
| 2808 | journal_lock_updates(EXT3_SB(sb)->s_journal); | ||
| 2809 | journal_flush(EXT3_SB(sb)->s_journal); | ||
| 2810 | journal_unlock_updates(EXT3_SB(sb)->s_journal); | ||
| 2811 | } | ||
| 2812 | |||
| 2813 | err = vfs_quota_on_path(sb, type, format_id, &nd.path); | ||
| 2779 | path_put(&nd.path); | 2814 | path_put(&nd.path); |
| 2780 | return vfs_quota_on(sb, type, format_id, path, remount); | 2815 | return err; |
| 2781 | } | 2816 | } |
| 2782 | 2817 | ||
| 2783 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 2818 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c index 821efaf2b94e..37b81097bdf2 100644 --- a/fs/ext3/xattr_security.c +++ b/fs/ext3/xattr_security.c | |||
| @@ -15,7 +15,7 @@ static size_t | |||
| 15 | ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, | 15 | ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, |
| 16 | const char *name, size_t name_len) | 16 | const char *name, size_t name_len) |
| 17 | { | 17 | { |
| 18 | const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; | 18 | const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN; |
| 19 | const size_t total_len = prefix_len + name_len + 1; | 19 | const size_t total_len = prefix_len + name_len + 1; |
| 20 | 20 | ||
| 21 | 21 | ||
diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c index 0327497a55ce..c7c41a410c4b 100644 --- a/fs/ext3/xattr_trusted.c +++ b/fs/ext3/xattr_trusted.c | |||
| @@ -13,13 +13,11 @@ | |||
| 13 | #include <linux/ext3_fs.h> | 13 | #include <linux/ext3_fs.h> |
| 14 | #include "xattr.h" | 14 | #include "xattr.h" |
| 15 | 15 | ||
| 16 | #define XATTR_TRUSTED_PREFIX "trusted." | ||
| 17 | |||
| 18 | static size_t | 16 | static size_t |
| 19 | ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, | 17 | ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, |
| 20 | const char *name, size_t name_len) | 18 | const char *name, size_t name_len) |
| 21 | { | 19 | { |
| 22 | const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1; | 20 | const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; |
| 23 | const size_t total_len = prefix_len + name_len + 1; | 21 | const size_t total_len = prefix_len + name_len + 1; |
| 24 | 22 | ||
| 25 | if (!capable(CAP_SYS_ADMIN)) | 23 | if (!capable(CAP_SYS_ADMIN)) |
diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c index 1abd8f92c440..430fe63b31b3 100644 --- a/fs/ext3/xattr_user.c +++ b/fs/ext3/xattr_user.c | |||
| @@ -12,13 +12,11 @@ | |||
| 12 | #include <linux/ext3_fs.h> | 12 | #include <linux/ext3_fs.h> |
| 13 | #include "xattr.h" | 13 | #include "xattr.h" |
| 14 | 14 | ||
| 15 | #define XATTR_USER_PREFIX "user." | ||
| 16 | |||
| 17 | static size_t | 15 | static size_t |
| 18 | ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, | 16 | ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, |
| 19 | const char *name, size_t name_len) | 17 | const char *name, size_t name_len) |
| 20 | { | 18 | { |
| 21 | const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1; | 19 | const size_t prefix_len = XATTR_USER_PREFIX_LEN; |
| 22 | const size_t total_len = prefix_len + name_len + 1; | 20 | const size_t total_len = prefix_len + name_len + 1; |
| 23 | 21 | ||
| 24 | if (!test_opt(inode->i_sb, XATTR_USER)) | 22 | if (!test_opt(inode->i_sb, XATTR_USER)) |
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 3c8dab880d91..694ed6fadcc8 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
| @@ -40,34 +40,35 @@ ext4_acl_from_disk(const void *value, size_t size) | |||
| 40 | acl = posix_acl_alloc(count, GFP_NOFS); | 40 | acl = posix_acl_alloc(count, GFP_NOFS); |
| 41 | if (!acl) | 41 | if (!acl) |
| 42 | return ERR_PTR(-ENOMEM); | 42 | return ERR_PTR(-ENOMEM); |
| 43 | for (n=0; n < count; n++) { | 43 | for (n = 0; n < count; n++) { |
| 44 | ext4_acl_entry *entry = | 44 | ext4_acl_entry *entry = |
| 45 | (ext4_acl_entry *)value; | 45 | (ext4_acl_entry *)value; |
| 46 | if ((char *)value + sizeof(ext4_acl_entry_short) > end) | 46 | if ((char *)value + sizeof(ext4_acl_entry_short) > end) |
| 47 | goto fail; | 47 | goto fail; |
| 48 | acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); | 48 | acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); |
| 49 | acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); | 49 | acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); |
| 50 | switch(acl->a_entries[n].e_tag) { | 50 | |
| 51 | case ACL_USER_OBJ: | 51 | switch (acl->a_entries[n].e_tag) { |
| 52 | case ACL_GROUP_OBJ: | 52 | case ACL_USER_OBJ: |
| 53 | case ACL_MASK: | 53 | case ACL_GROUP_OBJ: |
| 54 | case ACL_OTHER: | 54 | case ACL_MASK: |
| 55 | value = (char *)value + | 55 | case ACL_OTHER: |
| 56 | sizeof(ext4_acl_entry_short); | 56 | value = (char *)value + |
| 57 | acl->a_entries[n].e_id = ACL_UNDEFINED_ID; | 57 | sizeof(ext4_acl_entry_short); |
| 58 | break; | 58 | acl->a_entries[n].e_id = ACL_UNDEFINED_ID; |
| 59 | 59 | break; | |
| 60 | case ACL_USER: | 60 | |
| 61 | case ACL_GROUP: | 61 | case ACL_USER: |
| 62 | value = (char *)value + sizeof(ext4_acl_entry); | 62 | case ACL_GROUP: |
| 63 | if ((char *)value > end) | 63 | value = (char *)value + sizeof(ext4_acl_entry); |
| 64 | goto fail; | 64 | if ((char *)value > end) |
| 65 | acl->a_entries[n].e_id = | ||
| 66 | le32_to_cpu(entry->e_id); | ||
| 67 | break; | ||
| 68 | |||
| 69 | default: | ||
| 70 | goto fail; | 65 | goto fail; |
| 66 | acl->a_entries[n].e_id = | ||
| 67 | le32_to_cpu(entry->e_id); | ||
| 68 | break; | ||
| 69 | |||
| 70 | default: | ||
| 71 | goto fail; | ||
| 71 | } | 72 | } |
| 72 | } | 73 | } |
| 73 | if (value != end) | 74 | if (value != end) |
| @@ -96,27 +97,26 @@ ext4_acl_to_disk(const struct posix_acl *acl, size_t *size) | |||
| 96 | return ERR_PTR(-ENOMEM); | 97 | return ERR_PTR(-ENOMEM); |
| 97 | ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION); | 98 | ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION); |
| 98 | e = (char *)ext_acl + sizeof(ext4_acl_header); | 99 | e = (char *)ext_acl + sizeof(ext4_acl_header); |
| 99 | for (n=0; n < acl->a_count; n++) { | 100 | for (n = 0; n < acl->a_count; n++) { |
| 100 | ext4_acl_entry *entry = (ext4_acl_entry *)e; | 101 | ext4_acl_entry *entry = (ext4_acl_entry *)e; |
| 101 | entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); | 102 | entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); |
| 102 | entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); | 103 | entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); |
| 103 | switch(acl->a_entries[n].e_tag) { | 104 | switch (acl->a_entries[n].e_tag) { |
| 104 | case ACL_USER: | 105 | case ACL_USER: |
| 105 | case ACL_GROUP: | 106 | case ACL_GROUP: |
| 106 | entry->e_id = | 107 | entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); |
| 107 | cpu_to_le32(acl->a_entries[n].e_id); | 108 | e += sizeof(ext4_acl_entry); |
| 108 | e += sizeof(ext4_acl_entry); | 109 | break; |
| 109 | break; | 110 | |
| 110 | 111 | case ACL_USER_OBJ: | |
| 111 | case ACL_USER_OBJ: | 112 | case ACL_GROUP_OBJ: |
| 112 | case ACL_GROUP_OBJ: | 113 | case ACL_MASK: |
| 113 | case ACL_MASK: | 114 | case ACL_OTHER: |
| 114 | case ACL_OTHER: | 115 | e += sizeof(ext4_acl_entry_short); |
| 115 | e += sizeof(ext4_acl_entry_short); | 116 | break; |
| 116 | break; | 117 | |
| 117 | 118 | default: | |
| 118 | default: | 119 | goto fail; |
| 119 | goto fail; | ||
| 120 | } | 120 | } |
| 121 | } | 121 | } |
| 122 | return (char *)ext_acl; | 122 | return (char *)ext_acl; |
| @@ -167,23 +167,23 @@ ext4_get_acl(struct inode *inode, int type) | |||
| 167 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 167 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
| 168 | return NULL; | 168 | return NULL; |
| 169 | 169 | ||
| 170 | switch(type) { | 170 | switch (type) { |
| 171 | case ACL_TYPE_ACCESS: | 171 | case ACL_TYPE_ACCESS: |
| 172 | acl = ext4_iget_acl(inode, &ei->i_acl); | 172 | acl = ext4_iget_acl(inode, &ei->i_acl); |
| 173 | if (acl != EXT4_ACL_NOT_CACHED) | 173 | if (acl != EXT4_ACL_NOT_CACHED) |
| 174 | return acl; | 174 | return acl; |
| 175 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; | 175 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; |
| 176 | break; | 176 | break; |
| 177 | 177 | ||
| 178 | case ACL_TYPE_DEFAULT: | 178 | case ACL_TYPE_DEFAULT: |
| 179 | acl = ext4_iget_acl(inode, &ei->i_default_acl); | 179 | acl = ext4_iget_acl(inode, &ei->i_default_acl); |
| 180 | if (acl != EXT4_ACL_NOT_CACHED) | 180 | if (acl != EXT4_ACL_NOT_CACHED) |
| 181 | return acl; | 181 | return acl; |
| 182 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; | 182 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; |
| 183 | break; | 183 | break; |
| 184 | 184 | ||
| 185 | default: | 185 | default: |
| 186 | return ERR_PTR(-EINVAL); | 186 | return ERR_PTR(-EINVAL); |
| 187 | } | 187 | } |
| 188 | retval = ext4_xattr_get(inode, name_index, "", NULL, 0); | 188 | retval = ext4_xattr_get(inode, name_index, "", NULL, 0); |
| 189 | if (retval > 0) { | 189 | if (retval > 0) { |
| @@ -201,14 +201,14 @@ ext4_get_acl(struct inode *inode, int type) | |||
| 201 | kfree(value); | 201 | kfree(value); |
| 202 | 202 | ||
| 203 | if (!IS_ERR(acl)) { | 203 | if (!IS_ERR(acl)) { |
| 204 | switch(type) { | 204 | switch (type) { |
| 205 | case ACL_TYPE_ACCESS: | 205 | case ACL_TYPE_ACCESS: |
| 206 | ext4_iset_acl(inode, &ei->i_acl, acl); | 206 | ext4_iset_acl(inode, &ei->i_acl, acl); |
| 207 | break; | 207 | break; |
| 208 | 208 | ||
| 209 | case ACL_TYPE_DEFAULT: | 209 | case ACL_TYPE_DEFAULT: |
| 210 | ext4_iset_acl(inode, &ei->i_default_acl, acl); | 210 | ext4_iset_acl(inode, &ei->i_default_acl, acl); |
| 211 | break; | 211 | break; |
| 212 | } | 212 | } |
| 213 | } | 213 | } |
| 214 | return acl; | 214 | return acl; |
| @@ -232,31 +232,31 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, | |||
| 232 | if (S_ISLNK(inode->i_mode)) | 232 | if (S_ISLNK(inode->i_mode)) |
| 233 | return -EOPNOTSUPP; | 233 | return -EOPNOTSUPP; |
| 234 | 234 | ||
| 235 | switch(type) { | 235 | switch (type) { |
| 236 | case ACL_TYPE_ACCESS: | 236 | case ACL_TYPE_ACCESS: |
| 237 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; | 237 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; |
| 238 | if (acl) { | 238 | if (acl) { |
| 239 | mode_t mode = inode->i_mode; | 239 | mode_t mode = inode->i_mode; |
| 240 | error = posix_acl_equiv_mode(acl, &mode); | 240 | error = posix_acl_equiv_mode(acl, &mode); |
| 241 | if (error < 0) | 241 | if (error < 0) |
| 242 | return error; | 242 | return error; |
| 243 | else { | 243 | else { |
| 244 | inode->i_mode = mode; | 244 | inode->i_mode = mode; |
| 245 | ext4_mark_inode_dirty(handle, inode); | 245 | ext4_mark_inode_dirty(handle, inode); |
| 246 | if (error == 0) | 246 | if (error == 0) |
| 247 | acl = NULL; | 247 | acl = NULL; |
| 248 | } | ||
| 249 | } | 248 | } |
| 250 | break; | 249 | } |
| 250 | break; | ||
| 251 | 251 | ||
| 252 | case ACL_TYPE_DEFAULT: | 252 | case ACL_TYPE_DEFAULT: |
| 253 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; | 253 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; |
| 254 | if (!S_ISDIR(inode->i_mode)) | 254 | if (!S_ISDIR(inode->i_mode)) |
| 255 | return acl ? -EACCES : 0; | 255 | return acl ? -EACCES : 0; |
| 256 | break; | 256 | break; |
| 257 | 257 | ||
| 258 | default: | 258 | default: |
| 259 | return -EINVAL; | 259 | return -EINVAL; |
| 260 | } | 260 | } |
| 261 | if (acl) { | 261 | if (acl) { |
| 262 | value = ext4_acl_to_disk(acl, &size); | 262 | value = ext4_acl_to_disk(acl, &size); |
| @@ -269,14 +269,14 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, | |||
| 269 | 269 | ||
| 270 | kfree(value); | 270 | kfree(value); |
| 271 | if (!error) { | 271 | if (!error) { |
| 272 | switch(type) { | 272 | switch (type) { |
| 273 | case ACL_TYPE_ACCESS: | 273 | case ACL_TYPE_ACCESS: |
| 274 | ext4_iset_acl(inode, &ei->i_acl, acl); | 274 | ext4_iset_acl(inode, &ei->i_acl, acl); |
| 275 | break; | 275 | break; |
| 276 | 276 | ||
| 277 | case ACL_TYPE_DEFAULT: | 277 | case ACL_TYPE_DEFAULT: |
| 278 | ext4_iset_acl(inode, &ei->i_default_acl, acl); | 278 | ext4_iset_acl(inode, &ei->i_default_acl, acl); |
| 279 | break; | 279 | break; |
| 280 | } | 280 | } |
| 281 | } | 281 | } |
| 282 | return error; | 282 | return error; |
| @@ -299,7 +299,7 @@ ext4_check_acl(struct inode *inode, int mask) | |||
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | int | 301 | int |
| 302 | ext4_permission(struct inode *inode, int mask, struct nameidata *nd) | 302 | ext4_permission(struct inode *inode, int mask) |
| 303 | { | 303 | { |
| 304 | return generic_permission(inode, mask, ext4_check_acl); | 304 | return generic_permission(inode, mask, ext4_check_acl); |
| 305 | } | 305 | } |
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 26a5c1abf147..cd2b855a07d6 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h | |||
| @@ -58,7 +58,7 @@ static inline int ext4_acl_count(size_t size) | |||
| 58 | #define EXT4_ACL_NOT_CACHED ((void *)-1) | 58 | #define EXT4_ACL_NOT_CACHED ((void *)-1) |
| 59 | 59 | ||
| 60 | /* acl.c */ | 60 | /* acl.c */ |
| 61 | extern int ext4_permission (struct inode *, int, struct nameidata *); | 61 | extern int ext4_permission (struct inode *, int); |
| 62 | extern int ext4_acl_chmod (struct inode *); | 62 | extern int ext4_acl_chmod (struct inode *); |
| 63 | extern int ext4_init_acl (handle_t *, struct inode *, struct inode *); | 63 | extern int ext4_init_acl (handle_t *, struct inode *, struct inode *); |
| 64 | 64 | ||
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 495ab21b9832..e9fa960ba6da 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
| @@ -314,25 +314,28 @@ ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
| 314 | if (unlikely(!bh)) { | 314 | if (unlikely(!bh)) { |
| 315 | ext4_error(sb, __func__, | 315 | ext4_error(sb, __func__, |
| 316 | "Cannot read block bitmap - " | 316 | "Cannot read block bitmap - " |
| 317 | "block_group = %d, block_bitmap = %llu", | 317 | "block_group = %lu, block_bitmap = %llu", |
| 318 | (int)block_group, (unsigned long long)bitmap_blk); | 318 | block_group, bitmap_blk); |
| 319 | return NULL; | 319 | return NULL; |
| 320 | } | 320 | } |
| 321 | if (bh_uptodate_or_lock(bh)) | 321 | if (bh_uptodate_or_lock(bh)) |
| 322 | return bh; | 322 | return bh; |
| 323 | 323 | ||
| 324 | spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group)); | ||
| 324 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 325 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
| 325 | ext4_init_block_bitmap(sb, bh, block_group, desc); | 326 | ext4_init_block_bitmap(sb, bh, block_group, desc); |
| 326 | set_buffer_uptodate(bh); | 327 | set_buffer_uptodate(bh); |
| 327 | unlock_buffer(bh); | 328 | unlock_buffer(bh); |
| 329 | spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); | ||
| 328 | return bh; | 330 | return bh; |
| 329 | } | 331 | } |
| 332 | spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); | ||
| 330 | if (bh_submit_read(bh) < 0) { | 333 | if (bh_submit_read(bh) < 0) { |
| 331 | put_bh(bh); | 334 | put_bh(bh); |
| 332 | ext4_error(sb, __func__, | 335 | ext4_error(sb, __func__, |
| 333 | "Cannot read block bitmap - " | 336 | "Cannot read block bitmap - " |
| 334 | "block_group = %d, block_bitmap = %llu", | 337 | "block_group = %lu, block_bitmap = %llu", |
| 335 | (int)block_group, (unsigned long long)bitmap_blk); | 338 | block_group, bitmap_blk); |
| 336 | return NULL; | 339 | return NULL; |
| 337 | } | 340 | } |
| 338 | ext4_valid_block_bitmap(sb, desc, block_group, bh); | 341 | ext4_valid_block_bitmap(sb, desc, block_group, bh); |
| @@ -1623,6 +1626,9 @@ ext4_fsblk_t ext4_has_free_blocks(struct ext4_sb_info *sbi, | |||
| 1623 | free_blocks = | 1626 | free_blocks = |
| 1624 | percpu_counter_sum_and_set(&sbi->s_freeblocks_counter); | 1627 | percpu_counter_sum_and_set(&sbi->s_freeblocks_counter); |
| 1625 | #endif | 1628 | #endif |
| 1629 | if (free_blocks <= root_blocks) | ||
| 1630 | /* we don't have free space */ | ||
| 1631 | return 0; | ||
| 1626 | if (free_blocks - root_blocks < nblocks) | 1632 | if (free_blocks - root_blocks < nblocks) |
| 1627 | return free_blocks - root_blocks; | 1633 | return free_blocks - root_blocks; |
| 1628 | return nblocks; | 1634 | return nblocks; |
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index d3d23d73c08b..ec8e33b45219 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
| @@ -411,7 +411,7 @@ static int call_filldir(struct file * filp, void * dirent, | |||
| 411 | get_dtype(sb, fname->file_type)); | 411 | get_dtype(sb, fname->file_type)); |
| 412 | if (error) { | 412 | if (error) { |
| 413 | filp->f_pos = curr_pos; | 413 | filp->f_pos = curr_pos; |
| 414 | info->extra_fname = fname->next; | 414 | info->extra_fname = fname; |
| 415 | return error; | 415 | return error; |
| 416 | } | 416 | } |
| 417 | fname = fname->next; | 417 | fname = fname->next; |
| @@ -450,11 +450,21 @@ static int ext4_dx_readdir(struct file * filp, | |||
| 450 | * If there are any leftover names on the hash collision | 450 | * If there are any leftover names on the hash collision |
| 451 | * chain, return them first. | 451 | * chain, return them first. |
| 452 | */ | 452 | */ |
| 453 | if (info->extra_fname && | 453 | if (info->extra_fname) { |
| 454 | call_filldir(filp, dirent, filldir, info->extra_fname)) | 454 | if (call_filldir(filp, dirent, filldir, info->extra_fname)) |
| 455 | goto finished; | 455 | goto finished; |
| 456 | 456 | ||
| 457 | if (!info->curr_node) | 457 | info->extra_fname = NULL; |
| 458 | info->curr_node = rb_next(info->curr_node); | ||
| 459 | if (!info->curr_node) { | ||
| 460 | if (info->next_hash == ~0) { | ||
| 461 | filp->f_pos = EXT4_HTREE_EOF; | ||
| 462 | goto finished; | ||
| 463 | } | ||
| 464 | info->curr_hash = info->next_hash; | ||
| 465 | info->curr_minor_hash = 0; | ||
| 466 | } | ||
| 467 | } else if (!info->curr_node) | ||
| 458 | info->curr_node = rb_first(&info->root); | 468 | info->curr_node = rb_first(&info->root); |
| 459 | 469 | ||
| 460 | while (1) { | 470 | while (1) { |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 303e41cf7b14..295003241d3d 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -1044,7 +1044,6 @@ extern void ext4_mb_update_group_info(struct ext4_group_info *grp, | |||
| 1044 | 1044 | ||
| 1045 | 1045 | ||
| 1046 | /* inode.c */ | 1046 | /* inode.c */ |
| 1047 | void ext4_da_release_space(struct inode *inode, int used, int to_free); | ||
| 1048 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, | 1047 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, |
| 1049 | struct buffer_head *bh, ext4_fsblk_t blocknr); | 1048 | struct buffer_head *bh, ext4_fsblk_t blocknr); |
| 1050 | struct buffer_head *ext4_getblk(handle_t *, struct inode *, | 1049 | struct buffer_head *ext4_getblk(handle_t *, struct inode *, |
| @@ -1073,6 +1072,8 @@ extern void ext4_set_inode_flags(struct inode *); | |||
| 1073 | extern void ext4_get_inode_flags(struct ext4_inode_info *); | 1072 | extern void ext4_get_inode_flags(struct ext4_inode_info *); |
| 1074 | extern void ext4_set_aops(struct inode *inode); | 1073 | extern void ext4_set_aops(struct inode *inode); |
| 1075 | extern int ext4_writepage_trans_blocks(struct inode *); | 1074 | extern int ext4_writepage_trans_blocks(struct inode *); |
| 1075 | extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int idxblocks); | ||
| 1076 | extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); | ||
| 1076 | extern int ext4_block_truncate_page(handle_t *handle, | 1077 | extern int ext4_block_truncate_page(handle_t *handle, |
| 1077 | struct address_space *mapping, loff_t from); | 1078 | struct address_space *mapping, loff_t from); |
| 1078 | extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page); | 1079 | extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct page *page); |
| @@ -1228,6 +1229,8 @@ extern const struct inode_operations ext4_fast_symlink_inode_operations; | |||
| 1228 | /* extents.c */ | 1229 | /* extents.c */ |
| 1229 | extern int ext4_ext_tree_init(handle_t *handle, struct inode *); | 1230 | extern int ext4_ext_tree_init(handle_t *handle, struct inode *); |
| 1230 | extern int ext4_ext_writepage_trans_blocks(struct inode *, int); | 1231 | extern int ext4_ext_writepage_trans_blocks(struct inode *, int); |
| 1232 | extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks, | ||
| 1233 | int chunk); | ||
| 1231 | extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | 1234 | extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, |
| 1232 | ext4_lblk_t iblock, | 1235 | ext4_lblk_t iblock, |
| 1233 | unsigned long max_blocks, struct buffer_head *bh_result, | 1236 | unsigned long max_blocks, struct buffer_head *bh_result, |
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 6c166c0a54b7..d33dc56d6986 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
| @@ -216,7 +216,9 @@ extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks); | |||
| 216 | extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); | 216 | extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); |
| 217 | extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t); | 217 | extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t); |
| 218 | extern int ext4_extent_tree_init(handle_t *, struct inode *); | 218 | extern int ext4_extent_tree_init(handle_t *, struct inode *); |
| 219 | extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *); | 219 | extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, |
| 220 | int num, | ||
| 221 | struct ext4_ext_path *path); | ||
| 220 | extern int ext4_ext_try_to_merge(struct inode *inode, | 222 | extern int ext4_ext_try_to_merge(struct inode *inode, |
| 221 | struct ext4_ext_path *path, | 223 | struct ext4_ext_path *path, |
| 222 | struct ext4_extent *); | 224 | struct ext4_extent *); |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index eb8bc3afe6e9..b455c685a98b 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
| @@ -51,6 +51,14 @@ | |||
| 51 | EXT4_XATTR_TRANS_BLOCKS - 2 + \ | 51 | EXT4_XATTR_TRANS_BLOCKS - 2 + \ |
| 52 | 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) | 52 | 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) |
| 53 | 53 | ||
| 54 | /* | ||
| 55 | * Define the number of metadata blocks we need to account to modify data. | ||
| 56 | * | ||
| 57 | * This include super block, inode block, quota blocks and xattr blocks | ||
| 58 | */ | ||
| 59 | #define EXT4_META_TRANS_BLOCKS(sb) (EXT4_XATTR_TRANS_BLOCKS + \ | ||
| 60 | 2*EXT4_QUOTA_TRANS_BLOCKS(sb)) | ||
| 61 | |||
| 54 | /* Delete operations potentially hit one directory's namespace plus an | 62 | /* Delete operations potentially hit one directory's namespace plus an |
| 55 | * entire inode, plus arbitrary amounts of bitmap/indirection data. Be | 63 | * entire inode, plus arbitrary amounts of bitmap/indirection data. Be |
| 56 | * generous. We can grow the delete transaction later if necessary. */ | 64 | * generous. We can grow the delete transaction later if necessary. */ |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 42c4c0c892ed..b24d3c53f20c 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -99,7 +99,7 @@ static int ext4_ext_journal_restart(handle_t *handle, int needed) | |||
| 99 | if (handle->h_buffer_credits > needed) | 99 | if (handle->h_buffer_credits > needed) |
| 100 | return 0; | 100 | return 0; |
| 101 | err = ext4_journal_extend(handle, needed); | 101 | err = ext4_journal_extend(handle, needed); |
| 102 | if (err) | 102 | if (err <= 0) |
| 103 | return err; | 103 | return err; |
| 104 | return ext4_journal_restart(handle, needed); | 104 | return ext4_journal_restart(handle, needed); |
| 105 | } | 105 | } |
| @@ -1441,7 +1441,7 @@ unsigned int ext4_ext_check_overlap(struct inode *inode, | |||
| 1441 | 1441 | ||
| 1442 | /* | 1442 | /* |
| 1443 | * get the next allocated block if the extent in the path | 1443 | * get the next allocated block if the extent in the path |
| 1444 | * is before the requested block(s) | 1444 | * is before the requested block(s) |
| 1445 | */ | 1445 | */ |
| 1446 | if (b2 < b1) { | 1446 | if (b2 < b1) { |
| 1447 | b2 = ext4_ext_next_allocated_block(path); | 1447 | b2 = ext4_ext_next_allocated_block(path); |
| @@ -1747,54 +1747,61 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, | |||
| 1747 | } | 1747 | } |
| 1748 | 1748 | ||
| 1749 | /* | 1749 | /* |
| 1750 | * ext4_ext_calc_credits_for_insert: | 1750 | * ext4_ext_calc_credits_for_single_extent: |
| 1751 | * This routine returns max. credits that the extent tree can consume. | 1751 | * This routine returns max. credits that needed to insert an extent |
| 1752 | * It should be OK for low-performance paths like ->writepage() | 1752 | * to the extent tree. |
| 1753 | * To allow many writing processes to fit into a single transaction, | 1753 | * When pass the actual path, the caller should calculate credits |
| 1754 | * the caller should calculate credits under i_data_sem and | 1754 | * under i_data_sem. |
| 1755 | * pass the actual path. | ||
| 1756 | */ | 1755 | */ |
| 1757 | int ext4_ext_calc_credits_for_insert(struct inode *inode, | 1756 | int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks, |
| 1758 | struct ext4_ext_path *path) | 1757 | struct ext4_ext_path *path) |
| 1759 | { | 1758 | { |
| 1760 | int depth, needed; | ||
| 1761 | |||
| 1762 | if (path) { | 1759 | if (path) { |
| 1760 | int depth = ext_depth(inode); | ||
| 1761 | int ret = 0; | ||
| 1762 | |||
| 1763 | /* probably there is space in leaf? */ | 1763 | /* probably there is space in leaf? */ |
| 1764 | depth = ext_depth(inode); | ||
| 1765 | if (le16_to_cpu(path[depth].p_hdr->eh_entries) | 1764 | if (le16_to_cpu(path[depth].p_hdr->eh_entries) |
| 1766 | < le16_to_cpu(path[depth].p_hdr->eh_max)) | 1765 | < le16_to_cpu(path[depth].p_hdr->eh_max)) { |
| 1767 | return 1; | ||
| 1768 | } | ||
| 1769 | |||
| 1770 | /* | ||
| 1771 | * given 32-bit logical block (4294967296 blocks), max. tree | ||
| 1772 | * can be 4 levels in depth -- 4 * 340^4 == 53453440000. | ||
| 1773 | * Let's also add one more level for imbalance. | ||
| 1774 | */ | ||
| 1775 | depth = 5; | ||
| 1776 | 1766 | ||
| 1777 | /* allocation of new data block(s) */ | 1767 | /* |
| 1778 | needed = 2; | 1768 | * There are some space in the leaf tree, no |
| 1769 | * need to account for leaf block credit | ||
| 1770 | * | ||
| 1771 | * bitmaps and block group descriptor blocks | ||
| 1772 | * and other metadat blocks still need to be | ||
| 1773 | * accounted. | ||
| 1774 | */ | ||
| 1775 | /* 1 bitmap, 1 block group descriptor */ | ||
| 1776 | ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb); | ||
| 1777 | } | ||
| 1778 | } | ||
| 1779 | 1779 | ||
| 1780 | /* | 1780 | return ext4_chunk_trans_blocks(inode, nrblocks); |
| 1781 | * tree can be full, so it would need to grow in depth: | 1781 | } |
| 1782 | * we need one credit to modify old root, credits for | ||
| 1783 | * new root will be added in split accounting | ||
| 1784 | */ | ||
| 1785 | needed += 1; | ||
| 1786 | 1782 | ||
| 1787 | /* | 1783 | /* |
| 1788 | * Index split can happen, we would need: | 1784 | * How many index/leaf blocks need to change/allocate to modify nrblocks? |
| 1789 | * allocate intermediate indexes (bitmap + group) | 1785 | * |
| 1790 | * + change two blocks at each level, but root (already included) | 1786 | * if nrblocks are fit in a single extent (chunk flag is 1), then |
| 1791 | */ | 1787 | * in the worse case, each tree level index/leaf need to be changed |
| 1792 | needed += (depth * 2) + (depth * 2); | 1788 | * if the tree split due to insert a new extent, then the old tree |
| 1789 | * index/leaf need to be updated too | ||
| 1790 | * | ||
| 1791 | * If the nrblocks are discontiguous, they could cause | ||
| 1792 | * the whole tree split more than once, but this is really rare. | ||
| 1793 | */ | ||
| 1794 | int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) | ||
| 1795 | { | ||
| 1796 | int index; | ||
| 1797 | int depth = ext_depth(inode); | ||
| 1793 | 1798 | ||
| 1794 | /* any allocation modifies superblock */ | 1799 | if (chunk) |
| 1795 | needed += 1; | 1800 | index = depth * 2; |
| 1801 | else | ||
| 1802 | index = depth * 3; | ||
| 1796 | 1803 | ||
| 1797 | return needed; | 1804 | return index; |
| 1798 | } | 1805 | } |
| 1799 | 1806 | ||
| 1800 | static int ext4_remove_blocks(handle_t *handle, struct inode *inode, | 1807 | static int ext4_remove_blocks(handle_t *handle, struct inode *inode, |
| @@ -1910,16 +1917,18 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
| 1910 | BUG_ON(b != ex_ee_block + ex_ee_len - 1); | 1917 | BUG_ON(b != ex_ee_block + ex_ee_len - 1); |
| 1911 | } | 1918 | } |
| 1912 | 1919 | ||
| 1913 | /* at present, extent can't cross block group: */ | 1920 | /* |
| 1914 | /* leaf + bitmap + group desc + sb + inode */ | 1921 | * 3 for leaf, sb, and inode plus 2 (bmap and group |
| 1915 | credits = 5; | 1922 | * descriptor) for each block group; assume two block |
| 1923 | * groups plus ex_ee_len/blocks_per_block_group for | ||
| 1924 | * the worst case | ||
| 1925 | */ | ||
| 1926 | credits = 7 + 2*(ex_ee_len/EXT4_BLOCKS_PER_GROUP(inode->i_sb)); | ||
| 1916 | if (ex == EXT_FIRST_EXTENT(eh)) { | 1927 | if (ex == EXT_FIRST_EXTENT(eh)) { |
| 1917 | correct_index = 1; | 1928 | correct_index = 1; |
| 1918 | credits += (ext_depth(inode)) + 1; | 1929 | credits += (ext_depth(inode)) + 1; |
| 1919 | } | 1930 | } |
| 1920 | #ifdef CONFIG_QUOTA | ||
| 1921 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | 1931 | credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); |
| 1922 | #endif | ||
| 1923 | 1932 | ||
| 1924 | err = ext4_ext_journal_restart(handle, credits); | 1933 | err = ext4_ext_journal_restart(handle, credits); |
| 1925 | if (err) | 1934 | if (err) |
| @@ -2323,7 +2332,10 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
| 2323 | unsigned int newdepth; | 2332 | unsigned int newdepth; |
| 2324 | /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */ | 2333 | /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */ |
| 2325 | if (allocated <= EXT4_EXT_ZERO_LEN) { | 2334 | if (allocated <= EXT4_EXT_ZERO_LEN) { |
| 2326 | /* Mark first half uninitialized. | 2335 | /* |
| 2336 | * iblock == ee_block is handled by the zerouout | ||
| 2337 | * at the beginning. | ||
| 2338 | * Mark first half uninitialized. | ||
| 2327 | * Mark second half initialized and zero out the | 2339 | * Mark second half initialized and zero out the |
| 2328 | * initialized extent | 2340 | * initialized extent |
| 2329 | */ | 2341 | */ |
| @@ -2346,7 +2358,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
| 2346 | ex->ee_len = orig_ex.ee_len; | 2358 | ex->ee_len = orig_ex.ee_len; |
| 2347 | ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); | 2359 | ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); |
| 2348 | ext4_ext_dirty(handle, inode, path + depth); | 2360 | ext4_ext_dirty(handle, inode, path + depth); |
| 2349 | /* zeroed the full extent */ | 2361 | /* blocks available from iblock */ |
| 2350 | return allocated; | 2362 | return allocated; |
| 2351 | 2363 | ||
| 2352 | } else if (err) | 2364 | } else if (err) |
| @@ -2374,6 +2386,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
| 2374 | err = PTR_ERR(path); | 2386 | err = PTR_ERR(path); |
| 2375 | return err; | 2387 | return err; |
| 2376 | } | 2388 | } |
| 2389 | /* get the second half extent details */ | ||
| 2377 | ex = path[depth].p_ext; | 2390 | ex = path[depth].p_ext; |
| 2378 | err = ext4_ext_get_access(handle, inode, | 2391 | err = ext4_ext_get_access(handle, inode, |
| 2379 | path + depth); | 2392 | path + depth); |
| @@ -2403,6 +2416,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
| 2403 | ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); | 2416 | ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); |
| 2404 | ext4_ext_dirty(handle, inode, path + depth); | 2417 | ext4_ext_dirty(handle, inode, path + depth); |
| 2405 | /* zeroed the full extent */ | 2418 | /* zeroed the full extent */ |
| 2419 | /* blocks available from iblock */ | ||
| 2406 | return allocated; | 2420 | return allocated; |
| 2407 | 2421 | ||
| 2408 | } else if (err) | 2422 | } else if (err) |
| @@ -2418,23 +2432,22 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
| 2418 | */ | 2432 | */ |
| 2419 | orig_ex.ee_len = cpu_to_le16(ee_len - | 2433 | orig_ex.ee_len = cpu_to_le16(ee_len - |
| 2420 | ext4_ext_get_actual_len(ex3)); | 2434 | ext4_ext_get_actual_len(ex3)); |
| 2421 | if (newdepth != depth) { | 2435 | depth = newdepth; |
| 2422 | depth = newdepth; | 2436 | ext4_ext_drop_refs(path); |
| 2423 | ext4_ext_drop_refs(path); | 2437 | path = ext4_ext_find_extent(inode, iblock, path); |
| 2424 | path = ext4_ext_find_extent(inode, iblock, path); | 2438 | if (IS_ERR(path)) { |
| 2425 | if (IS_ERR(path)) { | 2439 | err = PTR_ERR(path); |
| 2426 | err = PTR_ERR(path); | 2440 | goto out; |
| 2427 | goto out; | ||
| 2428 | } | ||
| 2429 | eh = path[depth].p_hdr; | ||
| 2430 | ex = path[depth].p_ext; | ||
| 2431 | if (ex2 != &newex) | ||
| 2432 | ex2 = ex; | ||
| 2433 | |||
| 2434 | err = ext4_ext_get_access(handle, inode, path + depth); | ||
| 2435 | if (err) | ||
| 2436 | goto out; | ||
| 2437 | } | 2441 | } |
| 2442 | eh = path[depth].p_hdr; | ||
| 2443 | ex = path[depth].p_ext; | ||
| 2444 | if (ex2 != &newex) | ||
| 2445 | ex2 = ex; | ||
| 2446 | |||
| 2447 | err = ext4_ext_get_access(handle, inode, path + depth); | ||
| 2448 | if (err) | ||
| 2449 | goto out; | ||
| 2450 | |||
| 2438 | allocated = max_blocks; | 2451 | allocated = max_blocks; |
| 2439 | 2452 | ||
| 2440 | /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying | 2453 | /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying |
| @@ -2452,6 +2465,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, | |||
| 2452 | ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); | 2465 | ext4_ext_store_pblock(ex, ext_pblock(&orig_ex)); |
| 2453 | ext4_ext_dirty(handle, inode, path + depth); | 2466 | ext4_ext_dirty(handle, inode, path + depth); |
| 2454 | /* zero out the first half */ | 2467 | /* zero out the first half */ |
| 2468 | /* blocks available from iblock */ | ||
| 2455 | return allocated; | 2469 | return allocated; |
| 2456 | } | 2470 | } |
| 2457 | } | 2471 | } |
| @@ -2796,7 +2810,7 @@ void ext4_ext_truncate(struct inode *inode) | |||
| 2796 | /* | 2810 | /* |
| 2797 | * probably first extent we're gonna free will be last in block | 2811 | * probably first extent we're gonna free will be last in block |
| 2798 | */ | 2812 | */ |
| 2799 | err = ext4_writepage_trans_blocks(inode) + 3; | 2813 | err = ext4_writepage_trans_blocks(inode); |
| 2800 | handle = ext4_journal_start(inode, err); | 2814 | handle = ext4_journal_start(inode, err); |
| 2801 | if (IS_ERR(handle)) | 2815 | if (IS_ERR(handle)) |
| 2802 | return; | 2816 | return; |
| @@ -2810,7 +2824,7 @@ void ext4_ext_truncate(struct inode *inode) | |||
| 2810 | down_write(&EXT4_I(inode)->i_data_sem); | 2824 | down_write(&EXT4_I(inode)->i_data_sem); |
| 2811 | ext4_ext_invalidate_cache(inode); | 2825 | ext4_ext_invalidate_cache(inode); |
| 2812 | 2826 | ||
| 2813 | ext4_mb_discard_inode_preallocations(inode); | 2827 | ext4_discard_reservation(inode); |
| 2814 | 2828 | ||
| 2815 | /* | 2829 | /* |
| 2816 | * TODO: optimization is possible here. | 2830 | * TODO: optimization is possible here. |
| @@ -2849,27 +2863,6 @@ out_stop: | |||
| 2849 | ext4_journal_stop(handle); | 2863 | ext4_journal_stop(handle); |
| 2850 | } | 2864 | } |
| 2851 | 2865 | ||
| 2852 | /* | ||
| 2853 | * ext4_ext_writepage_trans_blocks: | ||
| 2854 | * calculate max number of blocks we could modify | ||
| 2855 | * in order to allocate new block for an inode | ||
| 2856 | */ | ||
| 2857 | int ext4_ext_writepage_trans_blocks(struct inode *inode, int num) | ||
| 2858 | { | ||
| 2859 | int needed; | ||
| 2860 | |||
| 2861 | needed = ext4_ext_calc_credits_for_insert(inode, NULL); | ||
| 2862 | |||
| 2863 | /* caller wants to allocate num blocks, but note it includes sb */ | ||
| 2864 | needed = needed * num - (num - 1); | ||
| 2865 | |||
| 2866 | #ifdef CONFIG_QUOTA | ||
| 2867 | needed += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | ||
| 2868 | #endif | ||
| 2869 | |||
| 2870 | return needed; | ||
| 2871 | } | ||
| 2872 | |||
| 2873 | static void ext4_falloc_update_inode(struct inode *inode, | 2866 | static void ext4_falloc_update_inode(struct inode *inode, |
| 2874 | int mode, loff_t new_size, int update_ctime) | 2867 | int mode, loff_t new_size, int update_ctime) |
| 2875 | { | 2868 | { |
| @@ -2930,10 +2923,9 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) | |||
| 2930 | max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) | 2923 | max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits) |
| 2931 | - block; | 2924 | - block; |
| 2932 | /* | 2925 | /* |
| 2933 | * credits to insert 1 extent into extent tree + buffers to be able to | 2926 | * credits to insert 1 extent into extent tree |
| 2934 | * modify 1 super block, 1 block bitmap and 1 group descriptor. | ||
| 2935 | */ | 2927 | */ |
| 2936 | credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3; | 2928 | credits = ext4_chunk_trans_blocks(inode, max_blocks); |
| 2937 | mutex_lock(&inode->i_mutex); | 2929 | mutex_lock(&inode->i_mutex); |
| 2938 | retry: | 2930 | retry: |
| 2939 | while (ret >= 0 && ret < max_blocks) { | 2931 | while (ret >= 0 && ret < max_blocks) { |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index a92eb305344f..f344834bbf58 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
| @@ -97,34 +97,44 @@ unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh, | |||
| 97 | * Return buffer_head of bitmap on success or NULL. | 97 | * Return buffer_head of bitmap on success or NULL. |
| 98 | */ | 98 | */ |
| 99 | static struct buffer_head * | 99 | static struct buffer_head * |
| 100 | read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | 100 | ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) |
| 101 | { | 101 | { |
| 102 | struct ext4_group_desc *desc; | 102 | struct ext4_group_desc *desc; |
| 103 | struct buffer_head *bh = NULL; | 103 | struct buffer_head *bh = NULL; |
| 104 | ext4_fsblk_t bitmap_blk; | ||
| 104 | 105 | ||
| 105 | desc = ext4_get_group_desc(sb, block_group, NULL); | 106 | desc = ext4_get_group_desc(sb, block_group, NULL); |
| 106 | if (!desc) | 107 | if (!desc) |
| 107 | goto error_out; | 108 | return NULL; |
| 108 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { | 109 | bitmap_blk = ext4_inode_bitmap(sb, desc); |
| 109 | bh = sb_getblk(sb, ext4_inode_bitmap(sb, desc)); | 110 | bh = sb_getblk(sb, bitmap_blk); |
| 110 | if (!buffer_uptodate(bh)) { | 111 | if (unlikely(!bh)) { |
| 111 | lock_buffer(bh); | 112 | ext4_error(sb, __func__, |
| 112 | if (!buffer_uptodate(bh)) { | 113 | "Cannot read inode bitmap - " |
| 113 | ext4_init_inode_bitmap(sb, bh, block_group, | 114 | "block_group = %lu, inode_bitmap = %llu", |
| 114 | desc); | 115 | block_group, bitmap_blk); |
| 115 | set_buffer_uptodate(bh); | 116 | return NULL; |
| 116 | } | ||
| 117 | unlock_buffer(bh); | ||
| 118 | } | ||
| 119 | } else { | ||
| 120 | bh = sb_bread(sb, ext4_inode_bitmap(sb, desc)); | ||
| 121 | } | 117 | } |
| 122 | if (!bh) | 118 | if (bh_uptodate_or_lock(bh)) |
| 123 | ext4_error(sb, "read_inode_bitmap", | 119 | return bh; |
| 120 | |||
| 121 | spin_lock(sb_bgl_lock(EXT4_SB(sb), block_group)); | ||
| 122 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { | ||
| 123 | ext4_init_inode_bitmap(sb, bh, block_group, desc); | ||
| 124 | set_buffer_uptodate(bh); | ||
| 125 | unlock_buffer(bh); | ||
| 126 | spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); | ||
| 127 | return bh; | ||
| 128 | } | ||
| 129 | spin_unlock(sb_bgl_lock(EXT4_SB(sb), block_group)); | ||
| 130 | if (bh_submit_read(bh) < 0) { | ||
| 131 | put_bh(bh); | ||
| 132 | ext4_error(sb, __func__, | ||
| 124 | "Cannot read inode bitmap - " | 133 | "Cannot read inode bitmap - " |
| 125 | "block_group = %lu, inode_bitmap = %llu", | 134 | "block_group = %lu, inode_bitmap = %llu", |
| 126 | block_group, ext4_inode_bitmap(sb, desc)); | 135 | block_group, bitmap_blk); |
| 127 | error_out: | 136 | return NULL; |
| 137 | } | ||
| 128 | return bh; | 138 | return bh; |
| 129 | } | 139 | } |
| 130 | 140 | ||
| @@ -200,7 +210,7 @@ void ext4_free_inode (handle_t *handle, struct inode * inode) | |||
| 200 | } | 210 | } |
| 201 | block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); | 211 | block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); |
| 202 | bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); | 212 | bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); |
| 203 | bitmap_bh = read_inode_bitmap(sb, block_group); | 213 | bitmap_bh = ext4_read_inode_bitmap(sb, block_group); |
| 204 | if (!bitmap_bh) | 214 | if (!bitmap_bh) |
| 205 | goto error_return; | 215 | goto error_return; |
| 206 | 216 | ||
| @@ -341,7 +351,7 @@ find_close_to_parent: | |||
| 341 | goto found_flexbg; | 351 | goto found_flexbg; |
| 342 | } | 352 | } |
| 343 | 353 | ||
| 344 | if (best_flex < 0 || | 354 | if (flex_group[best_flex].free_inodes == 0 || |
| 345 | (flex_group[i].free_blocks > | 355 | (flex_group[i].free_blocks > |
| 346 | flex_group[best_flex].free_blocks && | 356 | flex_group[best_flex].free_blocks && |
| 347 | flex_group[i].free_inodes)) | 357 | flex_group[i].free_inodes)) |
| @@ -623,7 +633,7 @@ got_group: | |||
| 623 | goto fail; | 633 | goto fail; |
| 624 | 634 | ||
| 625 | brelse(bitmap_bh); | 635 | brelse(bitmap_bh); |
| 626 | bitmap_bh = read_inode_bitmap(sb, group); | 636 | bitmap_bh = ext4_read_inode_bitmap(sb, group); |
| 627 | if (!bitmap_bh) | 637 | if (!bitmap_bh) |
| 628 | goto fail; | 638 | goto fail; |
| 629 | 639 | ||
| @@ -728,7 +738,7 @@ got: | |||
| 728 | 738 | ||
| 729 | /* When marking the block group with | 739 | /* When marking the block group with |
| 730 | * ~EXT4_BG_INODE_UNINIT we don't want to depend | 740 | * ~EXT4_BG_INODE_UNINIT we don't want to depend |
| 731 | * on the value of bg_itable_unsed even though | 741 | * on the value of bg_itable_unused even though |
| 732 | * mke2fs could have initialized the same for us. | 742 | * mke2fs could have initialized the same for us. |
| 733 | * Instead we calculated the value below | 743 | * Instead we calculated the value below |
| 734 | */ | 744 | */ |
| @@ -891,7 +901,7 @@ struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) | |||
| 891 | 901 | ||
| 892 | block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); | 902 | block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); |
| 893 | bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); | 903 | bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); |
| 894 | bitmap_bh = read_inode_bitmap(sb, block_group); | 904 | bitmap_bh = ext4_read_inode_bitmap(sb, block_group); |
| 895 | if (!bitmap_bh) { | 905 | if (!bitmap_bh) { |
| 896 | ext4_warning(sb, __func__, | 906 | ext4_warning(sb, __func__, |
| 897 | "inode bitmap error for orphan %lu", ino); | 907 | "inode bitmap error for orphan %lu", ino); |
| @@ -969,7 +979,7 @@ unsigned long ext4_count_free_inodes (struct super_block * sb) | |||
| 969 | continue; | 979 | continue; |
| 970 | desc_count += le16_to_cpu(gdp->bg_free_inodes_count); | 980 | desc_count += le16_to_cpu(gdp->bg_free_inodes_count); |
| 971 | brelse(bitmap_bh); | 981 | brelse(bitmap_bh); |
| 972 | bitmap_bh = read_inode_bitmap(sb, i); | 982 | bitmap_bh = ext4_read_inode_bitmap(sb, i); |
| 973 | if (!bitmap_bh) | 983 | if (!bitmap_bh) |
| 974 | continue; | 984 | continue; |
| 975 | 985 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 8ca2763df091..7e91913e325b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -41,6 +41,8 @@ | |||
| 41 | #include "acl.h" | 41 | #include "acl.h" |
| 42 | #include "ext4_extents.h" | 42 | #include "ext4_extents.h" |
| 43 | 43 | ||
| 44 | #define MPAGE_DA_EXTENT_TAIL 0x01 | ||
| 45 | |||
| 44 | static inline int ext4_begin_ordered_truncate(struct inode *inode, | 46 | static inline int ext4_begin_ordered_truncate(struct inode *inode, |
| 45 | loff_t new_size) | 47 | loff_t new_size) |
| 46 | { | 48 | { |
| @@ -191,6 +193,7 @@ static int ext4_journal_test_restart(handle_t *handle, struct inode *inode) | |||
| 191 | void ext4_delete_inode (struct inode * inode) | 193 | void ext4_delete_inode (struct inode * inode) |
| 192 | { | 194 | { |
| 193 | handle_t *handle; | 195 | handle_t *handle; |
| 196 | int err; | ||
| 194 | 197 | ||
| 195 | if (ext4_should_order_data(inode)) | 198 | if (ext4_should_order_data(inode)) |
| 196 | ext4_begin_ordered_truncate(inode, 0); | 199 | ext4_begin_ordered_truncate(inode, 0); |
| @@ -199,8 +202,9 @@ void ext4_delete_inode (struct inode * inode) | |||
| 199 | if (is_bad_inode(inode)) | 202 | if (is_bad_inode(inode)) |
| 200 | goto no_delete; | 203 | goto no_delete; |
| 201 | 204 | ||
| 202 | handle = start_transaction(inode); | 205 | handle = ext4_journal_start(inode, blocks_for_truncate(inode)+3); |
| 203 | if (IS_ERR(handle)) { | 206 | if (IS_ERR(handle)) { |
| 207 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); | ||
| 204 | /* | 208 | /* |
| 205 | * If we're going to skip the normal cleanup, we still need to | 209 | * If we're going to skip the normal cleanup, we still need to |
| 206 | * make sure that the in-core orphan linked list is properly | 210 | * make sure that the in-core orphan linked list is properly |
| @@ -213,8 +217,34 @@ void ext4_delete_inode (struct inode * inode) | |||
| 213 | if (IS_SYNC(inode)) | 217 | if (IS_SYNC(inode)) |
| 214 | handle->h_sync = 1; | 218 | handle->h_sync = 1; |
| 215 | inode->i_size = 0; | 219 | inode->i_size = 0; |
| 220 | err = ext4_mark_inode_dirty(handle, inode); | ||
| 221 | if (err) { | ||
| 222 | ext4_warning(inode->i_sb, __func__, | ||
| 223 | "couldn't mark inode dirty (err %d)", err); | ||
| 224 | goto stop_handle; | ||
| 225 | } | ||
| 216 | if (inode->i_blocks) | 226 | if (inode->i_blocks) |
| 217 | ext4_truncate(inode); | 227 | ext4_truncate(inode); |
| 228 | |||
| 229 | /* | ||
| 230 | * ext4_ext_truncate() doesn't reserve any slop when it | ||
| 231 | * restarts journal transactions; therefore there may not be | ||
| 232 | * enough credits left in the handle to remove the inode from | ||
| 233 | * the orphan list and set the dtime field. | ||
| 234 | */ | ||
| 235 | if (handle->h_buffer_credits < 3) { | ||
| 236 | err = ext4_journal_extend(handle, 3); | ||
| 237 | if (err > 0) | ||
| 238 | err = ext4_journal_restart(handle, 3); | ||
| 239 | if (err != 0) { | ||
| 240 | ext4_warning(inode->i_sb, __func__, | ||
| 241 | "couldn't extend journal (err %d)", err); | ||
| 242 | stop_handle: | ||
| 243 | ext4_journal_stop(handle); | ||
| 244 | goto no_delete; | ||
| 245 | } | ||
| 246 | } | ||
| 247 | |||
| 218 | /* | 248 | /* |
| 219 | * Kill off the orphan record which ext4_truncate created. | 249 | * Kill off the orphan record which ext4_truncate created. |
| 220 | * AKPM: I think this can be inside the above `if'. | 250 | * AKPM: I think this can be inside the above `if'. |
| @@ -952,23 +982,74 @@ out: | |||
| 952 | return err; | 982 | return err; |
| 953 | } | 983 | } |
| 954 | 984 | ||
| 955 | /* Maximum number of blocks we map for direct IO at once. */ | ||
| 956 | #define DIO_MAX_BLOCKS 4096 | ||
| 957 | /* | 985 | /* |
| 958 | * Number of credits we need for writing DIO_MAX_BLOCKS: | 986 | * Calculate the number of metadata blocks need to reserve |
| 959 | * We need sb + group descriptor + bitmap + inode -> 4 | 987 | * to allocate @blocks for non extent file based file |
| 960 | * For B blocks with A block pointers per block we need: | ||
| 961 | * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect). | ||
| 962 | * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25. | ||
| 963 | */ | 988 | */ |
| 964 | #define DIO_CREDITS 25 | 989 | static int ext4_indirect_calc_metadata_amount(struct inode *inode, int blocks) |
| 990 | { | ||
| 991 | int icap = EXT4_ADDR_PER_BLOCK(inode->i_sb); | ||
| 992 | int ind_blks, dind_blks, tind_blks; | ||
| 993 | |||
| 994 | /* number of new indirect blocks needed */ | ||
| 995 | ind_blks = (blocks + icap - 1) / icap; | ||
| 996 | |||
| 997 | dind_blks = (ind_blks + icap - 1) / icap; | ||
| 965 | 998 | ||
| 999 | tind_blks = 1; | ||
| 1000 | |||
| 1001 | return ind_blks + dind_blks + tind_blks; | ||
| 1002 | } | ||
| 966 | 1003 | ||
| 967 | /* | 1004 | /* |
| 1005 | * Calculate the number of metadata blocks need to reserve | ||
| 1006 | * to allocate given number of blocks | ||
| 1007 | */ | ||
| 1008 | static int ext4_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 1009 | { | ||
| 1010 | if (!blocks) | ||
| 1011 | return 0; | ||
| 1012 | |||
| 1013 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) | ||
| 1014 | return ext4_ext_calc_metadata_amount(inode, blocks); | ||
| 1015 | |||
| 1016 | return ext4_indirect_calc_metadata_amount(inode, blocks); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | static void ext4_da_update_reserve_space(struct inode *inode, int used) | ||
| 1020 | { | ||
| 1021 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
| 1022 | int total, mdb, mdb_free; | ||
| 1023 | |||
| 1024 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | ||
| 1025 | /* recalculate the number of metablocks still need to be reserved */ | ||
| 1026 | total = EXT4_I(inode)->i_reserved_data_blocks - used; | ||
| 1027 | mdb = ext4_calc_metadata_amount(inode, total); | ||
| 1028 | |||
| 1029 | /* figure out how many metablocks to release */ | ||
| 1030 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | ||
| 1031 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; | ||
| 1032 | |||
| 1033 | /* Account for allocated meta_blocks */ | ||
| 1034 | mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; | ||
| 1035 | |||
| 1036 | /* update fs free blocks counter for truncate case */ | ||
| 1037 | percpu_counter_add(&sbi->s_freeblocks_counter, mdb_free); | ||
| 1038 | |||
| 1039 | /* update per-inode reservations */ | ||
| 1040 | BUG_ON(used > EXT4_I(inode)->i_reserved_data_blocks); | ||
| 1041 | EXT4_I(inode)->i_reserved_data_blocks -= used; | ||
| 1042 | |||
| 1043 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | ||
| 1044 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; | ||
| 1045 | EXT4_I(inode)->i_allocated_meta_blocks = 0; | ||
| 1046 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /* | ||
| 1050 | * The ext4_get_blocks_wrap() function try to look up the requested blocks, | ||
| 1051 | * and returns if the blocks are already mapped. | ||
| 968 | * | 1052 | * |
| 969 | * | ||
| 970 | * ext4_ext4 get_block() wrapper function | ||
| 971 | * It will do a look up first, and returns if the blocks already mapped. | ||
| 972 | * Otherwise it takes the write lock of the i_data_sem and allocate blocks | 1053 | * Otherwise it takes the write lock of the i_data_sem and allocate blocks |
| 973 | * and store the allocated blocks in the result buffer head and mark it | 1054 | * and store the allocated blocks in the result buffer head and mark it |
| 974 | * mapped. | 1055 | * mapped. |
| @@ -1069,26 +1150,30 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block, | |||
| 1069 | * which were deferred till now | 1150 | * which were deferred till now |
| 1070 | */ | 1151 | */ |
| 1071 | if ((retval > 0) && buffer_delay(bh)) | 1152 | if ((retval > 0) && buffer_delay(bh)) |
| 1072 | ext4_da_release_space(inode, retval, 0); | 1153 | ext4_da_update_reserve_space(inode, retval); |
| 1073 | } | 1154 | } |
| 1074 | 1155 | ||
| 1075 | up_write((&EXT4_I(inode)->i_data_sem)); | 1156 | up_write((&EXT4_I(inode)->i_data_sem)); |
| 1076 | return retval; | 1157 | return retval; |
| 1077 | } | 1158 | } |
| 1078 | 1159 | ||
| 1160 | /* Maximum number of blocks we map for direct IO at once. */ | ||
| 1161 | #define DIO_MAX_BLOCKS 4096 | ||
| 1162 | |||
| 1079 | static int ext4_get_block(struct inode *inode, sector_t iblock, | 1163 | static int ext4_get_block(struct inode *inode, sector_t iblock, |
| 1080 | struct buffer_head *bh_result, int create) | 1164 | struct buffer_head *bh_result, int create) |
| 1081 | { | 1165 | { |
| 1082 | handle_t *handle = ext4_journal_current_handle(); | 1166 | handle_t *handle = ext4_journal_current_handle(); |
| 1083 | int ret = 0, started = 0; | 1167 | int ret = 0, started = 0; |
| 1084 | unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; | 1168 | unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; |
| 1169 | int dio_credits; | ||
| 1085 | 1170 | ||
| 1086 | if (create && !handle) { | 1171 | if (create && !handle) { |
| 1087 | /* Direct IO write... */ | 1172 | /* Direct IO write... */ |
| 1088 | if (max_blocks > DIO_MAX_BLOCKS) | 1173 | if (max_blocks > DIO_MAX_BLOCKS) |
| 1089 | max_blocks = DIO_MAX_BLOCKS; | 1174 | max_blocks = DIO_MAX_BLOCKS; |
| 1090 | handle = ext4_journal_start(inode, DIO_CREDITS + | 1175 | dio_credits = ext4_chunk_trans_blocks(inode, max_blocks); |
| 1091 | 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb)); | 1176 | handle = ext4_journal_start(inode, dio_credits); |
| 1092 | if (IS_ERR(handle)) { | 1177 | if (IS_ERR(handle)) { |
| 1093 | ret = PTR_ERR(handle); | 1178 | ret = PTR_ERR(handle); |
| 1094 | goto out; | 1179 | goto out; |
| @@ -1336,12 +1421,8 @@ static int ext4_ordered_write_end(struct file *file, | |||
| 1336 | { | 1421 | { |
| 1337 | handle_t *handle = ext4_journal_current_handle(); | 1422 | handle_t *handle = ext4_journal_current_handle(); |
| 1338 | struct inode *inode = mapping->host; | 1423 | struct inode *inode = mapping->host; |
| 1339 | unsigned from, to; | ||
| 1340 | int ret = 0, ret2; | 1424 | int ret = 0, ret2; |
| 1341 | 1425 | ||
| 1342 | from = pos & (PAGE_CACHE_SIZE - 1); | ||
| 1343 | to = from + len; | ||
| 1344 | |||
| 1345 | ret = ext4_jbd2_file_inode(handle, inode); | 1426 | ret = ext4_jbd2_file_inode(handle, inode); |
| 1346 | 1427 | ||
| 1347 | if (ret == 0) { | 1428 | if (ret == 0) { |
| @@ -1437,36 +1518,6 @@ static int ext4_journalled_write_end(struct file *file, | |||
| 1437 | 1518 | ||
| 1438 | return ret ? ret : copied; | 1519 | return ret ? ret : copied; |
| 1439 | } | 1520 | } |
| 1440 | /* | ||
| 1441 | * Calculate the number of metadata blocks need to reserve | ||
| 1442 | * to allocate @blocks for non extent file based file | ||
| 1443 | */ | ||
| 1444 | static int ext4_indirect_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 1445 | { | ||
| 1446 | int icap = EXT4_ADDR_PER_BLOCK(inode->i_sb); | ||
| 1447 | int ind_blks, dind_blks, tind_blks; | ||
| 1448 | |||
| 1449 | /* number of new indirect blocks needed */ | ||
| 1450 | ind_blks = (blocks + icap - 1) / icap; | ||
| 1451 | |||
| 1452 | dind_blks = (ind_blks + icap - 1) / icap; | ||
| 1453 | |||
| 1454 | tind_blks = 1; | ||
| 1455 | |||
| 1456 | return ind_blks + dind_blks + tind_blks; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | /* | ||
| 1460 | * Calculate the number of metadata blocks need to reserve | ||
| 1461 | * to allocate given number of blocks | ||
| 1462 | */ | ||
| 1463 | static int ext4_calc_metadata_amount(struct inode *inode, int blocks) | ||
| 1464 | { | ||
| 1465 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) | ||
| 1466 | return ext4_ext_calc_metadata_amount(inode, blocks); | ||
| 1467 | |||
| 1468 | return ext4_indirect_calc_metadata_amount(inode, blocks); | ||
| 1469 | } | ||
| 1470 | 1521 | ||
| 1471 | static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | 1522 | static int ext4_da_reserve_space(struct inode *inode, int nrblocks) |
| 1472 | { | 1523 | { |
| @@ -1490,7 +1541,6 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | |||
| 1490 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1541 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
| 1491 | return -ENOSPC; | 1542 | return -ENOSPC; |
| 1492 | } | 1543 | } |
| 1493 | |||
| 1494 | /* reduce fs free blocks counter */ | 1544 | /* reduce fs free blocks counter */ |
| 1495 | percpu_counter_sub(&sbi->s_freeblocks_counter, total); | 1545 | percpu_counter_sub(&sbi->s_freeblocks_counter, total); |
| 1496 | 1546 | ||
| @@ -1501,35 +1551,49 @@ static int ext4_da_reserve_space(struct inode *inode, int nrblocks) | |||
| 1501 | return 0; /* success */ | 1551 | return 0; /* success */ |
| 1502 | } | 1552 | } |
| 1503 | 1553 | ||
| 1504 | void ext4_da_release_space(struct inode *inode, int used, int to_free) | 1554 | static void ext4_da_release_space(struct inode *inode, int to_free) |
| 1505 | { | 1555 | { |
| 1506 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | 1556 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); |
| 1507 | int total, mdb, mdb_free, release; | 1557 | int total, mdb, mdb_free, release; |
| 1508 | 1558 | ||
| 1559 | if (!to_free) | ||
| 1560 | return; /* Nothing to release, exit */ | ||
| 1561 | |||
| 1509 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); | 1562 | spin_lock(&EXT4_I(inode)->i_block_reservation_lock); |
| 1563 | |||
| 1564 | if (!EXT4_I(inode)->i_reserved_data_blocks) { | ||
| 1565 | /* | ||
| 1566 | * if there is no reserved blocks, but we try to free some | ||
| 1567 | * then the counter is messed up somewhere. | ||
| 1568 | * but since this function is called from invalidate | ||
| 1569 | * page, it's harmless to return without any action | ||
| 1570 | */ | ||
| 1571 | printk(KERN_INFO "ext4 delalloc try to release %d reserved " | ||
| 1572 | "blocks for inode %lu, but there is no reserved " | ||
| 1573 | "data blocks\n", to_free, inode->i_ino); | ||
| 1574 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | ||
| 1575 | return; | ||
| 1576 | } | ||
| 1577 | |||
| 1510 | /* recalculate the number of metablocks still need to be reserved */ | 1578 | /* recalculate the number of metablocks still need to be reserved */ |
| 1511 | total = EXT4_I(inode)->i_reserved_data_blocks - used - to_free; | 1579 | total = EXT4_I(inode)->i_reserved_data_blocks - to_free; |
| 1512 | mdb = ext4_calc_metadata_amount(inode, total); | 1580 | mdb = ext4_calc_metadata_amount(inode, total); |
| 1513 | 1581 | ||
| 1514 | /* figure out how many metablocks to release */ | 1582 | /* figure out how many metablocks to release */ |
| 1515 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | 1583 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); |
| 1516 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; | 1584 | mdb_free = EXT4_I(inode)->i_reserved_meta_blocks - mdb; |
| 1517 | 1585 | ||
| 1518 | /* Account for allocated meta_blocks */ | ||
| 1519 | mdb_free -= EXT4_I(inode)->i_allocated_meta_blocks; | ||
| 1520 | |||
| 1521 | release = to_free + mdb_free; | 1586 | release = to_free + mdb_free; |
| 1522 | 1587 | ||
| 1523 | /* update fs free blocks counter for truncate case */ | 1588 | /* update fs free blocks counter for truncate case */ |
| 1524 | percpu_counter_add(&sbi->s_freeblocks_counter, release); | 1589 | percpu_counter_add(&sbi->s_freeblocks_counter, release); |
| 1525 | 1590 | ||
| 1526 | /* update per-inode reservations */ | 1591 | /* update per-inode reservations */ |
| 1527 | BUG_ON(used + to_free > EXT4_I(inode)->i_reserved_data_blocks); | 1592 | BUG_ON(to_free > EXT4_I(inode)->i_reserved_data_blocks); |
| 1528 | EXT4_I(inode)->i_reserved_data_blocks -= (used + to_free); | 1593 | EXT4_I(inode)->i_reserved_data_blocks -= to_free; |
| 1529 | 1594 | ||
| 1530 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); | 1595 | BUG_ON(mdb > EXT4_I(inode)->i_reserved_meta_blocks); |
| 1531 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; | 1596 | EXT4_I(inode)->i_reserved_meta_blocks = mdb; |
| 1532 | EXT4_I(inode)->i_allocated_meta_blocks = 0; | ||
| 1533 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); | 1597 | spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); |
| 1534 | } | 1598 | } |
| 1535 | 1599 | ||
| @@ -1551,7 +1615,7 @@ static void ext4_da_page_release_reservation(struct page *page, | |||
| 1551 | } | 1615 | } |
| 1552 | curr_off = next_off; | 1616 | curr_off = next_off; |
| 1553 | } while ((bh = bh->b_this_page) != head); | 1617 | } while ((bh = bh->b_this_page) != head); |
| 1554 | ext4_da_release_space(page->mapping->host, 0, to_release); | 1618 | ext4_da_release_space(page->mapping->host, to_release); |
| 1555 | } | 1619 | } |
| 1556 | 1620 | ||
| 1557 | /* | 1621 | /* |
| @@ -1564,11 +1628,13 @@ struct mpage_da_data { | |||
| 1564 | unsigned long first_page, next_page; /* extent of pages */ | 1628 | unsigned long first_page, next_page; /* extent of pages */ |
| 1565 | get_block_t *get_block; | 1629 | get_block_t *get_block; |
| 1566 | struct writeback_control *wbc; | 1630 | struct writeback_control *wbc; |
| 1631 | int io_done; | ||
| 1632 | long pages_written; | ||
| 1567 | }; | 1633 | }; |
| 1568 | 1634 | ||
| 1569 | /* | 1635 | /* |
| 1570 | * mpage_da_submit_io - walks through extent of pages and try to write | 1636 | * mpage_da_submit_io - walks through extent of pages and try to write |
| 1571 | * them with __mpage_writepage() | 1637 | * them with writepage() call back |
| 1572 | * | 1638 | * |
| 1573 | * @mpd->inode: inode | 1639 | * @mpd->inode: inode |
| 1574 | * @mpd->first_page: first page of the extent | 1640 | * @mpd->first_page: first page of the extent |
| @@ -1583,18 +1649,11 @@ struct mpage_da_data { | |||
| 1583 | static int mpage_da_submit_io(struct mpage_da_data *mpd) | 1649 | static int mpage_da_submit_io(struct mpage_da_data *mpd) |
| 1584 | { | 1650 | { |
| 1585 | struct address_space *mapping = mpd->inode->i_mapping; | 1651 | struct address_space *mapping = mpd->inode->i_mapping; |
| 1586 | struct mpage_data mpd_pp = { | ||
| 1587 | .bio = NULL, | ||
| 1588 | .last_block_in_bio = 0, | ||
| 1589 | .get_block = mpd->get_block, | ||
| 1590 | .use_writepage = 1, | ||
| 1591 | }; | ||
| 1592 | int ret = 0, err, nr_pages, i; | 1652 | int ret = 0, err, nr_pages, i; |
| 1593 | unsigned long index, end; | 1653 | unsigned long index, end; |
| 1594 | struct pagevec pvec; | 1654 | struct pagevec pvec; |
| 1595 | 1655 | ||
| 1596 | BUG_ON(mpd->next_page <= mpd->first_page); | 1656 | BUG_ON(mpd->next_page <= mpd->first_page); |
| 1597 | |||
| 1598 | pagevec_init(&pvec, 0); | 1657 | pagevec_init(&pvec, 0); |
| 1599 | index = mpd->first_page; | 1658 | index = mpd->first_page; |
| 1600 | end = mpd->next_page - 1; | 1659 | end = mpd->next_page - 1; |
| @@ -1612,8 +1671,9 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd) | |||
| 1612 | break; | 1671 | break; |
| 1613 | index++; | 1672 | index++; |
| 1614 | 1673 | ||
| 1615 | err = __mpage_writepage(page, mpd->wbc, &mpd_pp); | 1674 | err = mapping->a_ops->writepage(page, mpd->wbc); |
| 1616 | 1675 | if (!err) | |
| 1676 | mpd->pages_written++; | ||
| 1617 | /* | 1677 | /* |
| 1618 | * In error case, we have to continue because | 1678 | * In error case, we have to continue because |
| 1619 | * remaining pages are still locked | 1679 | * remaining pages are still locked |
| @@ -1624,9 +1684,6 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd) | |||
| 1624 | } | 1684 | } |
| 1625 | pagevec_release(&pvec); | 1685 | pagevec_release(&pvec); |
| 1626 | } | 1686 | } |
| 1627 | if (mpd_pp.bio) | ||
| 1628 | mpage_bio_submit(WRITE, mpd_pp.bio); | ||
| 1629 | |||
| 1630 | return ret; | 1687 | return ret; |
| 1631 | } | 1688 | } |
| 1632 | 1689 | ||
| @@ -1649,7 +1706,7 @@ static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical, | |||
| 1649 | int blocks = exbh->b_size >> inode->i_blkbits; | 1706 | int blocks = exbh->b_size >> inode->i_blkbits; |
| 1650 | sector_t pblock = exbh->b_blocknr, cur_logical; | 1707 | sector_t pblock = exbh->b_blocknr, cur_logical; |
| 1651 | struct buffer_head *head, *bh; | 1708 | struct buffer_head *head, *bh; |
| 1652 | unsigned long index, end; | 1709 | pgoff_t index, end; |
| 1653 | struct pagevec pvec; | 1710 | struct pagevec pvec; |
| 1654 | int nr_pages, i; | 1711 | int nr_pages, i; |
| 1655 | 1712 | ||
| @@ -1692,6 +1749,13 @@ static void mpage_put_bnr_to_bhs(struct mpage_da_data *mpd, sector_t logical, | |||
| 1692 | if (buffer_delay(bh)) { | 1749 | if (buffer_delay(bh)) { |
| 1693 | bh->b_blocknr = pblock; | 1750 | bh->b_blocknr = pblock; |
| 1694 | clear_buffer_delay(bh); | 1751 | clear_buffer_delay(bh); |
| 1752 | bh->b_bdev = inode->i_sb->s_bdev; | ||
| 1753 | } else if (buffer_unwritten(bh)) { | ||
| 1754 | bh->b_blocknr = pblock; | ||
| 1755 | clear_buffer_unwritten(bh); | ||
| 1756 | set_buffer_mapped(bh); | ||
| 1757 | set_buffer_new(bh); | ||
| 1758 | bh->b_bdev = inode->i_sb->s_bdev; | ||
| 1695 | } else if (buffer_mapped(bh)) | 1759 | } else if (buffer_mapped(bh)) |
| 1696 | BUG_ON(bh->b_blocknr != pblock); | 1760 | BUG_ON(bh->b_blocknr != pblock); |
| 1697 | 1761 | ||
| @@ -1727,13 +1791,11 @@ static inline void __unmap_underlying_blocks(struct inode *inode, | |||
| 1727 | * | 1791 | * |
| 1728 | * The function skips space we know is already mapped to disk blocks. | 1792 | * The function skips space we know is already mapped to disk blocks. |
| 1729 | * | 1793 | * |
| 1730 | * The function ignores errors ->get_block() returns, thus real | ||
| 1731 | * error handling is postponed to __mpage_writepage() | ||
| 1732 | */ | 1794 | */ |
| 1733 | static void mpage_da_map_blocks(struct mpage_da_data *mpd) | 1795 | static void mpage_da_map_blocks(struct mpage_da_data *mpd) |
| 1734 | { | 1796 | { |
| 1797 | int err = 0; | ||
| 1735 | struct buffer_head *lbh = &mpd->lbh; | 1798 | struct buffer_head *lbh = &mpd->lbh; |
| 1736 | int err = 0, remain = lbh->b_size; | ||
| 1737 | sector_t next = lbh->b_blocknr; | 1799 | sector_t next = lbh->b_blocknr; |
| 1738 | struct buffer_head new; | 1800 | struct buffer_head new; |
| 1739 | 1801 | ||
| @@ -1743,38 +1805,36 @@ static void mpage_da_map_blocks(struct mpage_da_data *mpd) | |||
| 1743 | if (buffer_mapped(lbh) && !buffer_delay(lbh)) | 1805 | if (buffer_mapped(lbh) && !buffer_delay(lbh)) |
| 1744 | return; | 1806 | return; |
| 1745 | 1807 | ||
| 1746 | while (remain) { | 1808 | new.b_state = lbh->b_state; |
| 1747 | new.b_state = lbh->b_state; | 1809 | new.b_blocknr = 0; |
| 1748 | new.b_blocknr = 0; | 1810 | new.b_size = lbh->b_size; |
| 1749 | new.b_size = remain; | ||
| 1750 | err = mpd->get_block(mpd->inode, next, &new, 1); | ||
| 1751 | if (err) { | ||
| 1752 | /* | ||
| 1753 | * Rather than implement own error handling | ||
| 1754 | * here, we just leave remaining blocks | ||
| 1755 | * unallocated and try again with ->writepage() | ||
| 1756 | */ | ||
| 1757 | break; | ||
| 1758 | } | ||
| 1759 | BUG_ON(new.b_size == 0); | ||
| 1760 | 1811 | ||
| 1761 | if (buffer_new(&new)) | 1812 | /* |
| 1762 | __unmap_underlying_blocks(mpd->inode, &new); | 1813 | * If we didn't accumulate anything |
| 1814 | * to write simply return | ||
| 1815 | */ | ||
| 1816 | if (!new.b_size) | ||
| 1817 | return; | ||
| 1818 | err = mpd->get_block(mpd->inode, next, &new, 1); | ||
| 1819 | if (err) | ||
| 1820 | return; | ||
| 1821 | BUG_ON(new.b_size == 0); | ||
| 1763 | 1822 | ||
| 1764 | /* | 1823 | if (buffer_new(&new)) |
| 1765 | * If blocks are delayed marked, we need to | 1824 | __unmap_underlying_blocks(mpd->inode, &new); |
| 1766 | * put actual blocknr and drop delayed bit | ||
| 1767 | */ | ||
| 1768 | if (buffer_delay(lbh)) | ||
| 1769 | mpage_put_bnr_to_bhs(mpd, next, &new); | ||
| 1770 | 1825 | ||
| 1771 | /* go for the remaining blocks */ | 1826 | /* |
| 1772 | next += new.b_size >> mpd->inode->i_blkbits; | 1827 | * If blocks are delayed marked, we need to |
| 1773 | remain -= new.b_size; | 1828 | * put actual blocknr and drop delayed bit |
| 1774 | } | 1829 | */ |
| 1830 | if (buffer_delay(lbh) || buffer_unwritten(lbh)) | ||
| 1831 | mpage_put_bnr_to_bhs(mpd, next, &new); | ||
| 1832 | |||
| 1833 | return; | ||
| 1775 | } | 1834 | } |
| 1776 | 1835 | ||
| 1777 | #define BH_FLAGS ((1 << BH_Uptodate) | (1 << BH_Mapped) | (1 << BH_Delay)) | 1836 | #define BH_FLAGS ((1 << BH_Uptodate) | (1 << BH_Mapped) | \ |
| 1837 | (1 << BH_Delay) | (1 << BH_Unwritten)) | ||
| 1778 | 1838 | ||
| 1779 | /* | 1839 | /* |
| 1780 | * mpage_add_bh_to_extent - try to add one more block to extent of blocks | 1840 | * mpage_add_bh_to_extent - try to add one more block to extent of blocks |
| @@ -1788,41 +1848,61 @@ static void mpage_da_map_blocks(struct mpage_da_data *mpd) | |||
| 1788 | static void mpage_add_bh_to_extent(struct mpage_da_data *mpd, | 1848 | static void mpage_add_bh_to_extent(struct mpage_da_data *mpd, |
| 1789 | sector_t logical, struct buffer_head *bh) | 1849 | sector_t logical, struct buffer_head *bh) |
| 1790 | { | 1850 | { |
| 1791 | struct buffer_head *lbh = &mpd->lbh; | ||
| 1792 | sector_t next; | 1851 | sector_t next; |
| 1852 | size_t b_size = bh->b_size; | ||
| 1853 | struct buffer_head *lbh = &mpd->lbh; | ||
| 1854 | int nrblocks = lbh->b_size >> mpd->inode->i_blkbits; | ||
| 1793 | 1855 | ||
| 1794 | next = lbh->b_blocknr + (lbh->b_size >> mpd->inode->i_blkbits); | 1856 | /* check if thereserved journal credits might overflow */ |
| 1795 | 1857 | if (!(EXT4_I(mpd->inode)->i_flags & EXT4_EXTENTS_FL)) { | |
| 1858 | if (nrblocks >= EXT4_MAX_TRANS_DATA) { | ||
| 1859 | /* | ||
| 1860 | * With non-extent format we are limited by the journal | ||
| 1861 | * credit available. Total credit needed to insert | ||
| 1862 | * nrblocks contiguous blocks is dependent on the | ||
| 1863 | * nrblocks. So limit nrblocks. | ||
| 1864 | */ | ||
| 1865 | goto flush_it; | ||
| 1866 | } else if ((nrblocks + (b_size >> mpd->inode->i_blkbits)) > | ||
| 1867 | EXT4_MAX_TRANS_DATA) { | ||
| 1868 | /* | ||
| 1869 | * Adding the new buffer_head would make it cross the | ||
| 1870 | * allowed limit for which we have journal credit | ||
| 1871 | * reserved. So limit the new bh->b_size | ||
| 1872 | */ | ||
| 1873 | b_size = (EXT4_MAX_TRANS_DATA - nrblocks) << | ||
| 1874 | mpd->inode->i_blkbits; | ||
| 1875 | /* we will do mpage_da_submit_io in the next loop */ | ||
| 1876 | } | ||
| 1877 | } | ||
| 1796 | /* | 1878 | /* |
| 1797 | * First block in the extent | 1879 | * First block in the extent |
| 1798 | */ | 1880 | */ |
| 1799 | if (lbh->b_size == 0) { | 1881 | if (lbh->b_size == 0) { |
| 1800 | lbh->b_blocknr = logical; | 1882 | lbh->b_blocknr = logical; |
| 1801 | lbh->b_size = bh->b_size; | 1883 | lbh->b_size = b_size; |
| 1802 | lbh->b_state = bh->b_state & BH_FLAGS; | 1884 | lbh->b_state = bh->b_state & BH_FLAGS; |
| 1803 | return; | 1885 | return; |
| 1804 | } | 1886 | } |
| 1805 | 1887 | ||
| 1888 | next = lbh->b_blocknr + nrblocks; | ||
| 1806 | /* | 1889 | /* |
| 1807 | * Can we merge the block to our big extent? | 1890 | * Can we merge the block to our big extent? |
| 1808 | */ | 1891 | */ |
| 1809 | if (logical == next && (bh->b_state & BH_FLAGS) == lbh->b_state) { | 1892 | if (logical == next && (bh->b_state & BH_FLAGS) == lbh->b_state) { |
| 1810 | lbh->b_size += bh->b_size; | 1893 | lbh->b_size += b_size; |
| 1811 | return; | 1894 | return; |
| 1812 | } | 1895 | } |
| 1813 | 1896 | ||
| 1897 | flush_it: | ||
| 1814 | /* | 1898 | /* |
| 1815 | * We couldn't merge the block to our extent, so we | 1899 | * We couldn't merge the block to our extent, so we |
| 1816 | * need to flush current extent and start new one | 1900 | * need to flush current extent and start new one |
| 1817 | */ | 1901 | */ |
| 1818 | mpage_da_map_blocks(mpd); | 1902 | mpage_da_map_blocks(mpd); |
| 1819 | 1903 | mpage_da_submit_io(mpd); | |
| 1820 | /* | 1904 | mpd->io_done = 1; |
| 1821 | * Now start a new extent | 1905 | return; |
| 1822 | */ | ||
| 1823 | lbh->b_size = bh->b_size; | ||
| 1824 | lbh->b_state = bh->b_state & BH_FLAGS; | ||
| 1825 | lbh->b_blocknr = logical; | ||
| 1826 | } | 1906 | } |
| 1827 | 1907 | ||
| 1828 | /* | 1908 | /* |
| @@ -1842,17 +1922,35 @@ static int __mpage_da_writepage(struct page *page, | |||
| 1842 | struct buffer_head *bh, *head, fake; | 1922 | struct buffer_head *bh, *head, fake; |
| 1843 | sector_t logical; | 1923 | sector_t logical; |
| 1844 | 1924 | ||
| 1925 | if (mpd->io_done) { | ||
| 1926 | /* | ||
| 1927 | * Rest of the page in the page_vec | ||
| 1928 | * redirty then and skip then. We will | ||
| 1929 | * try to to write them again after | ||
| 1930 | * starting a new transaction | ||
| 1931 | */ | ||
| 1932 | redirty_page_for_writepage(wbc, page); | ||
| 1933 | unlock_page(page); | ||
| 1934 | return MPAGE_DA_EXTENT_TAIL; | ||
| 1935 | } | ||
| 1845 | /* | 1936 | /* |
| 1846 | * Can we merge this page to current extent? | 1937 | * Can we merge this page to current extent? |
| 1847 | */ | 1938 | */ |
| 1848 | if (mpd->next_page != page->index) { | 1939 | if (mpd->next_page != page->index) { |
| 1849 | /* | 1940 | /* |
| 1850 | * Nope, we can't. So, we map non-allocated blocks | 1941 | * Nope, we can't. So, we map non-allocated blocks |
| 1851 | * and start IO on them using __mpage_writepage() | 1942 | * and start IO on them using writepage() |
| 1852 | */ | 1943 | */ |
| 1853 | if (mpd->next_page != mpd->first_page) { | 1944 | if (mpd->next_page != mpd->first_page) { |
| 1854 | mpage_da_map_blocks(mpd); | 1945 | mpage_da_map_blocks(mpd); |
| 1855 | mpage_da_submit_io(mpd); | 1946 | mpage_da_submit_io(mpd); |
| 1947 | /* | ||
| 1948 | * skip rest of the page in the page_vec | ||
| 1949 | */ | ||
| 1950 | mpd->io_done = 1; | ||
| 1951 | redirty_page_for_writepage(wbc, page); | ||
| 1952 | unlock_page(page); | ||
| 1953 | return MPAGE_DA_EXTENT_TAIL; | ||
| 1856 | } | 1954 | } |
| 1857 | 1955 | ||
| 1858 | /* | 1956 | /* |
| @@ -1883,6 +1981,8 @@ static int __mpage_da_writepage(struct page *page, | |||
| 1883 | set_buffer_dirty(bh); | 1981 | set_buffer_dirty(bh); |
| 1884 | set_buffer_uptodate(bh); | 1982 | set_buffer_uptodate(bh); |
| 1885 | mpage_add_bh_to_extent(mpd, logical, bh); | 1983 | mpage_add_bh_to_extent(mpd, logical, bh); |
| 1984 | if (mpd->io_done) | ||
| 1985 | return MPAGE_DA_EXTENT_TAIL; | ||
| 1886 | } else { | 1986 | } else { |
| 1887 | /* | 1987 | /* |
| 1888 | * Page with regular buffer heads, just add all dirty ones | 1988 | * Page with regular buffer heads, just add all dirty ones |
| @@ -1891,8 +1991,12 @@ static int __mpage_da_writepage(struct page *page, | |||
| 1891 | bh = head; | 1991 | bh = head; |
| 1892 | do { | 1992 | do { |
| 1893 | BUG_ON(buffer_locked(bh)); | 1993 | BUG_ON(buffer_locked(bh)); |
| 1894 | if (buffer_dirty(bh)) | 1994 | if (buffer_dirty(bh) && |
| 1995 | (!buffer_mapped(bh) || buffer_delay(bh))) { | ||
| 1895 | mpage_add_bh_to_extent(mpd, logical, bh); | 1996 | mpage_add_bh_to_extent(mpd, logical, bh); |
| 1997 | if (mpd->io_done) | ||
| 1998 | return MPAGE_DA_EXTENT_TAIL; | ||
| 1999 | } | ||
| 1896 | logical++; | 2000 | logical++; |
| 1897 | } while ((bh = bh->b_this_page) != head); | 2001 | } while ((bh = bh->b_this_page) != head); |
| 1898 | } | 2002 | } |
| @@ -1911,22 +2015,13 @@ static int __mpage_da_writepage(struct page *page, | |||
| 1911 | * | 2015 | * |
| 1912 | * This is a library function, which implements the writepages() | 2016 | * This is a library function, which implements the writepages() |
| 1913 | * address_space_operation. | 2017 | * address_space_operation. |
| 1914 | * | ||
| 1915 | * In order to avoid duplication of logic that deals with partial pages, | ||
| 1916 | * multiple bio per page, etc, we find non-allocated blocks, allocate | ||
| 1917 | * them with minimal calls to ->get_block() and re-use __mpage_writepage() | ||
| 1918 | * | ||
| 1919 | * It's important that we call __mpage_writepage() only once for each | ||
| 1920 | * involved page, otherwise we'd have to implement more complicated logic | ||
| 1921 | * to deal with pages w/o PG_lock or w/ PG_writeback and so on. | ||
| 1922 | * | ||
| 1923 | * See comments to mpage_writepages() | ||
| 1924 | */ | 2018 | */ |
| 1925 | static int mpage_da_writepages(struct address_space *mapping, | 2019 | static int mpage_da_writepages(struct address_space *mapping, |
| 1926 | struct writeback_control *wbc, | 2020 | struct writeback_control *wbc, |
| 1927 | get_block_t get_block) | 2021 | get_block_t get_block) |
| 1928 | { | 2022 | { |
| 1929 | struct mpage_da_data mpd; | 2023 | struct mpage_da_data mpd; |
| 2024 | long to_write; | ||
| 1930 | int ret; | 2025 | int ret; |
| 1931 | 2026 | ||
| 1932 | if (!get_block) | 2027 | if (!get_block) |
| @@ -1940,17 +2035,22 @@ static int mpage_da_writepages(struct address_space *mapping, | |||
| 1940 | mpd.first_page = 0; | 2035 | mpd.first_page = 0; |
| 1941 | mpd.next_page = 0; | 2036 | mpd.next_page = 0; |
| 1942 | mpd.get_block = get_block; | 2037 | mpd.get_block = get_block; |
| 2038 | mpd.io_done = 0; | ||
| 2039 | mpd.pages_written = 0; | ||
| 2040 | |||
| 2041 | to_write = wbc->nr_to_write; | ||
| 1943 | 2042 | ||
| 1944 | ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, &mpd); | 2043 | ret = write_cache_pages(mapping, wbc, __mpage_da_writepage, &mpd); |
| 1945 | 2044 | ||
| 1946 | /* | 2045 | /* |
| 1947 | * Handle last extent of pages | 2046 | * Handle last extent of pages |
| 1948 | */ | 2047 | */ |
| 1949 | if (mpd.next_page != mpd.first_page) { | 2048 | if (!mpd.io_done && mpd.next_page != mpd.first_page) { |
| 1950 | mpage_da_map_blocks(&mpd); | 2049 | mpage_da_map_blocks(&mpd); |
| 1951 | mpage_da_submit_io(&mpd); | 2050 | mpage_da_submit_io(&mpd); |
| 1952 | } | 2051 | } |
| 1953 | 2052 | ||
| 2053 | wbc->nr_to_write = to_write - mpd.pages_written; | ||
| 1954 | return ret; | 2054 | return ret; |
| 1955 | } | 2055 | } |
| 1956 | 2056 | ||
| @@ -2155,63 +2255,95 @@ static int ext4_da_writepage(struct page *page, | |||
| 2155 | } | 2255 | } |
| 2156 | 2256 | ||
| 2157 | /* | 2257 | /* |
| 2158 | * For now just follow the DIO way to estimate the max credits | 2258 | * This is called via ext4_da_writepages() to |
| 2159 | * needed to write out EXT4_MAX_WRITEBACK_PAGES. | 2259 | * calulate the total number of credits to reserve to fit |
| 2160 | * todo: need to calculate the max credits need for | 2260 | * a single extent allocation into a single transaction, |
| 2161 | * extent based files, currently the DIO credits is based on | 2261 | * ext4_da_writpeages() will loop calling this before |
| 2162 | * indirect-blocks mapping way. | 2262 | * the block allocation. |
| 2163 | * | ||
| 2164 | * Probably should have a generic way to calculate credits | ||
| 2165 | * for DIO, writepages, and truncate | ||
| 2166 | */ | 2263 | */ |
| 2167 | #define EXT4_MAX_WRITEBACK_PAGES DIO_MAX_BLOCKS | 2264 | |
| 2168 | #define EXT4_MAX_WRITEBACK_CREDITS DIO_CREDITS | 2265 | static int ext4_da_writepages_trans_blocks(struct inode *inode) |
| 2266 | { | ||
| 2267 | int max_blocks = EXT4_I(inode)->i_reserved_data_blocks; | ||
| 2268 | |||
| 2269 | /* | ||
| 2270 | * With non-extent format the journal credit needed to | ||
| 2271 | * insert nrblocks contiguous block is dependent on | ||
| 2272 | * number of contiguous block. So we will limit | ||
| 2273 | * number of contiguous block to a sane value | ||
| 2274 | */ | ||
| 2275 | if (!(inode->i_flags & EXT4_EXTENTS_FL) && | ||
| 2276 | (max_blocks > EXT4_MAX_TRANS_DATA)) | ||
| 2277 | max_blocks = EXT4_MAX_TRANS_DATA; | ||
| 2278 | |||
| 2279 | return ext4_chunk_trans_blocks(inode, max_blocks); | ||
| 2280 | } | ||
| 2169 | 2281 | ||
| 2170 | static int ext4_da_writepages(struct address_space *mapping, | 2282 | static int ext4_da_writepages(struct address_space *mapping, |
| 2171 | struct writeback_control *wbc) | 2283 | struct writeback_control *wbc) |
| 2172 | { | 2284 | { |
| 2173 | struct inode *inode = mapping->host; | ||
| 2174 | handle_t *handle = NULL; | 2285 | handle_t *handle = NULL; |
| 2175 | int needed_blocks; | ||
| 2176 | int ret = 0; | ||
| 2177 | long to_write; | ||
| 2178 | loff_t range_start = 0; | 2286 | loff_t range_start = 0; |
| 2287 | struct inode *inode = mapping->host; | ||
| 2288 | int needed_blocks, ret = 0, nr_to_writebump = 0; | ||
| 2289 | long to_write, pages_skipped = 0; | ||
| 2290 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); | ||
| 2179 | 2291 | ||
| 2180 | /* | 2292 | /* |
| 2181 | * No pages to write? This is mainly a kludge to avoid starting | 2293 | * No pages to write? This is mainly a kludge to avoid starting |
| 2182 | * a transaction for special inodes like journal inode on last iput() | 2294 | * a transaction for special inodes like journal inode on last iput() |
| 2183 | * because that could violate lock ordering on umount | 2295 | * because that could violate lock ordering on umount |
| 2184 | */ | 2296 | */ |
| 2185 | if (!mapping->nrpages) | 2297 | if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) |
| 2186 | return 0; | 2298 | return 0; |
| 2187 | |||
| 2188 | /* | 2299 | /* |
| 2189 | * Estimate the worse case needed credits to write out | 2300 | * Make sure nr_to_write is >= sbi->s_mb_stream_request |
| 2190 | * EXT4_MAX_BUF_BLOCKS pages | 2301 | * This make sure small files blocks are allocated in |
| 2302 | * single attempt. This ensure that small files | ||
| 2303 | * get less fragmented. | ||
| 2191 | */ | 2304 | */ |
| 2192 | needed_blocks = EXT4_MAX_WRITEBACK_CREDITS; | 2305 | if (wbc->nr_to_write < sbi->s_mb_stream_request) { |
| 2306 | nr_to_writebump = sbi->s_mb_stream_request - wbc->nr_to_write; | ||
| 2307 | wbc->nr_to_write = sbi->s_mb_stream_request; | ||
| 2308 | } | ||
| 2193 | 2309 | ||
| 2194 | to_write = wbc->nr_to_write; | 2310 | if (!wbc->range_cyclic) |
| 2195 | if (!wbc->range_cyclic) { | ||
| 2196 | /* | 2311 | /* |
| 2197 | * If range_cyclic is not set force range_cont | 2312 | * If range_cyclic is not set force range_cont |
| 2198 | * and save the old writeback_index | 2313 | * and save the old writeback_index |
| 2199 | */ | 2314 | */ |
| 2200 | wbc->range_cont = 1; | 2315 | wbc->range_cont = 1; |
| 2201 | range_start = wbc->range_start; | ||
| 2202 | } | ||
| 2203 | 2316 | ||
| 2204 | while (!ret && to_write) { | 2317 | range_start = wbc->range_start; |
| 2318 | pages_skipped = wbc->pages_skipped; | ||
| 2319 | |||
| 2320 | restart_loop: | ||
| 2321 | to_write = wbc->nr_to_write; | ||
| 2322 | while (!ret && to_write > 0) { | ||
| 2323 | |||
| 2324 | /* | ||
| 2325 | * we insert one extent at a time. So we need | ||
| 2326 | * credit needed for single extent allocation. | ||
| 2327 | * journalled mode is currently not supported | ||
| 2328 | * by delalloc | ||
| 2329 | */ | ||
| 2330 | BUG_ON(ext4_should_journal_data(inode)); | ||
| 2331 | needed_blocks = ext4_da_writepages_trans_blocks(inode); | ||
| 2332 | |||
| 2205 | /* start a new transaction*/ | 2333 | /* start a new transaction*/ |
| 2206 | handle = ext4_journal_start(inode, needed_blocks); | 2334 | handle = ext4_journal_start(inode, needed_blocks); |
| 2207 | if (IS_ERR(handle)) { | 2335 | if (IS_ERR(handle)) { |
| 2208 | ret = PTR_ERR(handle); | 2336 | ret = PTR_ERR(handle); |
| 2337 | printk(KERN_EMERG "%s: jbd2_start: " | ||
| 2338 | "%ld pages, ino %lu; err %d\n", __func__, | ||
| 2339 | wbc->nr_to_write, inode->i_ino, ret); | ||
| 2340 | dump_stack(); | ||
| 2209 | goto out_writepages; | 2341 | goto out_writepages; |
| 2210 | } | 2342 | } |
| 2211 | if (ext4_should_order_data(inode)) { | 2343 | if (ext4_should_order_data(inode)) { |
| 2212 | /* | 2344 | /* |
| 2213 | * With ordered mode we need to add | 2345 | * With ordered mode we need to add |
| 2214 | * the inode to the journal handle | 2346 | * the inode to the journal handl |
| 2215 | * when we do block allocation. | 2347 | * when we do block allocation. |
| 2216 | */ | 2348 | */ |
| 2217 | ret = ext4_jbd2_file_inode(handle, inode); | 2349 | ret = ext4_jbd2_file_inode(handle, inode); |
| @@ -2219,20 +2351,20 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
| 2219 | ext4_journal_stop(handle); | 2351 | ext4_journal_stop(handle); |
| 2220 | goto out_writepages; | 2352 | goto out_writepages; |
| 2221 | } | 2353 | } |
| 2222 | |||
| 2223 | } | 2354 | } |
| 2224 | /* | ||
| 2225 | * set the max dirty pages could be write at a time | ||
| 2226 | * to fit into the reserved transaction credits | ||
| 2227 | */ | ||
| 2228 | if (wbc->nr_to_write > EXT4_MAX_WRITEBACK_PAGES) | ||
| 2229 | wbc->nr_to_write = EXT4_MAX_WRITEBACK_PAGES; | ||
| 2230 | 2355 | ||
| 2231 | to_write -= wbc->nr_to_write; | 2356 | to_write -= wbc->nr_to_write; |
| 2232 | ret = mpage_da_writepages(mapping, wbc, | 2357 | ret = mpage_da_writepages(mapping, wbc, |
| 2233 | ext4_da_get_block_write); | 2358 | ext4_da_get_block_write); |
| 2234 | ext4_journal_stop(handle); | 2359 | ext4_journal_stop(handle); |
| 2235 | if (wbc->nr_to_write) { | 2360 | if (ret == MPAGE_DA_EXTENT_TAIL) { |
| 2361 | /* | ||
| 2362 | * got one extent now try with | ||
| 2363 | * rest of the pages | ||
| 2364 | */ | ||
| 2365 | to_write += wbc->nr_to_write; | ||
| 2366 | ret = 0; | ||
| 2367 | } else if (wbc->nr_to_write) { | ||
| 2236 | /* | 2368 | /* |
| 2237 | * There is no more writeout needed | 2369 | * There is no more writeout needed |
| 2238 | * or we requested for a noblocking writeout | 2370 | * or we requested for a noblocking writeout |
| @@ -2244,10 +2376,18 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
| 2244 | wbc->nr_to_write = to_write; | 2376 | wbc->nr_to_write = to_write; |
| 2245 | } | 2377 | } |
| 2246 | 2378 | ||
| 2247 | out_writepages: | 2379 | if (wbc->range_cont && (pages_skipped != wbc->pages_skipped)) { |
| 2248 | wbc->nr_to_write = to_write; | 2380 | /* We skipped pages in this loop */ |
| 2249 | if (range_start) | ||
| 2250 | wbc->range_start = range_start; | 2381 | wbc->range_start = range_start; |
| 2382 | wbc->nr_to_write = to_write + | ||
| 2383 | wbc->pages_skipped - pages_skipped; | ||
| 2384 | wbc->pages_skipped = pages_skipped; | ||
| 2385 | goto restart_loop; | ||
| 2386 | } | ||
| 2387 | |||
| 2388 | out_writepages: | ||
| 2389 | wbc->nr_to_write = to_write - nr_to_writebump; | ||
| 2390 | wbc->range_start = range_start; | ||
| 2251 | return ret; | 2391 | return ret; |
| 2252 | } | 2392 | } |
| 2253 | 2393 | ||
| @@ -2280,8 +2420,11 @@ retry: | |||
| 2280 | } | 2420 | } |
| 2281 | 2421 | ||
| 2282 | page = __grab_cache_page(mapping, index); | 2422 | page = __grab_cache_page(mapping, index); |
| 2283 | if (!page) | 2423 | if (!page) { |
| 2284 | return -ENOMEM; | 2424 | ext4_journal_stop(handle); |
| 2425 | ret = -ENOMEM; | ||
| 2426 | goto out; | ||
| 2427 | } | ||
| 2285 | *pagep = page; | 2428 | *pagep = page; |
| 2286 | 2429 | ||
| 2287 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 2430 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| @@ -2806,59 +2949,63 @@ static int ext4_journalled_set_page_dirty(struct page *page) | |||
| 2806 | } | 2949 | } |
| 2807 | 2950 | ||
| 2808 | static const struct address_space_operations ext4_ordered_aops = { | 2951 | static const struct address_space_operations ext4_ordered_aops = { |
| 2809 | .readpage = ext4_readpage, | 2952 | .readpage = ext4_readpage, |
| 2810 | .readpages = ext4_readpages, | 2953 | .readpages = ext4_readpages, |
| 2811 | .writepage = ext4_normal_writepage, | 2954 | .writepage = ext4_normal_writepage, |
| 2812 | .sync_page = block_sync_page, | 2955 | .sync_page = block_sync_page, |
| 2813 | .write_begin = ext4_write_begin, | 2956 | .write_begin = ext4_write_begin, |
| 2814 | .write_end = ext4_ordered_write_end, | 2957 | .write_end = ext4_ordered_write_end, |
| 2815 | .bmap = ext4_bmap, | 2958 | .bmap = ext4_bmap, |
| 2816 | .invalidatepage = ext4_invalidatepage, | 2959 | .invalidatepage = ext4_invalidatepage, |
| 2817 | .releasepage = ext4_releasepage, | 2960 | .releasepage = ext4_releasepage, |
| 2818 | .direct_IO = ext4_direct_IO, | 2961 | .direct_IO = ext4_direct_IO, |
| 2819 | .migratepage = buffer_migrate_page, | 2962 | .migratepage = buffer_migrate_page, |
| 2963 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2820 | }; | 2964 | }; |
| 2821 | 2965 | ||
| 2822 | static const struct address_space_operations ext4_writeback_aops = { | 2966 | static const struct address_space_operations ext4_writeback_aops = { |
| 2823 | .readpage = ext4_readpage, | 2967 | .readpage = ext4_readpage, |
| 2824 | .readpages = ext4_readpages, | 2968 | .readpages = ext4_readpages, |
| 2825 | .writepage = ext4_normal_writepage, | 2969 | .writepage = ext4_normal_writepage, |
| 2826 | .sync_page = block_sync_page, | 2970 | .sync_page = block_sync_page, |
| 2827 | .write_begin = ext4_write_begin, | 2971 | .write_begin = ext4_write_begin, |
| 2828 | .write_end = ext4_writeback_write_end, | 2972 | .write_end = ext4_writeback_write_end, |
| 2829 | .bmap = ext4_bmap, | 2973 | .bmap = ext4_bmap, |
| 2830 | .invalidatepage = ext4_invalidatepage, | 2974 | .invalidatepage = ext4_invalidatepage, |
| 2831 | .releasepage = ext4_releasepage, | 2975 | .releasepage = ext4_releasepage, |
| 2832 | .direct_IO = ext4_direct_IO, | 2976 | .direct_IO = ext4_direct_IO, |
| 2833 | .migratepage = buffer_migrate_page, | 2977 | .migratepage = buffer_migrate_page, |
| 2978 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2834 | }; | 2979 | }; |
| 2835 | 2980 | ||
| 2836 | static const struct address_space_operations ext4_journalled_aops = { | 2981 | static const struct address_space_operations ext4_journalled_aops = { |
| 2837 | .readpage = ext4_readpage, | 2982 | .readpage = ext4_readpage, |
| 2838 | .readpages = ext4_readpages, | 2983 | .readpages = ext4_readpages, |
| 2839 | .writepage = ext4_journalled_writepage, | 2984 | .writepage = ext4_journalled_writepage, |
| 2840 | .sync_page = block_sync_page, | 2985 | .sync_page = block_sync_page, |
| 2841 | .write_begin = ext4_write_begin, | 2986 | .write_begin = ext4_write_begin, |
| 2842 | .write_end = ext4_journalled_write_end, | 2987 | .write_end = ext4_journalled_write_end, |
| 2843 | .set_page_dirty = ext4_journalled_set_page_dirty, | 2988 | .set_page_dirty = ext4_journalled_set_page_dirty, |
| 2844 | .bmap = ext4_bmap, | 2989 | .bmap = ext4_bmap, |
| 2845 | .invalidatepage = ext4_invalidatepage, | 2990 | .invalidatepage = ext4_invalidatepage, |
| 2846 | .releasepage = ext4_releasepage, | 2991 | .releasepage = ext4_releasepage, |
| 2992 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2847 | }; | 2993 | }; |
| 2848 | 2994 | ||
| 2849 | static const struct address_space_operations ext4_da_aops = { | 2995 | static const struct address_space_operations ext4_da_aops = { |
| 2850 | .readpage = ext4_readpage, | 2996 | .readpage = ext4_readpage, |
| 2851 | .readpages = ext4_readpages, | 2997 | .readpages = ext4_readpages, |
| 2852 | .writepage = ext4_da_writepage, | 2998 | .writepage = ext4_da_writepage, |
| 2853 | .writepages = ext4_da_writepages, | 2999 | .writepages = ext4_da_writepages, |
| 2854 | .sync_page = block_sync_page, | 3000 | .sync_page = block_sync_page, |
| 2855 | .write_begin = ext4_da_write_begin, | 3001 | .write_begin = ext4_da_write_begin, |
| 2856 | .write_end = ext4_da_write_end, | 3002 | .write_end = ext4_da_write_end, |
| 2857 | .bmap = ext4_bmap, | 3003 | .bmap = ext4_bmap, |
| 2858 | .invalidatepage = ext4_da_invalidatepage, | 3004 | .invalidatepage = ext4_da_invalidatepage, |
| 2859 | .releasepage = ext4_releasepage, | 3005 | .releasepage = ext4_releasepage, |
| 2860 | .direct_IO = ext4_direct_IO, | 3006 | .direct_IO = ext4_direct_IO, |
| 2861 | .migratepage = buffer_migrate_page, | 3007 | .migratepage = buffer_migrate_page, |
| 3008 | .is_partially_uptodate = block_is_partially_uptodate, | ||
| 2862 | }; | 3009 | }; |
| 2863 | 3010 | ||
| 2864 | void ext4_set_aops(struct inode *inode) | 3011 | void ext4_set_aops(struct inode *inode) |
| @@ -3430,6 +3577,9 @@ void ext4_truncate(struct inode *inode) | |||
| 3430 | * modify the block allocation tree. | 3577 | * modify the block allocation tree. |
| 3431 | */ | 3578 | */ |
| 3432 | down_write(&ei->i_data_sem); | 3579 | down_write(&ei->i_data_sem); |
| 3580 | |||
| 3581 | ext4_discard_reservation(inode); | ||
| 3582 | |||
| 3433 | /* | 3583 | /* |
| 3434 | * The orphan list entry will now protect us from any crash which | 3584 | * The orphan list entry will now protect us from any crash which |
| 3435 | * occurs before the truncate completes, so it is now safe to propagate | 3585 | * occurs before the truncate completes, so it is now safe to propagate |
| @@ -3499,8 +3649,6 @@ do_indirects: | |||
| 3499 | ; | 3649 | ; |
| 3500 | } | 3650 | } |
| 3501 | 3651 | ||
| 3502 | ext4_discard_reservation(inode); | ||
| 3503 | |||
| 3504 | up_write(&ei->i_data_sem); | 3652 | up_write(&ei->i_data_sem); |
| 3505 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | 3653 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); |
| 3506 | ext4_mark_inode_dirty(handle, inode); | 3654 | ext4_mark_inode_dirty(handle, inode); |
| @@ -3586,6 +3734,16 @@ static int __ext4_get_inode_loc(struct inode *inode, | |||
| 3586 | } | 3734 | } |
| 3587 | if (!buffer_uptodate(bh)) { | 3735 | if (!buffer_uptodate(bh)) { |
| 3588 | lock_buffer(bh); | 3736 | lock_buffer(bh); |
| 3737 | |||
| 3738 | /* | ||
| 3739 | * If the buffer has the write error flag, we have failed | ||
| 3740 | * to write out another inode in the same block. In this | ||
| 3741 | * case, we don't have to read the block because we may | ||
| 3742 | * read the old inode data successfully. | ||
| 3743 | */ | ||
| 3744 | if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) | ||
| 3745 | set_buffer_uptodate(bh); | ||
| 3746 | |||
| 3589 | if (buffer_uptodate(bh)) { | 3747 | if (buffer_uptodate(bh)) { |
| 3590 | /* someone brought it uptodate while we waited */ | 3748 | /* someone brought it uptodate while we waited */ |
| 3591 | unlock_buffer(bh); | 3749 | unlock_buffer(bh); |
| @@ -4258,57 +4416,129 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 4258 | return 0; | 4416 | return 0; |
| 4259 | } | 4417 | } |
| 4260 | 4418 | ||
| 4419 | static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks, | ||
| 4420 | int chunk) | ||
| 4421 | { | ||
| 4422 | int indirects; | ||
| 4423 | |||
| 4424 | /* if nrblocks are contiguous */ | ||
| 4425 | if (chunk) { | ||
| 4426 | /* | ||
| 4427 | * With N contiguous data blocks, it need at most | ||
| 4428 | * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) indirect blocks | ||
| 4429 | * 2 dindirect blocks | ||
| 4430 | * 1 tindirect block | ||
| 4431 | */ | ||
| 4432 | indirects = nrblocks / EXT4_ADDR_PER_BLOCK(inode->i_sb); | ||
| 4433 | return indirects + 3; | ||
| 4434 | } | ||
| 4435 | /* | ||
| 4436 | * if nrblocks are not contiguous, worse case, each block touch | ||
| 4437 | * a indirect block, and each indirect block touch a double indirect | ||
| 4438 | * block, plus a triple indirect block | ||
| 4439 | */ | ||
| 4440 | indirects = nrblocks * 2 + 1; | ||
| 4441 | return indirects; | ||
| 4442 | } | ||
| 4443 | |||
| 4444 | static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk) | ||
| 4445 | { | ||
| 4446 | if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)) | ||
| 4447 | return ext4_indirect_trans_blocks(inode, nrblocks, 0); | ||
| 4448 | return ext4_ext_index_trans_blocks(inode, nrblocks, 0); | ||
| 4449 | } | ||
| 4261 | /* | 4450 | /* |
| 4262 | * How many blocks doth make a writepage()? | 4451 | * Account for index blocks, block groups bitmaps and block group |
| 4452 | * descriptor blocks if modify datablocks and index blocks | ||
| 4453 | * worse case, the indexs blocks spread over different block groups | ||
| 4263 | * | 4454 | * |
| 4264 | * With N blocks per page, it may be: | 4455 | * If datablocks are discontiguous, they are possible to spread over |
| 4265 | * N data blocks | 4456 | * different block groups too. If they are contiugous, with flexbg, |
| 4266 | * 2 indirect block | 4457 | * they could still across block group boundary. |
| 4267 | * 2 dindirect | ||
| 4268 | * 1 tindirect | ||
| 4269 | * N+5 bitmap blocks (from the above) | ||
| 4270 | * N+5 group descriptor summary blocks | ||
| 4271 | * 1 inode block | ||
| 4272 | * 1 superblock. | ||
| 4273 | * 2 * EXT4_SINGLEDATA_TRANS_BLOCKS for the quote files | ||
| 4274 | * | 4458 | * |
| 4275 | * 3 * (N + 5) + 2 + 2 * EXT4_SINGLEDATA_TRANS_BLOCKS | 4459 | * Also account for superblock, inode, quota and xattr blocks |
| 4276 | * | 4460 | */ |
| 4277 | * With ordered or writeback data it's the same, less the N data blocks. | 4461 | int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk) |
| 4462 | { | ||
| 4463 | int groups, gdpblocks; | ||
| 4464 | int idxblocks; | ||
| 4465 | int ret = 0; | ||
| 4466 | |||
| 4467 | /* | ||
| 4468 | * How many index blocks need to touch to modify nrblocks? | ||
| 4469 | * The "Chunk" flag indicating whether the nrblocks is | ||
| 4470 | * physically contiguous on disk | ||
| 4471 | * | ||
| 4472 | * For Direct IO and fallocate, they calls get_block to allocate | ||
| 4473 | * one single extent at a time, so they could set the "Chunk" flag | ||
| 4474 | */ | ||
| 4475 | idxblocks = ext4_index_trans_blocks(inode, nrblocks, chunk); | ||
| 4476 | |||
| 4477 | ret = idxblocks; | ||
| 4478 | |||
| 4479 | /* | ||
| 4480 | * Now let's see how many group bitmaps and group descriptors need | ||
| 4481 | * to account | ||
| 4482 | */ | ||
| 4483 | groups = idxblocks; | ||
| 4484 | if (chunk) | ||
| 4485 | groups += 1; | ||
| 4486 | else | ||
| 4487 | groups += nrblocks; | ||
| 4488 | |||
| 4489 | gdpblocks = groups; | ||
| 4490 | if (groups > EXT4_SB(inode->i_sb)->s_groups_count) | ||
| 4491 | groups = EXT4_SB(inode->i_sb)->s_groups_count; | ||
| 4492 | if (groups > EXT4_SB(inode->i_sb)->s_gdb_count) | ||
| 4493 | gdpblocks = EXT4_SB(inode->i_sb)->s_gdb_count; | ||
| 4494 | |||
| 4495 | /* bitmaps and block group descriptor blocks */ | ||
| 4496 | ret += groups + gdpblocks; | ||
| 4497 | |||
| 4498 | /* Blocks for super block, inode, quota and xattr blocks */ | ||
| 4499 | ret += EXT4_META_TRANS_BLOCKS(inode->i_sb); | ||
| 4500 | |||
| 4501 | return ret; | ||
| 4502 | } | ||
| 4503 | |||
| 4504 | /* | ||
| 4505 | * Calulate the total number of credits to reserve to fit | ||
| 4506 | * the modification of a single pages into a single transaction, | ||
| 4507 | * which may include multiple chunks of block allocations. | ||
| 4278 | * | 4508 | * |
| 4279 | * If the inode's direct blocks can hold an integral number of pages then a | 4509 | * This could be called via ext4_write_begin() |
| 4280 | * page cannot straddle two indirect blocks, and we can only touch one indirect | ||
| 4281 | * and dindirect block, and the "5" above becomes "3". | ||
| 4282 | * | 4510 | * |
| 4283 | * This still overestimates under most circumstances. If we were to pass the | 4511 | * We need to consider the worse case, when |
| 4284 | * start and end offsets in here as well we could do block_to_path() on each | 4512 | * one new block per extent. |
| 4285 | * block and work out the exact number of indirects which are touched. Pah. | ||
| 4286 | */ | 4513 | */ |
| 4287 | |||
| 4288 | int ext4_writepage_trans_blocks(struct inode *inode) | 4514 | int ext4_writepage_trans_blocks(struct inode *inode) |
| 4289 | { | 4515 | { |
| 4290 | int bpp = ext4_journal_blocks_per_page(inode); | 4516 | int bpp = ext4_journal_blocks_per_page(inode); |
| 4291 | int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3; | ||
| 4292 | int ret; | 4517 | int ret; |
| 4293 | 4518 | ||
| 4294 | if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) | 4519 | ret = ext4_meta_trans_blocks(inode, bpp, 0); |
| 4295 | return ext4_ext_writepage_trans_blocks(inode, bpp); | ||
| 4296 | 4520 | ||
| 4521 | /* Account for data blocks for journalled mode */ | ||
| 4297 | if (ext4_should_journal_data(inode)) | 4522 | if (ext4_should_journal_data(inode)) |
| 4298 | ret = 3 * (bpp + indirects) + 2; | 4523 | ret += bpp; |
| 4299 | else | ||
| 4300 | ret = 2 * (bpp + indirects) + 2; | ||
| 4301 | |||
| 4302 | #ifdef CONFIG_QUOTA | ||
| 4303 | /* We know that structure was already allocated during DQUOT_INIT so | ||
| 4304 | * we will be updating only the data blocks + inodes */ | ||
| 4305 | ret += 2*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb); | ||
| 4306 | #endif | ||
| 4307 | |||
| 4308 | return ret; | 4524 | return ret; |
| 4309 | } | 4525 | } |
| 4310 | 4526 | ||
| 4311 | /* | 4527 | /* |
| 4528 | * Calculate the journal credits for a chunk of data modification. | ||
| 4529 | * | ||
| 4530 | * This is called from DIO, fallocate or whoever calling | ||
| 4531 | * ext4_get_blocks_wrap() to map/allocate a chunk of contigous disk blocks. | ||
| 4532 | * | ||
| 4533 | * journal buffers for data blocks are not included here, as DIO | ||
| 4534 | * and fallocate do no need to journal data buffers. | ||
| 4535 | */ | ||
| 4536 | int ext4_chunk_trans_blocks(struct inode *inode, int nrblocks) | ||
| 4537 | { | ||
| 4538 | return ext4_meta_trans_blocks(inode, nrblocks, 1); | ||
| 4539 | } | ||
| 4540 | |||
| 4541 | /* | ||
| 4312 | * The caller must have previously called ext4_reserve_inode_write(). | 4542 | * The caller must have previously called ext4_reserve_inode_write(). |
| 4313 | * Give this, we know that the caller already has write access to iloc->bh. | 4543 | * Give this, we know that the caller already has write access to iloc->bh. |
| 4314 | */ | 4544 | */ |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 8d141a25bbee..e0e3a5eb1ddb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
| @@ -787,13 +787,16 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
| 787 | if (bh_uptodate_or_lock(bh[i])) | 787 | if (bh_uptodate_or_lock(bh[i])) |
| 788 | continue; | 788 | continue; |
| 789 | 789 | ||
| 790 | spin_lock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); | ||
| 790 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 791 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
| 791 | ext4_init_block_bitmap(sb, bh[i], | 792 | ext4_init_block_bitmap(sb, bh[i], |
| 792 | first_group + i, desc); | 793 | first_group + i, desc); |
| 793 | set_buffer_uptodate(bh[i]); | 794 | set_buffer_uptodate(bh[i]); |
| 794 | unlock_buffer(bh[i]); | 795 | unlock_buffer(bh[i]); |
| 796 | spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); | ||
| 795 | continue; | 797 | continue; |
| 796 | } | 798 | } |
| 799 | spin_unlock(sb_bgl_lock(EXT4_SB(sb), first_group + i)); | ||
| 797 | get_bh(bh[i]); | 800 | get_bh(bh[i]); |
| 798 | bh[i]->b_end_io = end_buffer_read_sync; | 801 | bh[i]->b_end_io = end_buffer_read_sync; |
| 799 | submit_bh(READ, bh[i]); | 802 | submit_bh(READ, bh[i]); |
| @@ -2477,7 +2480,7 @@ err_freesgi: | |||
| 2477 | int ext4_mb_init(struct super_block *sb, int needs_recovery) | 2480 | int ext4_mb_init(struct super_block *sb, int needs_recovery) |
| 2478 | { | 2481 | { |
| 2479 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2482 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 2480 | unsigned i; | 2483 | unsigned i, j; |
| 2481 | unsigned offset; | 2484 | unsigned offset; |
| 2482 | unsigned max; | 2485 | unsigned max; |
| 2483 | int ret; | 2486 | int ret; |
| @@ -2537,7 +2540,7 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) | |||
| 2537 | sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT; | 2540 | sbi->s_mb_history_filter = EXT4_MB_HISTORY_DEFAULT; |
| 2538 | sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC; | 2541 | sbi->s_mb_group_prealloc = MB_DEFAULT_GROUP_PREALLOC; |
| 2539 | 2542 | ||
| 2540 | i = sizeof(struct ext4_locality_group) * NR_CPUS; | 2543 | i = sizeof(struct ext4_locality_group) * nr_cpu_ids; |
| 2541 | sbi->s_locality_groups = kmalloc(i, GFP_KERNEL); | 2544 | sbi->s_locality_groups = kmalloc(i, GFP_KERNEL); |
| 2542 | if (sbi->s_locality_groups == NULL) { | 2545 | if (sbi->s_locality_groups == NULL) { |
| 2543 | clear_opt(sbi->s_mount_opt, MBALLOC); | 2546 | clear_opt(sbi->s_mount_opt, MBALLOC); |
| @@ -2545,11 +2548,12 @@ int ext4_mb_init(struct super_block *sb, int needs_recovery) | |||
| 2545 | kfree(sbi->s_mb_maxs); | 2548 | kfree(sbi->s_mb_maxs); |
| 2546 | return -ENOMEM; | 2549 | return -ENOMEM; |
| 2547 | } | 2550 | } |
| 2548 | for (i = 0; i < NR_CPUS; i++) { | 2551 | for (i = 0; i < nr_cpu_ids; i++) { |
| 2549 | struct ext4_locality_group *lg; | 2552 | struct ext4_locality_group *lg; |
| 2550 | lg = &sbi->s_locality_groups[i]; | 2553 | lg = &sbi->s_locality_groups[i]; |
| 2551 | mutex_init(&lg->lg_mutex); | 2554 | mutex_init(&lg->lg_mutex); |
| 2552 | INIT_LIST_HEAD(&lg->lg_prealloc_list); | 2555 | for (j = 0; j < PREALLOC_TB_SIZE; j++) |
| 2556 | INIT_LIST_HEAD(&lg->lg_prealloc_list[j]); | ||
| 2553 | spin_lock_init(&lg->lg_prealloc_lock); | 2557 | spin_lock_init(&lg->lg_prealloc_lock); |
| 2554 | } | 2558 | } |
| 2555 | 2559 | ||
| @@ -3260,6 +3264,7 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac, | |||
| 3260 | struct ext4_prealloc_space *pa) | 3264 | struct ext4_prealloc_space *pa) |
| 3261 | { | 3265 | { |
| 3262 | unsigned int len = ac->ac_o_ex.fe_len; | 3266 | unsigned int len = ac->ac_o_ex.fe_len; |
| 3267 | |||
| 3263 | ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart, | 3268 | ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart, |
| 3264 | &ac->ac_b_ex.fe_group, | 3269 | &ac->ac_b_ex.fe_group, |
| 3265 | &ac->ac_b_ex.fe_start); | 3270 | &ac->ac_b_ex.fe_start); |
| @@ -3277,14 +3282,45 @@ static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac, | |||
| 3277 | } | 3282 | } |
| 3278 | 3283 | ||
| 3279 | /* | 3284 | /* |
| 3285 | * Return the prealloc space that have minimal distance | ||
| 3286 | * from the goal block. @cpa is the prealloc | ||
| 3287 | * space that is having currently known minimal distance | ||
| 3288 | * from the goal block. | ||
| 3289 | */ | ||
| 3290 | static struct ext4_prealloc_space * | ||
| 3291 | ext4_mb_check_group_pa(ext4_fsblk_t goal_block, | ||
| 3292 | struct ext4_prealloc_space *pa, | ||
| 3293 | struct ext4_prealloc_space *cpa) | ||
| 3294 | { | ||
| 3295 | ext4_fsblk_t cur_distance, new_distance; | ||
| 3296 | |||
| 3297 | if (cpa == NULL) { | ||
| 3298 | atomic_inc(&pa->pa_count); | ||
| 3299 | return pa; | ||
| 3300 | } | ||
| 3301 | cur_distance = abs(goal_block - cpa->pa_pstart); | ||
| 3302 | new_distance = abs(goal_block - pa->pa_pstart); | ||
| 3303 | |||
| 3304 | if (cur_distance < new_distance) | ||
| 3305 | return cpa; | ||
| 3306 | |||
| 3307 | /* drop the previous reference */ | ||
| 3308 | atomic_dec(&cpa->pa_count); | ||
| 3309 | atomic_inc(&pa->pa_count); | ||
| 3310 | return pa; | ||
| 3311 | } | ||
| 3312 | |||
| 3313 | /* | ||
| 3280 | * search goal blocks in preallocated space | 3314 | * search goal blocks in preallocated space |
| 3281 | */ | 3315 | */ |
| 3282 | static noinline_for_stack int | 3316 | static noinline_for_stack int |
| 3283 | ext4_mb_use_preallocated(struct ext4_allocation_context *ac) | 3317 | ext4_mb_use_preallocated(struct ext4_allocation_context *ac) |
| 3284 | { | 3318 | { |
| 3319 | int order, i; | ||
| 3285 | struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); | 3320 | struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); |
| 3286 | struct ext4_locality_group *lg; | 3321 | struct ext4_locality_group *lg; |
| 3287 | struct ext4_prealloc_space *pa; | 3322 | struct ext4_prealloc_space *pa, *cpa = NULL; |
| 3323 | ext4_fsblk_t goal_block; | ||
| 3288 | 3324 | ||
| 3289 | /* only data can be preallocated */ | 3325 | /* only data can be preallocated */ |
| 3290 | if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) | 3326 | if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) |
| @@ -3322,22 +3358,38 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac) | |||
| 3322 | lg = ac->ac_lg; | 3358 | lg = ac->ac_lg; |
| 3323 | if (lg == NULL) | 3359 | if (lg == NULL) |
| 3324 | return 0; | 3360 | return 0; |
| 3361 | order = fls(ac->ac_o_ex.fe_len) - 1; | ||
| 3362 | if (order > PREALLOC_TB_SIZE - 1) | ||
| 3363 | /* The max size of hash table is PREALLOC_TB_SIZE */ | ||
| 3364 | order = PREALLOC_TB_SIZE - 1; | ||
| 3365 | |||
| 3366 | goal_block = ac->ac_g_ex.fe_group * EXT4_BLOCKS_PER_GROUP(ac->ac_sb) + | ||
| 3367 | ac->ac_g_ex.fe_start + | ||
| 3368 | le32_to_cpu(EXT4_SB(ac->ac_sb)->s_es->s_first_data_block); | ||
| 3369 | /* | ||
| 3370 | * search for the prealloc space that is having | ||
| 3371 | * minimal distance from the goal block. | ||
| 3372 | */ | ||
| 3373 | for (i = order; i < PREALLOC_TB_SIZE; i++) { | ||
| 3374 | rcu_read_lock(); | ||
| 3375 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[i], | ||
| 3376 | pa_inode_list) { | ||
| 3377 | spin_lock(&pa->pa_lock); | ||
| 3378 | if (pa->pa_deleted == 0 && | ||
| 3379 | pa->pa_free >= ac->ac_o_ex.fe_len) { | ||
| 3325 | 3380 | ||
| 3326 | rcu_read_lock(); | 3381 | cpa = ext4_mb_check_group_pa(goal_block, |
| 3327 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list, pa_inode_list) { | 3382 | pa, cpa); |
| 3328 | spin_lock(&pa->pa_lock); | 3383 | } |
| 3329 | if (pa->pa_deleted == 0 && pa->pa_free >= ac->ac_o_ex.fe_len) { | ||
| 3330 | atomic_inc(&pa->pa_count); | ||
| 3331 | ext4_mb_use_group_pa(ac, pa); | ||
| 3332 | spin_unlock(&pa->pa_lock); | 3384 | spin_unlock(&pa->pa_lock); |
| 3333 | ac->ac_criteria = 20; | ||
| 3334 | rcu_read_unlock(); | ||
| 3335 | return 1; | ||
| 3336 | } | 3385 | } |
| 3337 | spin_unlock(&pa->pa_lock); | 3386 | rcu_read_unlock(); |
| 3387 | } | ||
| 3388 | if (cpa) { | ||
| 3389 | ext4_mb_use_group_pa(ac, cpa); | ||
| 3390 | ac->ac_criteria = 20; | ||
| 3391 | return 1; | ||
| 3338 | } | 3392 | } |
| 3339 | rcu_read_unlock(); | ||
| 3340 | |||
| 3341 | return 0; | 3393 | return 0; |
| 3342 | } | 3394 | } |
| 3343 | 3395 | ||
| @@ -3560,6 +3612,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac) | |||
| 3560 | pa->pa_free = pa->pa_len; | 3612 | pa->pa_free = pa->pa_len; |
| 3561 | atomic_set(&pa->pa_count, 1); | 3613 | atomic_set(&pa->pa_count, 1); |
| 3562 | spin_lock_init(&pa->pa_lock); | 3614 | spin_lock_init(&pa->pa_lock); |
| 3615 | INIT_LIST_HEAD(&pa->pa_inode_list); | ||
| 3563 | pa->pa_deleted = 0; | 3616 | pa->pa_deleted = 0; |
| 3564 | pa->pa_linear = 1; | 3617 | pa->pa_linear = 1; |
| 3565 | 3618 | ||
| @@ -3580,10 +3633,10 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac) | |||
| 3580 | list_add(&pa->pa_group_list, &grp->bb_prealloc_list); | 3633 | list_add(&pa->pa_group_list, &grp->bb_prealloc_list); |
| 3581 | ext4_unlock_group(sb, ac->ac_b_ex.fe_group); | 3634 | ext4_unlock_group(sb, ac->ac_b_ex.fe_group); |
| 3582 | 3635 | ||
| 3583 | spin_lock(pa->pa_obj_lock); | 3636 | /* |
| 3584 | list_add_tail_rcu(&pa->pa_inode_list, &lg->lg_prealloc_list); | 3637 | * We will later add the new pa to the right bucket |
| 3585 | spin_unlock(pa->pa_obj_lock); | 3638 | * after updating the pa_free in ext4_mb_release_context |
| 3586 | 3639 | */ | |
| 3587 | return 0; | 3640 | return 0; |
| 3588 | } | 3641 | } |
| 3589 | 3642 | ||
| @@ -3733,20 +3786,23 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, | |||
| 3733 | 3786 | ||
| 3734 | bitmap_bh = ext4_read_block_bitmap(sb, group); | 3787 | bitmap_bh = ext4_read_block_bitmap(sb, group); |
| 3735 | if (bitmap_bh == NULL) { | 3788 | if (bitmap_bh == NULL) { |
| 3736 | /* error handling here */ | 3789 | ext4_error(sb, __func__, "Error in reading block " |
| 3737 | ext4_mb_release_desc(&e4b); | 3790 | "bitmap for %lu\n", group); |
| 3738 | BUG_ON(bitmap_bh == NULL); | 3791 | return 0; |
| 3739 | } | 3792 | } |
| 3740 | 3793 | ||
| 3741 | err = ext4_mb_load_buddy(sb, group, &e4b); | 3794 | err = ext4_mb_load_buddy(sb, group, &e4b); |
| 3742 | BUG_ON(err != 0); /* error handling here */ | 3795 | if (err) { |
| 3796 | ext4_error(sb, __func__, "Error in loading buddy " | ||
| 3797 | "information for %lu\n", group); | ||
| 3798 | put_bh(bitmap_bh); | ||
| 3799 | return 0; | ||
| 3800 | } | ||
| 3743 | 3801 | ||
| 3744 | if (needed == 0) | 3802 | if (needed == 0) |
| 3745 | needed = EXT4_BLOCKS_PER_GROUP(sb) + 1; | 3803 | needed = EXT4_BLOCKS_PER_GROUP(sb) + 1; |
| 3746 | 3804 | ||
| 3747 | grp = ext4_get_group_info(sb, group); | ||
| 3748 | INIT_LIST_HEAD(&list); | 3805 | INIT_LIST_HEAD(&list); |
| 3749 | |||
| 3750 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 3806 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
| 3751 | repeat: | 3807 | repeat: |
| 3752 | ext4_lock_group(sb, group); | 3808 | ext4_lock_group(sb, group); |
| @@ -3903,13 +3959,18 @@ repeat: | |||
| 3903 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL); | 3959 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL); |
| 3904 | 3960 | ||
| 3905 | err = ext4_mb_load_buddy(sb, group, &e4b); | 3961 | err = ext4_mb_load_buddy(sb, group, &e4b); |
| 3906 | BUG_ON(err != 0); /* error handling here */ | 3962 | if (err) { |
| 3963 | ext4_error(sb, __func__, "Error in loading buddy " | ||
| 3964 | "information for %lu\n", group); | ||
| 3965 | continue; | ||
| 3966 | } | ||
| 3907 | 3967 | ||
| 3908 | bitmap_bh = ext4_read_block_bitmap(sb, group); | 3968 | bitmap_bh = ext4_read_block_bitmap(sb, group); |
| 3909 | if (bitmap_bh == NULL) { | 3969 | if (bitmap_bh == NULL) { |
| 3910 | /* error handling here */ | 3970 | ext4_error(sb, __func__, "Error in reading block " |
| 3971 | "bitmap for %lu\n", group); | ||
| 3911 | ext4_mb_release_desc(&e4b); | 3972 | ext4_mb_release_desc(&e4b); |
| 3912 | BUG_ON(bitmap_bh == NULL); | 3973 | continue; |
| 3913 | } | 3974 | } |
| 3914 | 3975 | ||
| 3915 | ext4_lock_group(sb, group); | 3976 | ext4_lock_group(sb, group); |
| @@ -4112,22 +4173,168 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac, | |||
| 4112 | 4173 | ||
| 4113 | } | 4174 | } |
| 4114 | 4175 | ||
| 4176 | static noinline_for_stack void | ||
| 4177 | ext4_mb_discard_lg_preallocations(struct super_block *sb, | ||
| 4178 | struct ext4_locality_group *lg, | ||
| 4179 | int order, int total_entries) | ||
| 4180 | { | ||
| 4181 | ext4_group_t group = 0; | ||
| 4182 | struct ext4_buddy e4b; | ||
| 4183 | struct list_head discard_list; | ||
| 4184 | struct ext4_prealloc_space *pa, *tmp; | ||
| 4185 | struct ext4_allocation_context *ac; | ||
| 4186 | |||
| 4187 | mb_debug("discard locality group preallocation\n"); | ||
| 4188 | |||
| 4189 | INIT_LIST_HEAD(&discard_list); | ||
| 4190 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | ||
| 4191 | |||
| 4192 | spin_lock(&lg->lg_prealloc_lock); | ||
| 4193 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], | ||
| 4194 | pa_inode_list) { | ||
| 4195 | spin_lock(&pa->pa_lock); | ||
| 4196 | if (atomic_read(&pa->pa_count)) { | ||
| 4197 | /* | ||
| 4198 | * This is the pa that we just used | ||
| 4199 | * for block allocation. So don't | ||
| 4200 | * free that | ||
| 4201 | */ | ||
| 4202 | spin_unlock(&pa->pa_lock); | ||
| 4203 | continue; | ||
| 4204 | } | ||
| 4205 | if (pa->pa_deleted) { | ||
| 4206 | spin_unlock(&pa->pa_lock); | ||
| 4207 | continue; | ||
| 4208 | } | ||
| 4209 | /* only lg prealloc space */ | ||
| 4210 | BUG_ON(!pa->pa_linear); | ||
| 4211 | |||
| 4212 | /* seems this one can be freed ... */ | ||
| 4213 | pa->pa_deleted = 1; | ||
| 4214 | spin_unlock(&pa->pa_lock); | ||
| 4215 | |||
| 4216 | list_del_rcu(&pa->pa_inode_list); | ||
| 4217 | list_add(&pa->u.pa_tmp_list, &discard_list); | ||
| 4218 | |||
| 4219 | total_entries--; | ||
| 4220 | if (total_entries <= 5) { | ||
| 4221 | /* | ||
| 4222 | * we want to keep only 5 entries | ||
| 4223 | * allowing it to grow to 8. This | ||
| 4224 | * mak sure we don't call discard | ||
| 4225 | * soon for this list. | ||
| 4226 | */ | ||
| 4227 | break; | ||
| 4228 | } | ||
| 4229 | } | ||
| 4230 | spin_unlock(&lg->lg_prealloc_lock); | ||
| 4231 | |||
| 4232 | list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) { | ||
| 4233 | |||
| 4234 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, NULL); | ||
| 4235 | if (ext4_mb_load_buddy(sb, group, &e4b)) { | ||
| 4236 | ext4_error(sb, __func__, "Error in loading buddy " | ||
| 4237 | "information for %lu\n", group); | ||
| 4238 | continue; | ||
| 4239 | } | ||
| 4240 | ext4_lock_group(sb, group); | ||
| 4241 | list_del(&pa->pa_group_list); | ||
| 4242 | ext4_mb_release_group_pa(&e4b, pa, ac); | ||
| 4243 | ext4_unlock_group(sb, group); | ||
| 4244 | |||
| 4245 | ext4_mb_release_desc(&e4b); | ||
| 4246 | list_del(&pa->u.pa_tmp_list); | ||
| 4247 | call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); | ||
| 4248 | } | ||
| 4249 | if (ac) | ||
| 4250 | kmem_cache_free(ext4_ac_cachep, ac); | ||
| 4251 | } | ||
| 4252 | |||
| 4253 | /* | ||
| 4254 | * We have incremented pa_count. So it cannot be freed at this | ||
| 4255 | * point. Also we hold lg_mutex. So no parallel allocation is | ||
| 4256 | * possible from this lg. That means pa_free cannot be updated. | ||
| 4257 | * | ||
| 4258 | * A parallel ext4_mb_discard_group_preallocations is possible. | ||
| 4259 | * which can cause the lg_prealloc_list to be updated. | ||
| 4260 | */ | ||
| 4261 | |||
| 4262 | static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac) | ||
| 4263 | { | ||
| 4264 | int order, added = 0, lg_prealloc_count = 1; | ||
| 4265 | struct super_block *sb = ac->ac_sb; | ||
| 4266 | struct ext4_locality_group *lg = ac->ac_lg; | ||
| 4267 | struct ext4_prealloc_space *tmp_pa, *pa = ac->ac_pa; | ||
| 4268 | |||
| 4269 | order = fls(pa->pa_free) - 1; | ||
| 4270 | if (order > PREALLOC_TB_SIZE - 1) | ||
| 4271 | /* The max size of hash table is PREALLOC_TB_SIZE */ | ||
| 4272 | order = PREALLOC_TB_SIZE - 1; | ||
| 4273 | /* Add the prealloc space to lg */ | ||
| 4274 | rcu_read_lock(); | ||
| 4275 | list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[order], | ||
| 4276 | pa_inode_list) { | ||
| 4277 | spin_lock(&tmp_pa->pa_lock); | ||
| 4278 | if (tmp_pa->pa_deleted) { | ||
| 4279 | spin_unlock(&pa->pa_lock); | ||
| 4280 | continue; | ||
| 4281 | } | ||
| 4282 | if (!added && pa->pa_free < tmp_pa->pa_free) { | ||
| 4283 | /* Add to the tail of the previous entry */ | ||
| 4284 | list_add_tail_rcu(&pa->pa_inode_list, | ||
| 4285 | &tmp_pa->pa_inode_list); | ||
| 4286 | added = 1; | ||
| 4287 | /* | ||
| 4288 | * we want to count the total | ||
| 4289 | * number of entries in the list | ||
| 4290 | */ | ||
| 4291 | } | ||
| 4292 | spin_unlock(&tmp_pa->pa_lock); | ||
| 4293 | lg_prealloc_count++; | ||
| 4294 | } | ||
| 4295 | if (!added) | ||
| 4296 | list_add_tail_rcu(&pa->pa_inode_list, | ||
| 4297 | &lg->lg_prealloc_list[order]); | ||
| 4298 | rcu_read_unlock(); | ||
| 4299 | |||
| 4300 | /* Now trim the list to be not more than 8 elements */ | ||
| 4301 | if (lg_prealloc_count > 8) { | ||
| 4302 | ext4_mb_discard_lg_preallocations(sb, lg, | ||
| 4303 | order, lg_prealloc_count); | ||
| 4304 | return; | ||
| 4305 | } | ||
| 4306 | return ; | ||
| 4307 | } | ||
| 4308 | |||
| 4115 | /* | 4309 | /* |
| 4116 | * release all resource we used in allocation | 4310 | * release all resource we used in allocation |
| 4117 | */ | 4311 | */ |
| 4118 | static int ext4_mb_release_context(struct ext4_allocation_context *ac) | 4312 | static int ext4_mb_release_context(struct ext4_allocation_context *ac) |
| 4119 | { | 4313 | { |
| 4120 | if (ac->ac_pa) { | 4314 | struct ext4_prealloc_space *pa = ac->ac_pa; |
| 4121 | if (ac->ac_pa->pa_linear) { | 4315 | if (pa) { |
| 4316 | if (pa->pa_linear) { | ||
| 4122 | /* see comment in ext4_mb_use_group_pa() */ | 4317 | /* see comment in ext4_mb_use_group_pa() */ |
| 4123 | spin_lock(&ac->ac_pa->pa_lock); | 4318 | spin_lock(&pa->pa_lock); |
| 4124 | ac->ac_pa->pa_pstart += ac->ac_b_ex.fe_len; | 4319 | pa->pa_pstart += ac->ac_b_ex.fe_len; |
| 4125 | ac->ac_pa->pa_lstart += ac->ac_b_ex.fe_len; | 4320 | pa->pa_lstart += ac->ac_b_ex.fe_len; |
| 4126 | ac->ac_pa->pa_free -= ac->ac_b_ex.fe_len; | 4321 | pa->pa_free -= ac->ac_b_ex.fe_len; |
| 4127 | ac->ac_pa->pa_len -= ac->ac_b_ex.fe_len; | 4322 | pa->pa_len -= ac->ac_b_ex.fe_len; |
| 4128 | spin_unlock(&ac->ac_pa->pa_lock); | 4323 | spin_unlock(&pa->pa_lock); |
| 4324 | /* | ||
| 4325 | * We want to add the pa to the right bucket. | ||
| 4326 | * Remove it from the list and while adding | ||
| 4327 | * make sure the list to which we are adding | ||
| 4328 | * doesn't grow big. | ||
| 4329 | */ | ||
| 4330 | if (likely(pa->pa_free)) { | ||
| 4331 | spin_lock(pa->pa_obj_lock); | ||
| 4332 | list_del_rcu(&pa->pa_inode_list); | ||
| 4333 | spin_unlock(pa->pa_obj_lock); | ||
| 4334 | ext4_mb_add_n_trim(ac); | ||
| 4335 | } | ||
| 4129 | } | 4336 | } |
| 4130 | ext4_mb_put_pa(ac, ac->ac_sb, ac->ac_pa); | 4337 | ext4_mb_put_pa(ac, ac->ac_sb, pa); |
| 4131 | } | 4338 | } |
| 4132 | if (ac->ac_bitmap_page) | 4339 | if (ac->ac_bitmap_page) |
| 4133 | page_cache_release(ac->ac_bitmap_page); | 4340 | page_cache_release(ac->ac_bitmap_page); |
| @@ -4420,11 +4627,15 @@ do_more: | |||
| 4420 | count -= overflow; | 4627 | count -= overflow; |
| 4421 | } | 4628 | } |
| 4422 | bitmap_bh = ext4_read_block_bitmap(sb, block_group); | 4629 | bitmap_bh = ext4_read_block_bitmap(sb, block_group); |
| 4423 | if (!bitmap_bh) | 4630 | if (!bitmap_bh) { |
| 4631 | err = -EIO; | ||
| 4424 | goto error_return; | 4632 | goto error_return; |
| 4633 | } | ||
| 4425 | gdp = ext4_get_group_desc(sb, block_group, &gd_bh); | 4634 | gdp = ext4_get_group_desc(sb, block_group, &gd_bh); |
| 4426 | if (!gdp) | 4635 | if (!gdp) { |
| 4636 | err = -EIO; | ||
| 4427 | goto error_return; | 4637 | goto error_return; |
| 4638 | } | ||
| 4428 | 4639 | ||
| 4429 | if (in_range(ext4_block_bitmap(sb, gdp), block, count) || | 4640 | if (in_range(ext4_block_bitmap(sb, gdp), block, count) || |
| 4430 | in_range(ext4_inode_bitmap(sb, gdp), block, count) || | 4641 | in_range(ext4_inode_bitmap(sb, gdp), block, count) || |
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h index bfe6add46bcf..c7c9906c2a75 100644 --- a/fs/ext4/mballoc.h +++ b/fs/ext4/mballoc.h | |||
| @@ -164,11 +164,17 @@ struct ext4_free_extent { | |||
| 164 | * Locality group: | 164 | * Locality group: |
| 165 | * we try to group all related changes together | 165 | * we try to group all related changes together |
| 166 | * so that writeback can flush/allocate them together as well | 166 | * so that writeback can flush/allocate them together as well |
| 167 | * Size of lg_prealloc_list hash is determined by MB_DEFAULT_GROUP_PREALLOC | ||
| 168 | * (512). We store prealloc space into the hash based on the pa_free blocks | ||
| 169 | * order value.ie, fls(pa_free)-1; | ||
| 167 | */ | 170 | */ |
| 171 | #define PREALLOC_TB_SIZE 10 | ||
| 168 | struct ext4_locality_group { | 172 | struct ext4_locality_group { |
| 169 | /* for allocator */ | 173 | /* for allocator */ |
| 170 | struct mutex lg_mutex; /* to serialize allocates */ | 174 | /* to serialize allocates */ |
| 171 | struct list_head lg_prealloc_list;/* list of preallocations */ | 175 | struct mutex lg_mutex; |
| 176 | /* list of preallocations */ | ||
| 177 | struct list_head lg_prealloc_list[PREALLOC_TB_SIZE]; | ||
| 172 | spinlock_t lg_prealloc_lock; | 178 | spinlock_t lg_prealloc_lock; |
| 173 | }; | 179 | }; |
| 174 | 180 | ||
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index b9e077ba07e9..46fc0b5b12ba 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
| @@ -53,7 +53,8 @@ static int finish_range(handle_t *handle, struct inode *inode, | |||
| 53 | * credit. But below we try to not accumalate too much | 53 | * credit. But below we try to not accumalate too much |
| 54 | * of them by restarting the journal. | 54 | * of them by restarting the journal. |
| 55 | */ | 55 | */ |
| 56 | needed = ext4_ext_calc_credits_for_insert(inode, path); | 56 | needed = ext4_ext_calc_credits_for_single_extent(inode, |
| 57 | lb->last_block - lb->first_block + 1, path); | ||
| 57 | 58 | ||
| 58 | /* | 59 | /* |
| 59 | * Make sure the credit we accumalated is not really high | 60 | * Make sure the credit we accumalated is not really high |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index f000fbe2cd93..b3d35604ea18 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
| @@ -73,7 +73,7 @@ static int verify_group_input(struct super_block *sb, | |||
| 73 | "Inode bitmap not in group (block %llu)", | 73 | "Inode bitmap not in group (block %llu)", |
| 74 | (unsigned long long)input->inode_bitmap); | 74 | (unsigned long long)input->inode_bitmap); |
| 75 | else if (outside(input->inode_table, start, end) || | 75 | else if (outside(input->inode_table, start, end) || |
| 76 | outside(itend - 1, start, end)) | 76 | outside(itend - 1, start, end)) |
| 77 | ext4_warning(sb, __func__, | 77 | ext4_warning(sb, __func__, |
| 78 | "Inode table not in group (blocks %llu-%llu)", | 78 | "Inode table not in group (blocks %llu-%llu)", |
| 79 | (unsigned long long)input->inode_table, itend - 1); | 79 | (unsigned long long)input->inode_table, itend - 1); |
| @@ -104,7 +104,7 @@ static int verify_group_input(struct super_block *sb, | |||
| 104 | (unsigned long long)input->inode_bitmap, | 104 | (unsigned long long)input->inode_bitmap, |
| 105 | start, metaend - 1); | 105 | start, metaend - 1); |
| 106 | else if (inside(input->inode_table, start, metaend) || | 106 | else if (inside(input->inode_table, start, metaend) || |
| 107 | inside(itend - 1, start, metaend)) | 107 | inside(itend - 1, start, metaend)) |
| 108 | ext4_warning(sb, __func__, | 108 | ext4_warning(sb, __func__, |
| 109 | "Inode table (%llu-%llu) overlaps" | 109 | "Inode table (%llu-%llu) overlaps" |
| 110 | "GDT table (%llu-%llu)", | 110 | "GDT table (%llu-%llu)", |
| @@ -158,9 +158,9 @@ static int extend_or_restart_transaction(handle_t *handle, int thresh, | |||
| 158 | if (err) { | 158 | if (err) { |
| 159 | if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) | 159 | if ((err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) |
| 160 | return err; | 160 | return err; |
| 161 | if ((err = ext4_journal_get_write_access(handle, bh))) | 161 | if ((err = ext4_journal_get_write_access(handle, bh))) |
| 162 | return err; | 162 | return err; |
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | return 0; | 165 | return 0; |
| 166 | } | 166 | } |
| @@ -416,11 +416,11 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, | |||
| 416 | "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n", | 416 | "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n", |
| 417 | gdb_num); | 417 | gdb_num); |
| 418 | 418 | ||
| 419 | /* | 419 | /* |
| 420 | * If we are not using the primary superblock/GDT copy don't resize, | 420 | * If we are not using the primary superblock/GDT copy don't resize, |
| 421 | * because the user tools have no way of handling this. Probably a | 421 | * because the user tools have no way of handling this. Probably a |
| 422 | * bad time to do it anyways. | 422 | * bad time to do it anyways. |
| 423 | */ | 423 | */ |
| 424 | if (EXT4_SB(sb)->s_sbh->b_blocknr != | 424 | if (EXT4_SB(sb)->s_sbh->b_blocknr != |
| 425 | le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) { | 425 | le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) { |
| 426 | ext4_warning(sb, __func__, | 426 | ext4_warning(sb, __func__, |
| @@ -507,14 +507,14 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, | |||
| 507 | return 0; | 507 | return 0; |
| 508 | 508 | ||
| 509 | exit_inode: | 509 | exit_inode: |
| 510 | //ext4_journal_release_buffer(handle, iloc.bh); | 510 | /* ext4_journal_release_buffer(handle, iloc.bh); */ |
| 511 | brelse(iloc.bh); | 511 | brelse(iloc.bh); |
| 512 | exit_dindj: | 512 | exit_dindj: |
| 513 | //ext4_journal_release_buffer(handle, dind); | 513 | /* ext4_journal_release_buffer(handle, dind); */ |
| 514 | exit_primary: | 514 | exit_primary: |
| 515 | //ext4_journal_release_buffer(handle, *primary); | 515 | /* ext4_journal_release_buffer(handle, *primary); */ |
| 516 | exit_sbh: | 516 | exit_sbh: |
| 517 | //ext4_journal_release_buffer(handle, *primary); | 517 | /* ext4_journal_release_buffer(handle, *primary); */ |
| 518 | exit_dind: | 518 | exit_dind: |
| 519 | brelse(dind); | 519 | brelse(dind); |
| 520 | exit_bh: | 520 | exit_bh: |
| @@ -773,7 +773,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 773 | 773 | ||
| 774 | if (reserved_gdb || gdb_off == 0) { | 774 | if (reserved_gdb || gdb_off == 0) { |
| 775 | if (!EXT4_HAS_COMPAT_FEATURE(sb, | 775 | if (!EXT4_HAS_COMPAT_FEATURE(sb, |
| 776 | EXT4_FEATURE_COMPAT_RESIZE_INODE)){ | 776 | EXT4_FEATURE_COMPAT_RESIZE_INODE) |
| 777 | || !le16_to_cpu(es->s_reserved_gdt_blocks)) { | ||
| 777 | ext4_warning(sb, __func__, | 778 | ext4_warning(sb, __func__, |
| 778 | "No reserved GDT blocks, can't resize"); | 779 | "No reserved GDT blocks, can't resize"); |
| 779 | return -EPERM; | 780 | return -EPERM; |
| @@ -818,12 +819,12 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 818 | if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh))) | 819 | if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh))) |
| 819 | goto exit_journal; | 820 | goto exit_journal; |
| 820 | 821 | ||
| 821 | /* | 822 | /* |
| 822 | * We will only either add reserved group blocks to a backup group | 823 | * We will only either add reserved group blocks to a backup group |
| 823 | * or remove reserved blocks for the first group in a new group block. | 824 | * or remove reserved blocks for the first group in a new group block. |
| 824 | * Doing both would be mean more complex code, and sane people don't | 825 | * Doing both would be mean more complex code, and sane people don't |
| 825 | * use non-sparse filesystems anymore. This is already checked above. | 826 | * use non-sparse filesystems anymore. This is already checked above. |
| 826 | */ | 827 | */ |
| 827 | if (gdb_off) { | 828 | if (gdb_off) { |
| 828 | primary = sbi->s_group_desc[gdb_num]; | 829 | primary = sbi->s_group_desc[gdb_num]; |
| 829 | if ((err = ext4_journal_get_write_access(handle, primary))) | 830 | if ((err = ext4_journal_get_write_access(handle, primary))) |
| @@ -835,24 +836,24 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) | |||
| 835 | } else if ((err = add_new_gdb(handle, inode, input, &primary))) | 836 | } else if ((err = add_new_gdb(handle, inode, input, &primary))) |
| 836 | goto exit_journal; | 837 | goto exit_journal; |
| 837 | 838 | ||
| 838 | /* | 839 | /* |
| 839 | * OK, now we've set up the new group. Time to make it active. | 840 | * OK, now we've set up the new group. Time to make it active. |
| 840 | * | 841 | * |
| 841 | * Current kernels don't lock all allocations via lock_super(), | 842 | * Current kernels don't lock all allocations via lock_super(), |
| 842 | * so we have to be safe wrt. concurrent accesses the group | 843 | * so we have to be safe wrt. concurrent accesses the group |
| 843 | * data. So we need to be careful to set all of the relevant | 844 | * data. So we need to be careful to set all of the relevant |
| 844 | * group descriptor data etc. *before* we enable the group. | 845 | * group descriptor data etc. *before* we enable the group. |
| 845 | * | 846 | * |
| 846 | * The key field here is sbi->s_groups_count: as long as | 847 | * The key field here is sbi->s_groups_count: as long as |
| 847 | * that retains its old value, nobody is going to access the new | 848 | * that retains its old value, nobody is going to access the new |
| 848 | * group. | 849 | * group. |
| 849 | * | 850 | * |
| 850 | * So first we update all the descriptor metadata for the new | 851 | * So first we update all the descriptor metadata for the new |
| 851 | * group; then we update the total disk blocks count; then we | 852 | * group; then we update the total disk blocks count; then we |
| 852 | * update the groups count to enable the group; then finally we | 853 | * update the groups count to enable the group; then finally we |
| 853 | * update the free space counts so that the system can start | 854 | * update the free space counts so that the system can start |
| 854 | * using the new disk blocks. | 855 | * using the new disk blocks. |
| 855 | */ | 856 | */ |
| 856 | 857 | ||
| 857 | /* Update group descriptor block for new group */ | 858 | /* Update group descriptor block for new group */ |
| 858 | gdp = (struct ext4_group_desc *)((char *)primary->b_data + | 859 | gdp = (struct ext4_group_desc *)((char *)primary->b_data + |
| @@ -946,7 +947,8 @@ exit_put: | |||
| 946 | return err; | 947 | return err; |
| 947 | } /* ext4_group_add */ | 948 | } /* ext4_group_add */ |
| 948 | 949 | ||
| 949 | /* Extend the filesystem to the new number of blocks specified. This entry | 950 | /* |
| 951 | * Extend the filesystem to the new number of blocks specified. This entry | ||
| 950 | * point is only used to extend the current filesystem to the end of the last | 952 | * point is only used to extend the current filesystem to the end of the last |
| 951 | * existing group. It can be accessed via ioctl, or by "remount,resize=<size>" | 953 | * existing group. It can be accessed via ioctl, or by "remount,resize=<size>" |
| 952 | * for emergencies (because it has no dependencies on reserved blocks). | 954 | * for emergencies (because it has no dependencies on reserved blocks). |
| @@ -1024,7 +1026,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, | |||
| 1024 | o_blocks_count + add, add); | 1026 | o_blocks_count + add, add); |
| 1025 | 1027 | ||
| 1026 | /* See if the device is actually as big as what was requested */ | 1028 | /* See if the device is actually as big as what was requested */ |
| 1027 | bh = sb_bread(sb, o_blocks_count + add -1); | 1029 | bh = sb_bread(sb, o_blocks_count + add - 1); |
| 1028 | if (!bh) { | 1030 | if (!bh) { |
| 1029 | ext4_warning(sb, __func__, | 1031 | ext4_warning(sb, __func__, |
| 1030 | "can't read last block, resize aborted"); | 1032 | "can't read last block, resize aborted"); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1cb371dcd609..566344b926b7 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -49,20 +49,19 @@ static int ext4_load_journal(struct super_block *, struct ext4_super_block *, | |||
| 49 | unsigned long journal_devnum); | 49 | unsigned long journal_devnum); |
| 50 | static int ext4_create_journal(struct super_block *, struct ext4_super_block *, | 50 | static int ext4_create_journal(struct super_block *, struct ext4_super_block *, |
| 51 | unsigned int); | 51 | unsigned int); |
| 52 | static void ext4_commit_super (struct super_block * sb, | 52 | static void ext4_commit_super(struct super_block *sb, |
| 53 | struct ext4_super_block * es, | 53 | struct ext4_super_block *es, int sync); |
| 54 | int sync); | 54 | static void ext4_mark_recovery_complete(struct super_block *sb, |
| 55 | static void ext4_mark_recovery_complete(struct super_block * sb, | 55 | struct ext4_super_block *es); |
| 56 | struct ext4_super_block * es); | 56 | static void ext4_clear_journal_err(struct super_block *sb, |
| 57 | static void ext4_clear_journal_err(struct super_block * sb, | 57 | struct ext4_super_block *es); |
| 58 | struct ext4_super_block * es); | ||
| 59 | static int ext4_sync_fs(struct super_block *sb, int wait); | 58 | static int ext4_sync_fs(struct super_block *sb, int wait); |
| 60 | static const char *ext4_decode_error(struct super_block * sb, int errno, | 59 | static const char *ext4_decode_error(struct super_block *sb, int errno, |
| 61 | char nbuf[16]); | 60 | char nbuf[16]); |
| 62 | static int ext4_remount (struct super_block * sb, int * flags, char * data); | 61 | static int ext4_remount(struct super_block *sb, int *flags, char *data); |
| 63 | static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf); | 62 | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); |
| 64 | static void ext4_unlockfs(struct super_block *sb); | 63 | static void ext4_unlockfs(struct super_block *sb); |
| 65 | static void ext4_write_super (struct super_block * sb); | 64 | static void ext4_write_super(struct super_block *sb); |
| 66 | static void ext4_write_super_lockfs(struct super_block *sb); | 65 | static void ext4_write_super_lockfs(struct super_block *sb); |
| 67 | 66 | ||
| 68 | 67 | ||
| @@ -211,15 +210,15 @@ static void ext4_handle_error(struct super_block *sb) | |||
| 211 | if (sb->s_flags & MS_RDONLY) | 210 | if (sb->s_flags & MS_RDONLY) |
| 212 | return; | 211 | return; |
| 213 | 212 | ||
| 214 | if (!test_opt (sb, ERRORS_CONT)) { | 213 | if (!test_opt(sb, ERRORS_CONT)) { |
| 215 | journal_t *journal = EXT4_SB(sb)->s_journal; | 214 | journal_t *journal = EXT4_SB(sb)->s_journal; |
| 216 | 215 | ||
| 217 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; | 216 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; |
| 218 | if (journal) | 217 | if (journal) |
| 219 | jbd2_journal_abort(journal, -EIO); | 218 | jbd2_journal_abort(journal, -EIO); |
| 220 | } | 219 | } |
| 221 | if (test_opt (sb, ERRORS_RO)) { | 220 | if (test_opt(sb, ERRORS_RO)) { |
| 222 | printk (KERN_CRIT "Remounting filesystem read-only\n"); | 221 | printk(KERN_CRIT "Remounting filesystem read-only\n"); |
| 223 | sb->s_flags |= MS_RDONLY; | 222 | sb->s_flags |= MS_RDONLY; |
| 224 | } | 223 | } |
| 225 | ext4_commit_super(sb, es, 1); | 224 | ext4_commit_super(sb, es, 1); |
| @@ -228,13 +227,13 @@ static void ext4_handle_error(struct super_block *sb) | |||
| 228 | sb->s_id); | 227 | sb->s_id); |
| 229 | } | 228 | } |
| 230 | 229 | ||
| 231 | void ext4_error (struct super_block * sb, const char * function, | 230 | void ext4_error(struct super_block *sb, const char *function, |
| 232 | const char * fmt, ...) | 231 | const char *fmt, ...) |
| 233 | { | 232 | { |
| 234 | va_list args; | 233 | va_list args; |
| 235 | 234 | ||
| 236 | va_start(args, fmt); | 235 | va_start(args, fmt); |
| 237 | printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function); | 236 | printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function); |
| 238 | vprintk(fmt, args); | 237 | vprintk(fmt, args); |
| 239 | printk("\n"); | 238 | printk("\n"); |
| 240 | va_end(args); | 239 | va_end(args); |
| @@ -242,7 +241,7 @@ void ext4_error (struct super_block * sb, const char * function, | |||
| 242 | ext4_handle_error(sb); | 241 | ext4_handle_error(sb); |
| 243 | } | 242 | } |
| 244 | 243 | ||
| 245 | static const char *ext4_decode_error(struct super_block * sb, int errno, | 244 | static const char *ext4_decode_error(struct super_block *sb, int errno, |
| 246 | char nbuf[16]) | 245 | char nbuf[16]) |
| 247 | { | 246 | { |
| 248 | char *errstr = NULL; | 247 | char *errstr = NULL; |
| @@ -278,8 +277,7 @@ static const char *ext4_decode_error(struct super_block * sb, int errno, | |||
| 278 | /* __ext4_std_error decodes expected errors from journaling functions | 277 | /* __ext4_std_error decodes expected errors from journaling functions |
| 279 | * automatically and invokes the appropriate error response. */ | 278 | * automatically and invokes the appropriate error response. */ |
| 280 | 279 | ||
| 281 | void __ext4_std_error (struct super_block * sb, const char * function, | 280 | void __ext4_std_error(struct super_block *sb, const char *function, int errno) |
| 282 | int errno) | ||
| 283 | { | 281 | { |
| 284 | char nbuf[16]; | 282 | char nbuf[16]; |
| 285 | const char *errstr; | 283 | const char *errstr; |
| @@ -292,8 +290,8 @@ void __ext4_std_error (struct super_block * sb, const char * function, | |||
| 292 | return; | 290 | return; |
| 293 | 291 | ||
| 294 | errstr = ext4_decode_error(sb, errno, nbuf); | 292 | errstr = ext4_decode_error(sb, errno, nbuf); |
| 295 | printk (KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n", | 293 | printk(KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n", |
| 296 | sb->s_id, function, errstr); | 294 | sb->s_id, function, errstr); |
| 297 | 295 | ||
| 298 | ext4_handle_error(sb); | 296 | ext4_handle_error(sb); |
| 299 | } | 297 | } |
| @@ -308,15 +306,15 @@ void __ext4_std_error (struct super_block * sb, const char * function, | |||
| 308 | * case we take the easy way out and panic immediately. | 306 | * case we take the easy way out and panic immediately. |
| 309 | */ | 307 | */ |
| 310 | 308 | ||
| 311 | void ext4_abort (struct super_block * sb, const char * function, | 309 | void ext4_abort(struct super_block *sb, const char *function, |
| 312 | const char * fmt, ...) | 310 | const char *fmt, ...) |
| 313 | { | 311 | { |
| 314 | va_list args; | 312 | va_list args; |
| 315 | 313 | ||
| 316 | printk (KERN_CRIT "ext4_abort called.\n"); | 314 | printk(KERN_CRIT "ext4_abort called.\n"); |
| 317 | 315 | ||
| 318 | va_start(args, fmt); | 316 | va_start(args, fmt); |
| 319 | printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function); | 317 | printk(KERN_CRIT "EXT4-fs error (device %s): %s: ", sb->s_id, function); |
| 320 | vprintk(fmt, args); | 318 | vprintk(fmt, args); |
| 321 | printk("\n"); | 319 | printk("\n"); |
| 322 | va_end(args); | 320 | va_end(args); |
| @@ -334,8 +332,8 @@ void ext4_abort (struct super_block * sb, const char * function, | |||
| 334 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | 332 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); |
| 335 | } | 333 | } |
| 336 | 334 | ||
| 337 | void ext4_warning (struct super_block * sb, const char * function, | 335 | void ext4_warning(struct super_block *sb, const char *function, |
| 338 | const char * fmt, ...) | 336 | const char *fmt, ...) |
| 339 | { | 337 | { |
| 340 | va_list args; | 338 | va_list args; |
| 341 | 339 | ||
| @@ -496,7 +494,7 @@ static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi) | |||
| 496 | } | 494 | } |
| 497 | } | 495 | } |
| 498 | 496 | ||
| 499 | static void ext4_put_super (struct super_block * sb) | 497 | static void ext4_put_super(struct super_block *sb) |
| 500 | { | 498 | { |
| 501 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 499 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 502 | struct ext4_super_block *es = sbi->s_es; | 500 | struct ext4_super_block *es = sbi->s_es; |
| @@ -570,6 +568,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
| 570 | #endif | 568 | #endif |
| 571 | ei->i_block_alloc_info = NULL; | 569 | ei->i_block_alloc_info = NULL; |
| 572 | ei->vfs_inode.i_version = 1; | 570 | ei->vfs_inode.i_version = 1; |
| 571 | ei->vfs_inode.i_data.writeback_index = 0; | ||
| 573 | memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); | 572 | memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); |
| 574 | INIT_LIST_HEAD(&ei->i_prealloc_list); | 573 | INIT_LIST_HEAD(&ei->i_prealloc_list); |
| 575 | spin_lock_init(&ei->i_prealloc_lock); | 574 | spin_lock_init(&ei->i_prealloc_lock); |
| @@ -595,7 +594,7 @@ static void ext4_destroy_inode(struct inode *inode) | |||
| 595 | kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); | 594 | kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); |
| 596 | } | 595 | } |
| 597 | 596 | ||
| 598 | static void init_once(struct kmem_cache *cachep, void *foo) | 597 | static void init_once(void *foo) |
| 599 | { | 598 | { |
| 600 | struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; | 599 | struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; |
| 601 | 600 | ||
| @@ -647,7 +646,8 @@ static void ext4_clear_inode(struct inode *inode) | |||
| 647 | &EXT4_I(inode)->jinode); | 646 | &EXT4_I(inode)->jinode); |
| 648 | } | 647 | } |
| 649 | 648 | ||
| 650 | static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb) | 649 | static inline void ext4_show_quota_options(struct seq_file *seq, |
| 650 | struct super_block *sb) | ||
| 651 | { | 651 | { |
| 652 | #if defined(CONFIG_QUOTA) | 652 | #if defined(CONFIG_QUOTA) |
| 653 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 653 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| @@ -822,8 +822,8 @@ static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid, | |||
| 822 | } | 822 | } |
| 823 | 823 | ||
| 824 | #ifdef CONFIG_QUOTA | 824 | #ifdef CONFIG_QUOTA |
| 825 | #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") | 825 | #define QTYPE2NAME(t) ((t) == USRQUOTA?"user":"group") |
| 826 | #define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) | 826 | #define QTYPE2MOPT(on, t) ((t) == USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) |
| 827 | 827 | ||
| 828 | static int ext4_dquot_initialize(struct inode *inode, int type); | 828 | static int ext4_dquot_initialize(struct inode *inode, int type); |
| 829 | static int ext4_dquot_drop(struct inode *inode); | 829 | static int ext4_dquot_drop(struct inode *inode); |
| @@ -991,12 +991,12 @@ static ext4_fsblk_t get_sb_block(void **data) | |||
| 991 | return sb_block; | 991 | return sb_block; |
| 992 | } | 992 | } |
| 993 | 993 | ||
| 994 | static int parse_options (char *options, struct super_block *sb, | 994 | static int parse_options(char *options, struct super_block *sb, |
| 995 | unsigned int *inum, unsigned long *journal_devnum, | 995 | unsigned int *inum, unsigned long *journal_devnum, |
| 996 | ext4_fsblk_t *n_blocks_count, int is_remount) | 996 | ext4_fsblk_t *n_blocks_count, int is_remount) |
| 997 | { | 997 | { |
| 998 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 998 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 999 | char * p; | 999 | char *p; |
| 1000 | substring_t args[MAX_OPT_ARGS]; | 1000 | substring_t args[MAX_OPT_ARGS]; |
| 1001 | int data_opt = 0; | 1001 | int data_opt = 0; |
| 1002 | int option; | 1002 | int option; |
| @@ -1009,7 +1009,7 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1009 | if (!options) | 1009 | if (!options) |
| 1010 | return 1; | 1010 | return 1; |
| 1011 | 1011 | ||
| 1012 | while ((p = strsep (&options, ",")) != NULL) { | 1012 | while ((p = strsep(&options, ",")) != NULL) { |
| 1013 | int token; | 1013 | int token; |
| 1014 | if (!*p) | 1014 | if (!*p) |
| 1015 | continue; | 1015 | continue; |
| @@ -1017,16 +1017,16 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1017 | token = match_token(p, tokens, args); | 1017 | token = match_token(p, tokens, args); |
| 1018 | switch (token) { | 1018 | switch (token) { |
| 1019 | case Opt_bsd_df: | 1019 | case Opt_bsd_df: |
| 1020 | clear_opt (sbi->s_mount_opt, MINIX_DF); | 1020 | clear_opt(sbi->s_mount_opt, MINIX_DF); |
| 1021 | break; | 1021 | break; |
| 1022 | case Opt_minix_df: | 1022 | case Opt_minix_df: |
| 1023 | set_opt (sbi->s_mount_opt, MINIX_DF); | 1023 | set_opt(sbi->s_mount_opt, MINIX_DF); |
| 1024 | break; | 1024 | break; |
| 1025 | case Opt_grpid: | 1025 | case Opt_grpid: |
| 1026 | set_opt (sbi->s_mount_opt, GRPID); | 1026 | set_opt(sbi->s_mount_opt, GRPID); |
| 1027 | break; | 1027 | break; |
| 1028 | case Opt_nogrpid: | 1028 | case Opt_nogrpid: |
| 1029 | clear_opt (sbi->s_mount_opt, GRPID); | 1029 | clear_opt(sbi->s_mount_opt, GRPID); |
| 1030 | break; | 1030 | break; |
| 1031 | case Opt_resuid: | 1031 | case Opt_resuid: |
| 1032 | if (match_int(&args[0], &option)) | 1032 | if (match_int(&args[0], &option)) |
| @@ -1043,41 +1043,41 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1043 | /* *sb_block = match_int(&args[0]); */ | 1043 | /* *sb_block = match_int(&args[0]); */ |
| 1044 | break; | 1044 | break; |
| 1045 | case Opt_err_panic: | 1045 | case Opt_err_panic: |
| 1046 | clear_opt (sbi->s_mount_opt, ERRORS_CONT); | 1046 | clear_opt(sbi->s_mount_opt, ERRORS_CONT); |
| 1047 | clear_opt (sbi->s_mount_opt, ERRORS_RO); | 1047 | clear_opt(sbi->s_mount_opt, ERRORS_RO); |
| 1048 | set_opt (sbi->s_mount_opt, ERRORS_PANIC); | 1048 | set_opt(sbi->s_mount_opt, ERRORS_PANIC); |
| 1049 | break; | 1049 | break; |
| 1050 | case Opt_err_ro: | 1050 | case Opt_err_ro: |
| 1051 | clear_opt (sbi->s_mount_opt, ERRORS_CONT); | 1051 | clear_opt(sbi->s_mount_opt, ERRORS_CONT); |
| 1052 | clear_opt (sbi->s_mount_opt, ERRORS_PANIC); | 1052 | clear_opt(sbi->s_mount_opt, ERRORS_PANIC); |
| 1053 | set_opt (sbi->s_mount_opt, ERRORS_RO); | 1053 | set_opt(sbi->s_mount_opt, ERRORS_RO); |
| 1054 | break; | 1054 | break; |
| 1055 | case Opt_err_cont: | 1055 | case Opt_err_cont: |
| 1056 | clear_opt (sbi->s_mount_opt, ERRORS_RO); | 1056 | clear_opt(sbi->s_mount_opt, ERRORS_RO); |
| 1057 | clear_opt (sbi->s_mount_opt, ERRORS_PANIC); | 1057 | clear_opt(sbi->s_mount_opt, ERRORS_PANIC); |
| 1058 | set_opt (sbi->s_mount_opt, ERRORS_CONT); | 1058 | set_opt(sbi->s_mount_opt, ERRORS_CONT); |
| 1059 | break; | 1059 | break; |
| 1060 | case Opt_nouid32: | 1060 | case Opt_nouid32: |
| 1061 | set_opt (sbi->s_mount_opt, NO_UID32); | 1061 | set_opt(sbi->s_mount_opt, NO_UID32); |
| 1062 | break; | 1062 | break; |
| 1063 | case Opt_nocheck: | 1063 | case Opt_nocheck: |
| 1064 | clear_opt (sbi->s_mount_opt, CHECK); | 1064 | clear_opt(sbi->s_mount_opt, CHECK); |
| 1065 | break; | 1065 | break; |
| 1066 | case Opt_debug: | 1066 | case Opt_debug: |
| 1067 | set_opt (sbi->s_mount_opt, DEBUG); | 1067 | set_opt(sbi->s_mount_opt, DEBUG); |
| 1068 | break; | 1068 | break; |
| 1069 | case Opt_oldalloc: | 1069 | case Opt_oldalloc: |
| 1070 | set_opt (sbi->s_mount_opt, OLDALLOC); | 1070 | set_opt(sbi->s_mount_opt, OLDALLOC); |
| 1071 | break; | 1071 | break; |
| 1072 | case Opt_orlov: | 1072 | case Opt_orlov: |
| 1073 | clear_opt (sbi->s_mount_opt, OLDALLOC); | 1073 | clear_opt(sbi->s_mount_opt, OLDALLOC); |
| 1074 | break; | 1074 | break; |
| 1075 | #ifdef CONFIG_EXT4DEV_FS_XATTR | 1075 | #ifdef CONFIG_EXT4DEV_FS_XATTR |
| 1076 | case Opt_user_xattr: | 1076 | case Opt_user_xattr: |
| 1077 | set_opt (sbi->s_mount_opt, XATTR_USER); | 1077 | set_opt(sbi->s_mount_opt, XATTR_USER); |
| 1078 | break; | 1078 | break; |
| 1079 | case Opt_nouser_xattr: | 1079 | case Opt_nouser_xattr: |
| 1080 | clear_opt (sbi->s_mount_opt, XATTR_USER); | 1080 | clear_opt(sbi->s_mount_opt, XATTR_USER); |
| 1081 | break; | 1081 | break; |
| 1082 | #else | 1082 | #else |
| 1083 | case Opt_user_xattr: | 1083 | case Opt_user_xattr: |
| @@ -1115,7 +1115,7 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1115 | "journal on remount\n"); | 1115 | "journal on remount\n"); |
| 1116 | return 0; | 1116 | return 0; |
| 1117 | } | 1117 | } |
| 1118 | set_opt (sbi->s_mount_opt, UPDATE_JOURNAL); | 1118 | set_opt(sbi->s_mount_opt, UPDATE_JOURNAL); |
| 1119 | break; | 1119 | break; |
| 1120 | case Opt_journal_inum: | 1120 | case Opt_journal_inum: |
| 1121 | if (is_remount) { | 1121 | if (is_remount) { |
| @@ -1145,7 +1145,7 @@ static int parse_options (char *options, struct super_block *sb, | |||
| 1145 | set_opt(sbi->s_mount_opt, JOURNAL_CHECKSUM); | 1145 | set_opt(sbi->s_mount_opt, JOURNAL_CHECKSUM); |
| 1146 | break; | 1146 | break; |
| 1147 | case Opt_noload: | 1147 | case Opt_noload: |
| 1148 | set_opt (sbi->s_mount_opt, NOLOAD); | 1148 | set_opt(sbi->s_mount_opt, NOLOAD); |
| 1149 | break; | 1149 | break; |
| 1150 | case Opt_commit: | 1150 | case Opt_commit: |
| 1151 | if (match_int(&args[0], &option)) | 1151 | if (match_int(&args[0], &option)) |
| @@ -1331,7 +1331,7 @@ set_qf_format: | |||
| 1331 | "on this filesystem, use tune2fs\n"); | 1331 | "on this filesystem, use tune2fs\n"); |
| 1332 | return 0; | 1332 | return 0; |
| 1333 | } | 1333 | } |
| 1334 | set_opt (sbi->s_mount_opt, EXTENTS); | 1334 | set_opt(sbi->s_mount_opt, EXTENTS); |
| 1335 | break; | 1335 | break; |
| 1336 | case Opt_noextents: | 1336 | case Opt_noextents: |
| 1337 | /* | 1337 | /* |
| @@ -1348,7 +1348,7 @@ set_qf_format: | |||
| 1348 | "-o noextents options\n"); | 1348 | "-o noextents options\n"); |
| 1349 | return 0; | 1349 | return 0; |
| 1350 | } | 1350 | } |
| 1351 | clear_opt (sbi->s_mount_opt, EXTENTS); | 1351 | clear_opt(sbi->s_mount_opt, EXTENTS); |
| 1352 | break; | 1352 | break; |
| 1353 | case Opt_i_version: | 1353 | case Opt_i_version: |
| 1354 | set_opt(sbi->s_mount_opt, I_VERSION); | 1354 | set_opt(sbi->s_mount_opt, I_VERSION); |
| @@ -1374,9 +1374,9 @@ set_qf_format: | |||
| 1374 | set_opt(sbi->s_mount_opt, DELALLOC); | 1374 | set_opt(sbi->s_mount_opt, DELALLOC); |
| 1375 | break; | 1375 | break; |
| 1376 | default: | 1376 | default: |
| 1377 | printk (KERN_ERR | 1377 | printk(KERN_ERR |
| 1378 | "EXT4-fs: Unrecognized mount option \"%s\" " | 1378 | "EXT4-fs: Unrecognized mount option \"%s\" " |
| 1379 | "or missing value\n", p); | 1379 | "or missing value\n", p); |
| 1380 | return 0; | 1380 | return 0; |
| 1381 | } | 1381 | } |
| 1382 | } | 1382 | } |
| @@ -1423,31 +1423,31 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
| 1423 | int res = 0; | 1423 | int res = 0; |
| 1424 | 1424 | ||
| 1425 | if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { | 1425 | if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { |
| 1426 | printk (KERN_ERR "EXT4-fs warning: revision level too high, " | 1426 | printk(KERN_ERR "EXT4-fs warning: revision level too high, " |
| 1427 | "forcing read-only mode\n"); | 1427 | "forcing read-only mode\n"); |
| 1428 | res = MS_RDONLY; | 1428 | res = MS_RDONLY; |
| 1429 | } | 1429 | } |
| 1430 | if (read_only) | 1430 | if (read_only) |
| 1431 | return res; | 1431 | return res; |
| 1432 | if (!(sbi->s_mount_state & EXT4_VALID_FS)) | 1432 | if (!(sbi->s_mount_state & EXT4_VALID_FS)) |
| 1433 | printk (KERN_WARNING "EXT4-fs warning: mounting unchecked fs, " | 1433 | printk(KERN_WARNING "EXT4-fs warning: mounting unchecked fs, " |
| 1434 | "running e2fsck is recommended\n"); | 1434 | "running e2fsck is recommended\n"); |
| 1435 | else if ((sbi->s_mount_state & EXT4_ERROR_FS)) | 1435 | else if ((sbi->s_mount_state & EXT4_ERROR_FS)) |
| 1436 | printk (KERN_WARNING | 1436 | printk(KERN_WARNING |
| 1437 | "EXT4-fs warning: mounting fs with errors, " | 1437 | "EXT4-fs warning: mounting fs with errors, " |
| 1438 | "running e2fsck is recommended\n"); | 1438 | "running e2fsck is recommended\n"); |
| 1439 | else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && | 1439 | else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 && |
| 1440 | le16_to_cpu(es->s_mnt_count) >= | 1440 | le16_to_cpu(es->s_mnt_count) >= |
| 1441 | (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) | 1441 | (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) |
| 1442 | printk (KERN_WARNING | 1442 | printk(KERN_WARNING |
| 1443 | "EXT4-fs warning: maximal mount count reached, " | 1443 | "EXT4-fs warning: maximal mount count reached, " |
| 1444 | "running e2fsck is recommended\n"); | 1444 | "running e2fsck is recommended\n"); |
| 1445 | else if (le32_to_cpu(es->s_checkinterval) && | 1445 | else if (le32_to_cpu(es->s_checkinterval) && |
| 1446 | (le32_to_cpu(es->s_lastcheck) + | 1446 | (le32_to_cpu(es->s_lastcheck) + |
| 1447 | le32_to_cpu(es->s_checkinterval) <= get_seconds())) | 1447 | le32_to_cpu(es->s_checkinterval) <= get_seconds())) |
| 1448 | printk (KERN_WARNING | 1448 | printk(KERN_WARNING |
| 1449 | "EXT4-fs warning: checktime reached, " | 1449 | "EXT4-fs warning: checktime reached, " |
| 1450 | "running e2fsck is recommended\n"); | 1450 | "running e2fsck is recommended\n"); |
| 1451 | #if 0 | 1451 | #if 0 |
| 1452 | /* @@@ We _will_ want to clear the valid bit if we find | 1452 | /* @@@ We _will_ want to clear the valid bit if we find |
| 1453 | * inconsistencies, to force a fsck at reboot. But for | 1453 | * inconsistencies, to force a fsck at reboot. But for |
| @@ -1506,14 +1506,13 @@ static int ext4_fill_flex_info(struct super_block *sb) | |||
| 1506 | 1506 | ||
| 1507 | flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) / | 1507 | flex_group_count = (sbi->s_groups_count + groups_per_flex - 1) / |
| 1508 | groups_per_flex; | 1508 | groups_per_flex; |
| 1509 | sbi->s_flex_groups = kmalloc(flex_group_count * | 1509 | sbi->s_flex_groups = kzalloc(flex_group_count * |
| 1510 | sizeof(struct flex_groups), GFP_KERNEL); | 1510 | sizeof(struct flex_groups), GFP_KERNEL); |
| 1511 | if (sbi->s_flex_groups == NULL) { | 1511 | if (sbi->s_flex_groups == NULL) { |
| 1512 | printk(KERN_ERR "EXT4-fs: not enough memory\n"); | 1512 | printk(KERN_ERR "EXT4-fs: not enough memory for " |
| 1513 | "%lu flex groups\n", flex_group_count); | ||
| 1513 | goto failed; | 1514 | goto failed; |
| 1514 | } | 1515 | } |
| 1515 | memset(sbi->s_flex_groups, 0, flex_group_count * | ||
| 1516 | sizeof(struct flex_groups)); | ||
| 1517 | 1516 | ||
| 1518 | gdp = ext4_get_group_desc(sb, 1, &bh); | 1517 | gdp = ext4_get_group_desc(sb, 1, &bh); |
| 1519 | block_bitmap = ext4_block_bitmap(sb, gdp) - 1; | 1518 | block_bitmap = ext4_block_bitmap(sb, gdp) - 1; |
| @@ -1597,16 +1596,14 @@ static int ext4_check_descriptors(struct super_block *sb) | |||
| 1597 | (EXT4_BLOCKS_PER_GROUP(sb) - 1); | 1596 | (EXT4_BLOCKS_PER_GROUP(sb) - 1); |
| 1598 | 1597 | ||
| 1599 | block_bitmap = ext4_block_bitmap(sb, gdp); | 1598 | block_bitmap = ext4_block_bitmap(sb, gdp); |
| 1600 | if (block_bitmap < first_block || block_bitmap > last_block) | 1599 | if (block_bitmap < first_block || block_bitmap > last_block) { |
| 1601 | { | ||
| 1602 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " | 1600 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " |
| 1603 | "Block bitmap for group %lu not in group " | 1601 | "Block bitmap for group %lu not in group " |
| 1604 | "(block %llu)!", i, block_bitmap); | 1602 | "(block %llu)!", i, block_bitmap); |
| 1605 | return 0; | 1603 | return 0; |
| 1606 | } | 1604 | } |
| 1607 | inode_bitmap = ext4_inode_bitmap(sb, gdp); | 1605 | inode_bitmap = ext4_inode_bitmap(sb, gdp); |
| 1608 | if (inode_bitmap < first_block || inode_bitmap > last_block) | 1606 | if (inode_bitmap < first_block || inode_bitmap > last_block) { |
| 1609 | { | ||
| 1610 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " | 1607 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " |
| 1611 | "Inode bitmap for group %lu not in group " | 1608 | "Inode bitmap for group %lu not in group " |
| 1612 | "(block %llu)!", i, inode_bitmap); | 1609 | "(block %llu)!", i, inode_bitmap); |
| @@ -1614,26 +1611,28 @@ static int ext4_check_descriptors(struct super_block *sb) | |||
| 1614 | } | 1611 | } |
| 1615 | inode_table = ext4_inode_table(sb, gdp); | 1612 | inode_table = ext4_inode_table(sb, gdp); |
| 1616 | if (inode_table < first_block || | 1613 | if (inode_table < first_block || |
| 1617 | inode_table + sbi->s_itb_per_group - 1 > last_block) | 1614 | inode_table + sbi->s_itb_per_group - 1 > last_block) { |
| 1618 | { | ||
| 1619 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " | 1615 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " |
| 1620 | "Inode table for group %lu not in group " | 1616 | "Inode table for group %lu not in group " |
| 1621 | "(block %llu)!", i, inode_table); | 1617 | "(block %llu)!", i, inode_table); |
| 1622 | return 0; | 1618 | return 0; |
| 1623 | } | 1619 | } |
| 1620 | spin_lock(sb_bgl_lock(sbi, i)); | ||
| 1624 | if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { | 1621 | if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { |
| 1625 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " | 1622 | printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: " |
| 1626 | "Checksum for group %lu failed (%u!=%u)\n", | 1623 | "Checksum for group %lu failed (%u!=%u)\n", |
| 1627 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, | 1624 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, |
| 1628 | gdp)), le16_to_cpu(gdp->bg_checksum)); | 1625 | gdp)), le16_to_cpu(gdp->bg_checksum)); |
| 1629 | return 0; | 1626 | if (!(sb->s_flags & MS_RDONLY)) |
| 1627 | return 0; | ||
| 1630 | } | 1628 | } |
| 1629 | spin_unlock(sb_bgl_lock(sbi, i)); | ||
| 1631 | if (!flexbg_flag) | 1630 | if (!flexbg_flag) |
| 1632 | first_block += EXT4_BLOCKS_PER_GROUP(sb); | 1631 | first_block += EXT4_BLOCKS_PER_GROUP(sb); |
| 1633 | } | 1632 | } |
| 1634 | 1633 | ||
| 1635 | ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); | 1634 | ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); |
| 1636 | sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb)); | 1635 | sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb)); |
| 1637 | return 1; | 1636 | return 1; |
| 1638 | } | 1637 | } |
| 1639 | 1638 | ||
| @@ -1654,8 +1653,8 @@ static int ext4_check_descriptors(struct super_block *sb) | |||
| 1654 | * e2fsck was run on this filesystem, and it must have already done the orphan | 1653 | * e2fsck was run on this filesystem, and it must have already done the orphan |
| 1655 | * inode cleanup for us, so we can safely abort without any further action. | 1654 | * inode cleanup for us, so we can safely abort without any further action. |
| 1656 | */ | 1655 | */ |
| 1657 | static void ext4_orphan_cleanup (struct super_block * sb, | 1656 | static void ext4_orphan_cleanup(struct super_block *sb, |
| 1658 | struct ext4_super_block * es) | 1657 | struct ext4_super_block *es) |
| 1659 | { | 1658 | { |
| 1660 | unsigned int s_flags = sb->s_flags; | 1659 | unsigned int s_flags = sb->s_flags; |
| 1661 | int nr_orphans = 0, nr_truncates = 0; | 1660 | int nr_orphans = 0, nr_truncates = 0; |
| @@ -1732,7 +1731,7 @@ static void ext4_orphan_cleanup (struct super_block * sb, | |||
| 1732 | iput(inode); /* The delete magic happens here! */ | 1731 | iput(inode); /* The delete magic happens here! */ |
| 1733 | } | 1732 | } |
| 1734 | 1733 | ||
| 1735 | #define PLURAL(x) (x), ((x)==1) ? "" : "s" | 1734 | #define PLURAL(x) (x), ((x) == 1) ? "" : "s" |
| 1736 | 1735 | ||
| 1737 | if (nr_orphans) | 1736 | if (nr_orphans) |
| 1738 | printk(KERN_INFO "EXT4-fs: %s: %d orphan inode%s deleted\n", | 1737 | printk(KERN_INFO "EXT4-fs: %s: %d orphan inode%s deleted\n", |
| @@ -1899,12 +1898,12 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) | |||
| 1899 | return 0; | 1898 | return 0; |
| 1900 | } | 1899 | } |
| 1901 | 1900 | ||
| 1902 | static int ext4_fill_super (struct super_block *sb, void *data, int silent) | 1901 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
| 1903 | __releases(kernel_lock) | 1902 | __releases(kernel_lock) |
| 1904 | __acquires(kernel_lock) | 1903 | __acquires(kernel_lock) |
| 1905 | 1904 | ||
| 1906 | { | 1905 | { |
| 1907 | struct buffer_head * bh; | 1906 | struct buffer_head *bh; |
| 1908 | struct ext4_super_block *es = NULL; | 1907 | struct ext4_super_block *es = NULL; |
| 1909 | struct ext4_sb_info *sbi; | 1908 | struct ext4_sb_info *sbi; |
| 1910 | ext4_fsblk_t block; | 1909 | ext4_fsblk_t block; |
| @@ -1953,7 +1952,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 1953 | } | 1952 | } |
| 1954 | 1953 | ||
| 1955 | if (!(bh = sb_bread(sb, logical_sb_block))) { | 1954 | if (!(bh = sb_bread(sb, logical_sb_block))) { |
| 1956 | printk (KERN_ERR "EXT4-fs: unable to read superblock\n"); | 1955 | printk(KERN_ERR "EXT4-fs: unable to read superblock\n"); |
| 1957 | goto out_fail; | 1956 | goto out_fail; |
| 1958 | } | 1957 | } |
| 1959 | /* | 1958 | /* |
| @@ -2026,8 +2025,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2026 | set_opt(sbi->s_mount_opt, DELALLOC); | 2025 | set_opt(sbi->s_mount_opt, DELALLOC); |
| 2027 | 2026 | ||
| 2028 | 2027 | ||
| 2029 | if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, | 2028 | if (!parse_options((char *) data, sb, &journal_inum, &journal_devnum, |
| 2030 | NULL, 0)) | 2029 | NULL, 0)) |
| 2031 | goto failed_mount; | 2030 | goto failed_mount; |
| 2032 | 2031 | ||
| 2033 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | | 2032 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | |
| @@ -2102,7 +2101,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2102 | goto failed_mount; | 2101 | goto failed_mount; |
| 2103 | } | 2102 | } |
| 2104 | 2103 | ||
| 2105 | brelse (bh); | 2104 | brelse(bh); |
| 2106 | logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; | 2105 | logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; |
| 2107 | offset = do_div(logical_sb_block, blocksize); | 2106 | offset = do_div(logical_sb_block, blocksize); |
| 2108 | bh = sb_bread(sb, logical_sb_block); | 2107 | bh = sb_bread(sb, logical_sb_block); |
| @@ -2114,8 +2113,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2114 | es = (struct ext4_super_block *)(((char *)bh->b_data) + offset); | 2113 | es = (struct ext4_super_block *)(((char *)bh->b_data) + offset); |
| 2115 | sbi->s_es = es; | 2114 | sbi->s_es = es; |
| 2116 | if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { | 2115 | if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { |
| 2117 | printk (KERN_ERR | 2116 | printk(KERN_ERR |
| 2118 | "EXT4-fs: Magic mismatch, very weird !\n"); | 2117 | "EXT4-fs: Magic mismatch, very weird !\n"); |
| 2119 | goto failed_mount; | 2118 | goto failed_mount; |
| 2120 | } | 2119 | } |
| 2121 | } | 2120 | } |
| @@ -2132,9 +2131,9 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2132 | if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || | 2131 | if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || |
| 2133 | (!is_power_of_2(sbi->s_inode_size)) || | 2132 | (!is_power_of_2(sbi->s_inode_size)) || |
| 2134 | (sbi->s_inode_size > blocksize)) { | 2133 | (sbi->s_inode_size > blocksize)) { |
| 2135 | printk (KERN_ERR | 2134 | printk(KERN_ERR |
| 2136 | "EXT4-fs: unsupported inode size: %d\n", | 2135 | "EXT4-fs: unsupported inode size: %d\n", |
| 2137 | sbi->s_inode_size); | 2136 | sbi->s_inode_size); |
| 2138 | goto failed_mount; | 2137 | goto failed_mount; |
| 2139 | } | 2138 | } |
| 2140 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) | 2139 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) |
| @@ -2166,20 +2165,20 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2166 | sbi->s_mount_state = le16_to_cpu(es->s_state); | 2165 | sbi->s_mount_state = le16_to_cpu(es->s_state); |
| 2167 | sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); | 2166 | sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); |
| 2168 | sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); | 2167 | sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); |
| 2169 | for (i=0; i < 4; i++) | 2168 | for (i = 0; i < 4; i++) |
| 2170 | sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); | 2169 | sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); |
| 2171 | sbi->s_def_hash_version = es->s_def_hash_version; | 2170 | sbi->s_def_hash_version = es->s_def_hash_version; |
| 2172 | 2171 | ||
| 2173 | if (sbi->s_blocks_per_group > blocksize * 8) { | 2172 | if (sbi->s_blocks_per_group > blocksize * 8) { |
| 2174 | printk (KERN_ERR | 2173 | printk(KERN_ERR |
| 2175 | "EXT4-fs: #blocks per group too big: %lu\n", | 2174 | "EXT4-fs: #blocks per group too big: %lu\n", |
| 2176 | sbi->s_blocks_per_group); | 2175 | sbi->s_blocks_per_group); |
| 2177 | goto failed_mount; | 2176 | goto failed_mount; |
| 2178 | } | 2177 | } |
| 2179 | if (sbi->s_inodes_per_group > blocksize * 8) { | 2178 | if (sbi->s_inodes_per_group > blocksize * 8) { |
| 2180 | printk (KERN_ERR | 2179 | printk(KERN_ERR |
| 2181 | "EXT4-fs: #inodes per group too big: %lu\n", | 2180 | "EXT4-fs: #inodes per group too big: %lu\n", |
| 2182 | sbi->s_inodes_per_group); | 2181 | sbi->s_inodes_per_group); |
| 2183 | goto failed_mount; | 2182 | goto failed_mount; |
| 2184 | } | 2183 | } |
| 2185 | 2184 | ||
| @@ -2213,10 +2212,10 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2213 | sbi->s_groups_count = blocks_count; | 2212 | sbi->s_groups_count = blocks_count; |
| 2214 | db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / | 2213 | db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / |
| 2215 | EXT4_DESC_PER_BLOCK(sb); | 2214 | EXT4_DESC_PER_BLOCK(sb); |
| 2216 | sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), | 2215 | sbi->s_group_desc = kmalloc(db_count * sizeof(struct buffer_head *), |
| 2217 | GFP_KERNEL); | 2216 | GFP_KERNEL); |
| 2218 | if (sbi->s_group_desc == NULL) { | 2217 | if (sbi->s_group_desc == NULL) { |
| 2219 | printk (KERN_ERR "EXT4-fs: not enough memory\n"); | 2218 | printk(KERN_ERR "EXT4-fs: not enough memory\n"); |
| 2220 | goto failed_mount; | 2219 | goto failed_mount; |
| 2221 | } | 2220 | } |
| 2222 | 2221 | ||
| @@ -2226,13 +2225,13 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2226 | block = descriptor_loc(sb, logical_sb_block, i); | 2225 | block = descriptor_loc(sb, logical_sb_block, i); |
| 2227 | sbi->s_group_desc[i] = sb_bread(sb, block); | 2226 | sbi->s_group_desc[i] = sb_bread(sb, block); |
| 2228 | if (!sbi->s_group_desc[i]) { | 2227 | if (!sbi->s_group_desc[i]) { |
| 2229 | printk (KERN_ERR "EXT4-fs: " | 2228 | printk(KERN_ERR "EXT4-fs: " |
| 2230 | "can't read group descriptor %d\n", i); | 2229 | "can't read group descriptor %d\n", i); |
| 2231 | db_count = i; | 2230 | db_count = i; |
| 2232 | goto failed_mount2; | 2231 | goto failed_mount2; |
| 2233 | } | 2232 | } |
| 2234 | } | 2233 | } |
| 2235 | if (!ext4_check_descriptors (sb)) { | 2234 | if (!ext4_check_descriptors(sb)) { |
| 2236 | printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n"); | 2235 | printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n"); |
| 2237 | goto failed_mount2; | 2236 | goto failed_mount2; |
| 2238 | } | 2237 | } |
| @@ -2308,11 +2307,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2308 | EXT4_SB(sb)->s_journal->j_failed_commit) { | 2307 | EXT4_SB(sb)->s_journal->j_failed_commit) { |
| 2309 | printk(KERN_CRIT "EXT4-fs error (device %s): " | 2308 | printk(KERN_CRIT "EXT4-fs error (device %s): " |
| 2310 | "ext4_fill_super: Journal transaction " | 2309 | "ext4_fill_super: Journal transaction " |
| 2311 | "%u is corrupt\n", sb->s_id, | 2310 | "%u is corrupt\n", sb->s_id, |
| 2312 | EXT4_SB(sb)->s_journal->j_failed_commit); | 2311 | EXT4_SB(sb)->s_journal->j_failed_commit); |
| 2313 | if (test_opt (sb, ERRORS_RO)) { | 2312 | if (test_opt(sb, ERRORS_RO)) { |
| 2314 | printk (KERN_CRIT | 2313 | printk(KERN_CRIT |
| 2315 | "Mounting filesystem read-only\n"); | 2314 | "Mounting filesystem read-only\n"); |
| 2316 | sb->s_flags |= MS_RDONLY; | 2315 | sb->s_flags |= MS_RDONLY; |
| 2317 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | 2316 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; |
| 2318 | es->s_state |= cpu_to_le16(EXT4_ERROR_FS); | 2317 | es->s_state |= cpu_to_le16(EXT4_ERROR_FS); |
| @@ -2332,9 +2331,9 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2332 | goto failed_mount3; | 2331 | goto failed_mount3; |
| 2333 | } else { | 2332 | } else { |
| 2334 | if (!silent) | 2333 | if (!silent) |
| 2335 | printk (KERN_ERR | 2334 | printk(KERN_ERR |
| 2336 | "ext4: No journal on filesystem on %s\n", | 2335 | "ext4: No journal on filesystem on %s\n", |
| 2337 | sb->s_id); | 2336 | sb->s_id); |
| 2338 | goto failed_mount3; | 2337 | goto failed_mount3; |
| 2339 | } | 2338 | } |
| 2340 | 2339 | ||
| @@ -2418,7 +2417,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2418 | goto failed_mount4; | 2417 | goto failed_mount4; |
| 2419 | } | 2418 | } |
| 2420 | 2419 | ||
| 2421 | ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY); | 2420 | ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY); |
| 2422 | 2421 | ||
| 2423 | /* determine the minimum size of new large inodes, if present */ | 2422 | /* determine the minimum size of new large inodes, if present */ |
| 2424 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { | 2423 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { |
| @@ -2457,12 +2456,12 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) | |||
| 2457 | ext4_orphan_cleanup(sb, es); | 2456 | ext4_orphan_cleanup(sb, es); |
| 2458 | EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS; | 2457 | EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS; |
| 2459 | if (needs_recovery) | 2458 | if (needs_recovery) |
| 2460 | printk (KERN_INFO "EXT4-fs: recovery complete.\n"); | 2459 | printk(KERN_INFO "EXT4-fs: recovery complete.\n"); |
| 2461 | ext4_mark_recovery_complete(sb, es); | 2460 | ext4_mark_recovery_complete(sb, es); |
| 2462 | printk (KERN_INFO "EXT4-fs: mounted filesystem with %s data mode.\n", | 2461 | printk(KERN_INFO "EXT4-fs: mounted filesystem with %s data mode.\n", |
| 2463 | test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ? "journal": | 2462 | test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ? "journal": |
| 2464 | test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": | 2463 | test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered": |
| 2465 | "writeback"); | 2464 | "writeback"); |
| 2466 | 2465 | ||
| 2467 | if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { | 2466 | if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { |
| 2468 | printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - " | 2467 | printk(KERN_WARNING "EXT4-fs: Ignoring delalloc option - " |
| @@ -2575,14 +2574,14 @@ static journal_t *ext4_get_journal(struct super_block *sb, | |||
| 2575 | static journal_t *ext4_get_dev_journal(struct super_block *sb, | 2574 | static journal_t *ext4_get_dev_journal(struct super_block *sb, |
| 2576 | dev_t j_dev) | 2575 | dev_t j_dev) |
| 2577 | { | 2576 | { |
| 2578 | struct buffer_head * bh; | 2577 | struct buffer_head *bh; |
| 2579 | journal_t *journal; | 2578 | journal_t *journal; |
| 2580 | ext4_fsblk_t start; | 2579 | ext4_fsblk_t start; |
| 2581 | ext4_fsblk_t len; | 2580 | ext4_fsblk_t len; |
| 2582 | int hblock, blocksize; | 2581 | int hblock, blocksize; |
| 2583 | ext4_fsblk_t sb_block; | 2582 | ext4_fsblk_t sb_block; |
| 2584 | unsigned long offset; | 2583 | unsigned long offset; |
| 2585 | struct ext4_super_block * es; | 2584 | struct ext4_super_block *es; |
| 2586 | struct block_device *bdev; | 2585 | struct block_device *bdev; |
| 2587 | 2586 | ||
| 2588 | bdev = ext4_blkdev_get(j_dev); | 2587 | bdev = ext4_blkdev_get(j_dev); |
| @@ -2697,8 +2696,8 @@ static int ext4_load_journal(struct super_block *sb, | |||
| 2697 | "unavailable, cannot proceed.\n"); | 2696 | "unavailable, cannot proceed.\n"); |
| 2698 | return -EROFS; | 2697 | return -EROFS; |
| 2699 | } | 2698 | } |
| 2700 | printk (KERN_INFO "EXT4-fs: write access will " | 2699 | printk(KERN_INFO "EXT4-fs: write access will " |
| 2701 | "be enabled during recovery.\n"); | 2700 | "be enabled during recovery.\n"); |
| 2702 | } | 2701 | } |
| 2703 | } | 2702 | } |
| 2704 | 2703 | ||
| @@ -2751,8 +2750,8 @@ static int ext4_load_journal(struct super_block *sb, | |||
| 2751 | return 0; | 2750 | return 0; |
| 2752 | } | 2751 | } |
| 2753 | 2752 | ||
| 2754 | static int ext4_create_journal(struct super_block * sb, | 2753 | static int ext4_create_journal(struct super_block *sb, |
| 2755 | struct ext4_super_block * es, | 2754 | struct ext4_super_block *es, |
| 2756 | unsigned int journal_inum) | 2755 | unsigned int journal_inum) |
| 2757 | { | 2756 | { |
| 2758 | journal_t *journal; | 2757 | journal_t *journal; |
| @@ -2793,9 +2792,8 @@ static int ext4_create_journal(struct super_block * sb, | |||
| 2793 | return 0; | 2792 | return 0; |
| 2794 | } | 2793 | } |
| 2795 | 2794 | ||
| 2796 | static void ext4_commit_super (struct super_block * sb, | 2795 | static void ext4_commit_super(struct super_block *sb, |
| 2797 | struct ext4_super_block * es, | 2796 | struct ext4_super_block *es, int sync) |
| 2798 | int sync) | ||
| 2799 | { | 2797 | { |
| 2800 | struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; | 2798 | struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; |
| 2801 | 2799 | ||
| @@ -2816,8 +2814,8 @@ static void ext4_commit_super (struct super_block * sb, | |||
| 2816 | * remounting) the filesystem readonly, then we will end up with a | 2814 | * remounting) the filesystem readonly, then we will end up with a |
| 2817 | * consistent fs on disk. Record that fact. | 2815 | * consistent fs on disk. Record that fact. |
| 2818 | */ | 2816 | */ |
| 2819 | static void ext4_mark_recovery_complete(struct super_block * sb, | 2817 | static void ext4_mark_recovery_complete(struct super_block *sb, |
| 2820 | struct ext4_super_block * es) | 2818 | struct ext4_super_block *es) |
| 2821 | { | 2819 | { |
| 2822 | journal_t *journal = EXT4_SB(sb)->s_journal; | 2820 | journal_t *journal = EXT4_SB(sb)->s_journal; |
| 2823 | 2821 | ||
| @@ -2839,8 +2837,8 @@ static void ext4_mark_recovery_complete(struct super_block * sb, | |||
| 2839 | * has recorded an error from a previous lifetime, move that error to the | 2837 | * has recorded an error from a previous lifetime, move that error to the |
| 2840 | * main filesystem now. | 2838 | * main filesystem now. |
| 2841 | */ | 2839 | */ |
| 2842 | static void ext4_clear_journal_err(struct super_block * sb, | 2840 | static void ext4_clear_journal_err(struct super_block *sb, |
| 2843 | struct ext4_super_block * es) | 2841 | struct ext4_super_block *es) |
| 2844 | { | 2842 | { |
| 2845 | journal_t *journal; | 2843 | journal_t *journal; |
| 2846 | int j_errno; | 2844 | int j_errno; |
| @@ -2865,7 +2863,7 @@ static void ext4_clear_journal_err(struct super_block * sb, | |||
| 2865 | 2863 | ||
| 2866 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | 2864 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; |
| 2867 | es->s_state |= cpu_to_le16(EXT4_ERROR_FS); | 2865 | es->s_state |= cpu_to_le16(EXT4_ERROR_FS); |
| 2868 | ext4_commit_super (sb, es, 1); | 2866 | ext4_commit_super(sb, es, 1); |
| 2869 | 2867 | ||
| 2870 | jbd2_journal_clear_err(journal); | 2868 | jbd2_journal_clear_err(journal); |
| 2871 | } | 2869 | } |
| @@ -2898,7 +2896,7 @@ int ext4_force_commit(struct super_block *sb) | |||
| 2898 | * This implicitly triggers the writebehind on sync(). | 2896 | * This implicitly triggers the writebehind on sync(). |
| 2899 | */ | 2897 | */ |
| 2900 | 2898 | ||
| 2901 | static void ext4_write_super (struct super_block * sb) | 2899 | static void ext4_write_super(struct super_block *sb) |
| 2902 | { | 2900 | { |
| 2903 | if (mutex_trylock(&sb->s_lock) != 0) | 2901 | if (mutex_trylock(&sb->s_lock) != 0) |
| 2904 | BUG(); | 2902 | BUG(); |
| @@ -2954,13 +2952,14 @@ static void ext4_unlockfs(struct super_block *sb) | |||
| 2954 | } | 2952 | } |
| 2955 | } | 2953 | } |
| 2956 | 2954 | ||
| 2957 | static int ext4_remount (struct super_block * sb, int * flags, char * data) | 2955 | static int ext4_remount(struct super_block *sb, int *flags, char *data) |
| 2958 | { | 2956 | { |
| 2959 | struct ext4_super_block * es; | 2957 | struct ext4_super_block *es; |
| 2960 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2958 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| 2961 | ext4_fsblk_t n_blocks_count = 0; | 2959 | ext4_fsblk_t n_blocks_count = 0; |
| 2962 | unsigned long old_sb_flags; | 2960 | unsigned long old_sb_flags; |
| 2963 | struct ext4_mount_options old_opts; | 2961 | struct ext4_mount_options old_opts; |
| 2962 | ext4_group_t g; | ||
| 2964 | int err; | 2963 | int err; |
| 2965 | #ifdef CONFIG_QUOTA | 2964 | #ifdef CONFIG_QUOTA |
| 2966 | int i; | 2965 | int i; |
| @@ -3039,6 +3038,26 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) | |||
| 3039 | } | 3038 | } |
| 3040 | 3039 | ||
| 3041 | /* | 3040 | /* |
| 3041 | * Make sure the group descriptor checksums | ||
| 3042 | * are sane. If they aren't, refuse to | ||
| 3043 | * remount r/w. | ||
| 3044 | */ | ||
| 3045 | for (g = 0; g < sbi->s_groups_count; g++) { | ||
| 3046 | struct ext4_group_desc *gdp = | ||
| 3047 | ext4_get_group_desc(sb, g, NULL); | ||
| 3048 | |||
| 3049 | if (!ext4_group_desc_csum_verify(sbi, g, gdp)) { | ||
| 3050 | printk(KERN_ERR | ||
| 3051 | "EXT4-fs: ext4_remount: " | ||
| 3052 | "Checksum for group %lu failed (%u!=%u)\n", | ||
| 3053 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), | ||
| 3054 | le16_to_cpu(gdp->bg_checksum)); | ||
| 3055 | err = -EINVAL; | ||
| 3056 | goto restore_opts; | ||
| 3057 | } | ||
| 3058 | } | ||
| 3059 | |||
| 3060 | /* | ||
| 3042 | * If we have an unprocessed orphan list hanging | 3061 | * If we have an unprocessed orphan list hanging |
| 3043 | * around from a previously readonly bdev mount, | 3062 | * around from a previously readonly bdev mount, |
| 3044 | * require a full umount/remount for now. | 3063 | * require a full umount/remount for now. |
| @@ -3063,7 +3082,7 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) | |||
| 3063 | sbi->s_mount_state = le16_to_cpu(es->s_state); | 3082 | sbi->s_mount_state = le16_to_cpu(es->s_state); |
| 3064 | if ((err = ext4_group_extend(sb, es, n_blocks_count))) | 3083 | if ((err = ext4_group_extend(sb, es, n_blocks_count))) |
| 3065 | goto restore_opts; | 3084 | goto restore_opts; |
| 3066 | if (!ext4_setup_super (sb, es, 0)) | 3085 | if (!ext4_setup_super(sb, es, 0)) |
| 3067 | sb->s_flags &= ~MS_RDONLY; | 3086 | sb->s_flags &= ~MS_RDONLY; |
| 3068 | } | 3087 | } |
| 3069 | } | 3088 | } |
| @@ -3093,7 +3112,7 @@ restore_opts: | |||
| 3093 | return err; | 3112 | return err; |
| 3094 | } | 3113 | } |
| 3095 | 3114 | ||
| 3096 | static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) | 3115 | static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 3097 | { | 3116 | { |
| 3098 | struct super_block *sb = dentry->d_sb; | 3117 | struct super_block *sb = dentry->d_sb; |
| 3099 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 3118 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
| @@ -3331,12 +3350,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
| 3331 | } | 3350 | } |
| 3332 | /* Journaling quota? */ | 3351 | /* Journaling quota? */ |
| 3333 | if (EXT4_SB(sb)->s_qf_names[type]) { | 3352 | if (EXT4_SB(sb)->s_qf_names[type]) { |
| 3334 | /* Quotafile not of fs root? */ | 3353 | /* Quotafile not in fs root? */ |
| 3335 | if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) | 3354 | if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) |
| 3336 | printk(KERN_WARNING | 3355 | printk(KERN_WARNING |
| 3337 | "EXT4-fs: Quota file not on filesystem root. " | 3356 | "EXT4-fs: Quota file not on filesystem root. " |
| 3338 | "Journaled quota will not work.\n"); | 3357 | "Journaled quota will not work.\n"); |
| 3339 | } | 3358 | } |
| 3340 | 3359 | ||
| 3341 | /* | 3360 | /* |
| 3342 | * When we journal data on quota file, we have to flush journal to see | 3361 | * When we journal data on quota file, we have to flush journal to see |
| @@ -3352,8 +3371,9 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, | |||
| 3352 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 3371 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); |
| 3353 | } | 3372 | } |
| 3354 | 3373 | ||
| 3374 | err = vfs_quota_on_path(sb, type, format_id, &nd.path); | ||
| 3355 | path_put(&nd.path); | 3375 | path_put(&nd.path); |
| 3356 | return vfs_quota_on(sb, type, format_id, path, remount); | 3376 | return err; |
| 3357 | } | 3377 | } |
| 3358 | 3378 | ||
| 3359 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 3379 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 93c5fdcdad2e..8954208b4893 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
| @@ -1512,7 +1512,7 @@ static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header, | |||
| 1512 | char *name = entry->e_name; | 1512 | char *name = entry->e_name; |
| 1513 | int n; | 1513 | int n; |
| 1514 | 1514 | ||
| 1515 | for (n=0; n < entry->e_name_len; n++) { | 1515 | for (n = 0; n < entry->e_name_len; n++) { |
| 1516 | hash = (hash << NAME_HASH_SHIFT) ^ | 1516 | hash = (hash << NAME_HASH_SHIFT) ^ |
| 1517 | (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ | 1517 | (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ |
| 1518 | *name++; | 1518 | *name++; |
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 3a9ecac8d61f..3222f51c41cf 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c | |||
| @@ -36,7 +36,7 @@ static inline int fat_max_cache(struct inode *inode) | |||
| 36 | 36 | ||
| 37 | static struct kmem_cache *fat_cache_cachep; | 37 | static struct kmem_cache *fat_cache_cachep; |
| 38 | 38 | ||
| 39 | static void init_once(struct kmem_cache *cachep, void *foo) | 39 | static void init_once(void *foo) |
| 40 | { | 40 | { |
| 41 | struct fat_cache *cache = (struct fat_cache *)foo; | 41 | struct fat_cache *cache = (struct fat_cache *)foo; |
| 42 | 42 | ||
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 34541d06e626..cd4a0162e10d 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
| @@ -17,7 +17,6 @@ | |||
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
| 19 | #include <linux/msdos_fs.h> | 19 | #include <linux/msdos_fs.h> |
| 20 | #include <linux/dirent.h> | ||
| 21 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 22 | #include <linux/buffer_head.h> | 21 | #include <linux/buffer_head.h> |
| 23 | #include <linux/compat.h> | 22 | #include <linux/compat.h> |
| @@ -124,10 +123,11 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, | |||
| 124 | * but ignore that right now. | 123 | * but ignore that right now. |
| 125 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. | 124 | * Ahem... Stack smashing in ring 0 isn't fun. Fixed. |
| 126 | */ | 125 | */ |
| 127 | static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, | 126 | static int uni16_to_x8(unsigned char *ascii, const wchar_t *uni, int len, |
| 128 | int uni_xlate, struct nls_table *nls) | 127 | int uni_xlate, struct nls_table *nls) |
| 129 | { | 128 | { |
| 130 | wchar_t *ip, ec; | 129 | const wchar_t *ip; |
| 130 | wchar_t ec; | ||
| 131 | unsigned char *op, nc; | 131 | unsigned char *op, nc; |
| 132 | int charlen; | 132 | int charlen; |
| 133 | int k; | 133 | int k; |
| @@ -167,6 +167,16 @@ static int uni16_to_x8(unsigned char *ascii, wchar_t *uni, int len, | |||
| 167 | return (op - ascii); | 167 | return (op - ascii); |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | static inline int fat_uni_to_x8(struct msdos_sb_info *sbi, const wchar_t *uni, | ||
| 171 | unsigned char *buf, int size) | ||
| 172 | { | ||
| 173 | if (sbi->options.utf8) | ||
| 174 | return utf8_wcstombs(buf, uni, size); | ||
| 175 | else | ||
| 176 | return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate, | ||
| 177 | sbi->nls_io); | ||
| 178 | } | ||
| 179 | |||
| 170 | static inline int | 180 | static inline int |
| 171 | fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) | 181 | fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) |
| 172 | { | 182 | { |
| @@ -227,6 +237,19 @@ fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size, | |||
| 227 | return len; | 237 | return len; |
| 228 | } | 238 | } |
| 229 | 239 | ||
| 240 | static inline int fat_name_match(struct msdos_sb_info *sbi, | ||
| 241 | const unsigned char *a, int a_len, | ||
| 242 | const unsigned char *b, int b_len) | ||
| 243 | { | ||
| 244 | if (a_len != b_len) | ||
| 245 | return 0; | ||
| 246 | |||
| 247 | if (sbi->options.name_check != 's') | ||
| 248 | return !nls_strnicmp(sbi->nls_io, a, b, a_len); | ||
| 249 | else | ||
| 250 | return !memcmp(a, b, a_len); | ||
| 251 | } | ||
| 252 | |||
| 230 | enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, }; | 253 | enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, }; |
| 231 | 254 | ||
| 232 | /** | 255 | /** |
| @@ -302,6 +325,19 @@ parse_long: | |||
| 302 | } | 325 | } |
| 303 | 326 | ||
| 304 | /* | 327 | /* |
| 328 | * Maximum buffer size of short name. | ||
| 329 | * [(MSDOS_NAME + '.') * max one char + nul] | ||
| 330 | * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul] | ||
| 331 | */ | ||
| 332 | #define FAT_MAX_SHORT_SIZE ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1) | ||
| 333 | /* | ||
| 334 | * Maximum buffer size of unicode chars from slots. | ||
| 335 | * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)] | ||
| 336 | */ | ||
| 337 | #define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1) | ||
| 338 | #define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t)) | ||
| 339 | |||
| 340 | /* | ||
| 305 | * Return values: negative -> error, 0 -> not found, positive -> found, | 341 | * Return values: negative -> error, 0 -> not found, positive -> found, |
| 306 | * value is the total amount of slots, including the shortname entry. | 342 | * value is the total amount of slots, including the shortname entry. |
| 307 | */ | 343 | */ |
| @@ -312,29 +348,20 @@ int fat_search_long(struct inode *inode, const unsigned char *name, | |||
| 312 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 348 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
| 313 | struct buffer_head *bh = NULL; | 349 | struct buffer_head *bh = NULL; |
| 314 | struct msdos_dir_entry *de; | 350 | struct msdos_dir_entry *de; |
| 315 | struct nls_table *nls_io = sbi->nls_io; | ||
| 316 | struct nls_table *nls_disk = sbi->nls_disk; | 351 | struct nls_table *nls_disk = sbi->nls_disk; |
| 317 | wchar_t bufuname[14]; | ||
| 318 | unsigned char nr_slots; | 352 | unsigned char nr_slots; |
| 319 | int xlate_len; | 353 | wchar_t bufuname[14]; |
| 320 | wchar_t *unicode = NULL; | 354 | wchar_t *unicode = NULL; |
| 321 | unsigned char work[MSDOS_NAME]; | 355 | unsigned char work[MSDOS_NAME]; |
| 322 | unsigned char *bufname = NULL; | 356 | unsigned char bufname[FAT_MAX_SHORT_SIZE]; |
| 323 | int uni_xlate = sbi->options.unicode_xlate; | ||
| 324 | int utf8 = sbi->options.utf8; | ||
| 325 | int anycase = (sbi->options.name_check != 's'); | ||
| 326 | unsigned short opt_shortname = sbi->options.shortname; | 357 | unsigned short opt_shortname = sbi->options.shortname; |
| 327 | loff_t cpos = 0; | 358 | loff_t cpos = 0; |
| 328 | int chl, i, j, last_u, err; | 359 | int chl, i, j, last_u, err, len; |
| 329 | |||
| 330 | bufname = __getname(); | ||
| 331 | if (!bufname) | ||
| 332 | return -ENOMEM; | ||
| 333 | 360 | ||
| 334 | err = -ENOENT; | 361 | err = -ENOENT; |
| 335 | while(1) { | 362 | while (1) { |
| 336 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 363 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
| 337 | goto EODir; | 364 | goto end_of_dir; |
| 338 | parse_record: | 365 | parse_record: |
| 339 | nr_slots = 0; | 366 | nr_slots = 0; |
| 340 | if (de->name[0] == DELETED_FLAG) | 367 | if (de->name[0] == DELETED_FLAG) |
| @@ -353,7 +380,7 @@ parse_record: | |||
| 353 | else if (status == PARSE_NOT_LONGNAME) | 380 | else if (status == PARSE_NOT_LONGNAME) |
| 354 | goto parse_record; | 381 | goto parse_record; |
| 355 | else if (status == PARSE_EOF) | 382 | else if (status == PARSE_EOF) |
| 356 | goto EODir; | 383 | goto end_of_dir; |
| 357 | } | 384 | } |
| 358 | 385 | ||
| 359 | memcpy(work, de->name, sizeof(de->name)); | 386 | memcpy(work, de->name, sizeof(de->name)); |
| @@ -394,30 +421,24 @@ parse_record: | |||
| 394 | if (!last_u) | 421 | if (!last_u) |
| 395 | continue; | 422 | continue; |
| 396 | 423 | ||
| 424 | /* Compare shortname */ | ||
| 397 | bufuname[last_u] = 0x0000; | 425 | bufuname[last_u] = 0x0000; |
| 398 | xlate_len = utf8 | 426 | len = fat_uni_to_x8(sbi, bufuname, bufname, sizeof(bufname)); |
| 399 | ?utf8_wcstombs(bufname, bufuname, PATH_MAX) | 427 | if (fat_name_match(sbi, name, name_len, bufname, len)) |
| 400 | :uni16_to_x8(bufname, bufuname, PATH_MAX, uni_xlate, nls_io); | 428 | goto found; |
| 401 | if (xlate_len == name_len) | ||
| 402 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | ||
| 403 | (anycase && !nls_strnicmp(nls_io, name, bufname, | ||
| 404 | xlate_len))) | ||
| 405 | goto Found; | ||
| 406 | 429 | ||
| 407 | if (nr_slots) { | 430 | if (nr_slots) { |
| 408 | xlate_len = utf8 | 431 | void *longname = unicode + FAT_MAX_UNI_CHARS; |
| 409 | ?utf8_wcstombs(bufname, unicode, PATH_MAX) | 432 | int size = PATH_MAX - FAT_MAX_UNI_SIZE; |
| 410 | :uni16_to_x8(bufname, unicode, PATH_MAX, uni_xlate, nls_io); | 433 | |
| 411 | if (xlate_len != name_len) | 434 | /* Compare longname */ |
| 412 | continue; | 435 | len = fat_uni_to_x8(sbi, unicode, longname, size); |
| 413 | if ((!anycase && !memcmp(name, bufname, xlate_len)) || | 436 | if (fat_name_match(sbi, name, name_len, longname, len)) |
| 414 | (anycase && !nls_strnicmp(nls_io, name, bufname, | 437 | goto found; |
| 415 | xlate_len))) | ||
| 416 | goto Found; | ||
| 417 | } | 438 | } |
| 418 | } | 439 | } |
| 419 | 440 | ||
| 420 | Found: | 441 | found: |
| 421 | nr_slots++; /* include the de */ | 442 | nr_slots++; /* include the de */ |
| 422 | sinfo->slot_off = cpos - nr_slots * sizeof(*de); | 443 | sinfo->slot_off = cpos - nr_slots * sizeof(*de); |
| 423 | sinfo->nr_slots = nr_slots; | 444 | sinfo->nr_slots = nr_slots; |
| @@ -425,9 +446,7 @@ Found: | |||
| 425 | sinfo->bh = bh; | 446 | sinfo->bh = bh; |
| 426 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); | 447 | sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); |
| 427 | err = 0; | 448 | err = 0; |
| 428 | EODir: | 449 | end_of_dir: |
| 429 | if (bufname) | ||
| 430 | __putname(bufname); | ||
| 431 | if (unicode) | 450 | if (unicode) |
| 432 | __putname(unicode); | 451 | __putname(unicode); |
| 433 | 452 | ||
| @@ -453,23 +472,20 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
| 453 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 472 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
| 454 | struct buffer_head *bh; | 473 | struct buffer_head *bh; |
| 455 | struct msdos_dir_entry *de; | 474 | struct msdos_dir_entry *de; |
| 456 | struct nls_table *nls_io = sbi->nls_io; | ||
| 457 | struct nls_table *nls_disk = sbi->nls_disk; | 475 | struct nls_table *nls_disk = sbi->nls_disk; |
| 458 | unsigned char long_slots; | 476 | unsigned char nr_slots; |
| 459 | const char *fill_name; | ||
| 460 | int fill_len; | ||
| 461 | wchar_t bufuname[14]; | 477 | wchar_t bufuname[14]; |
| 462 | wchar_t *unicode = NULL; | 478 | wchar_t *unicode = NULL; |
| 463 | unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname; | 479 | unsigned char c, work[MSDOS_NAME]; |
| 464 | unsigned long lpos, dummy, *furrfu = &lpos; | 480 | unsigned char bufname[FAT_MAX_SHORT_SIZE], *ptname = bufname; |
| 465 | int uni_xlate = sbi->options.unicode_xlate; | 481 | unsigned short opt_shortname = sbi->options.shortname; |
| 466 | int isvfat = sbi->options.isvfat; | 482 | int isvfat = sbi->options.isvfat; |
| 467 | int utf8 = sbi->options.utf8; | ||
| 468 | int nocase = sbi->options.nocase; | 483 | int nocase = sbi->options.nocase; |
| 469 | unsigned short opt_shortname = sbi->options.shortname; | 484 | const char *fill_name = NULL; |
| 470 | unsigned long inum; | 485 | unsigned long inum; |
| 471 | int chi, chl, i, i2, j, last, last_u, dotoffset = 0; | 486 | unsigned long lpos, dummy, *furrfu = &lpos; |
| 472 | loff_t cpos; | 487 | loff_t cpos; |
| 488 | int chi, chl, i, i2, j, last, last_u, dotoffset = 0, fill_len = 0; | ||
| 473 | int ret = 0; | 489 | int ret = 0; |
| 474 | 490 | ||
| 475 | lock_super(sb); | 491 | lock_super(sb); |
| @@ -489,43 +505,58 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent, | |||
| 489 | cpos = 0; | 505 | cpos = 0; |
| 490 | } | 506 | } |
| 491 | } | 507 | } |
| 492 | if (cpos & (sizeof(struct msdos_dir_entry)-1)) { | 508 | if (cpos & (sizeof(struct msdos_dir_entry) - 1)) { |
| 493 | ret = -ENOENT; | 509 | ret = -ENOENT; |
| 494 | goto out; | 510 | goto out; |
| 495 | } | 511 | } |
| 496 | 512 | ||
| 497 | bh = NULL; | 513 | bh = NULL; |
| 498 | GetNew: | 514 | get_new: |
| 499 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | 515 | if (fat_get_entry(inode, &cpos, &bh, &de) == -1) |
| 500 | goto EODir; | 516 | goto end_of_dir; |
| 501 | parse_record: | 517 | parse_record: |
| 502 | long_slots = 0; | 518 | nr_slots = 0; |
| 503 | /* Check for long filename entry */ | 519 | /* |
| 504 | if (isvfat) { | 520 | * Check for long filename entry, but if short_only, we don't |
| 521 | * need to parse long filename. | ||
| 522 | */ | ||
| 523 | if (isvfat && !short_only) { | ||
| 505 | if (de->name[0] == DELETED_FLAG) | 524 | if (de->name[0] == DELETED_FLAG) |
| 506 | goto RecEnd; | 525 | goto record_end; |
| 507 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) | 526 | if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) |
| 508 | goto RecEnd; | 527 | goto record_end; |
| 509 | if (de->attr != ATTR_EXT && IS_FREE(de->name)) | 528 | if (de->attr != ATTR_EXT && IS_FREE(de->name)) |
| 510 | goto RecEnd; | 529 | goto record_end; |
| 511 | } else { | 530 | } else { |
| 512 | if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) | 531 | if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) |
| 513 | goto RecEnd; | 532 | goto record_end; |
| 514 | } | 533 | } |
| 515 | 534 | ||
| 516 | if (isvfat && de->attr == ATTR_EXT) { | 535 | if (isvfat && de->attr == ATTR_EXT) { |
| 517 | int status = fat_parse_long(inode, &cpos, &bh, &de, | 536 | int status = fat_parse_long(inode, &cpos, &bh, &de, |
| 518 | &unicode, &long_slots); | 537 | &unicode, &nr_slots); |
| 519 | if (status < 0) { | 538 | if (status < 0) { |
| 520 | filp->f_pos = cpos; | 539 | filp->f_pos = cpos; |
| 521 | ret = status; | 540 | ret = status; |
| 522 | goto out; | 541 | goto out; |
| 523 | } else if (status == PARSE_INVALID) | 542 | } else if (status == PARSE_INVALID) |
| 524 | goto RecEnd; | 543 | goto record_end; |
| 525 | else if (status == PARSE_NOT_LONGNAME) | 544 | else if (status == PARSE_NOT_LONGNAME) |
| 526 | goto parse_record; | 545 | goto parse_record; |
| 527 | else if (status == PARSE_EOF) | 546 | else if (status == PARSE_EOF) |
| 528 | goto EODir; | 547 | goto end_of_dir; |
| 548 | |||
| 549 | if (nr_slots) { | ||
| 550 | void *longname = unicode + FAT_MAX_UNI_CHARS; | ||
| 551 | int size = PATH_MAX - FAT_MAX_UNI_SIZE; | ||
| 552 | int len = fat_uni_to_x8(sbi, unicode, longname, size); | ||
| 553 | |||
| 554 | fill_name = longname; | ||
| 555 | fill_len = len; | ||
| 556 | /* !both && !short_only, so we don't need shortname. */ | ||
| 557 | if (!both) | ||
| 558 | goto start_filldir; | ||
| 559 | } | ||
| 529 | } | 560 | } |
| 530 | 561 | ||
| 531 | if (sbi->options.dotsOK) { | 562 | if (sbi->options.dotsOK) { |
| @@ -587,12 +618,32 @@ parse_record: | |||
| 587 | } | 618 | } |
| 588 | } | 619 | } |
| 589 | if (!last) | 620 | if (!last) |
| 590 | goto RecEnd; | 621 | goto record_end; |
| 591 | 622 | ||
| 592 | i = last + dotoffset; | 623 | i = last + dotoffset; |
| 593 | j = last_u; | 624 | j = last_u; |
| 594 | 625 | ||
| 595 | lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry); | 626 | if (isvfat) { |
| 627 | bufuname[j] = 0x0000; | ||
| 628 | i = fat_uni_to_x8(sbi, bufuname, bufname, sizeof(bufname)); | ||
| 629 | } | ||
| 630 | if (nr_slots) { | ||
| 631 | /* hack for fat_ioctl_filldir() */ | ||
| 632 | struct fat_ioctl_filldir_callback *p = dirent; | ||
| 633 | |||
| 634 | p->longname = fill_name; | ||
| 635 | p->long_len = fill_len; | ||
| 636 | p->shortname = bufname; | ||
| 637 | p->short_len = i; | ||
| 638 | fill_name = NULL; | ||
| 639 | fill_len = 0; | ||
| 640 | } else { | ||
| 641 | fill_name = bufname; | ||
| 642 | fill_len = i; | ||
| 643 | } | ||
| 644 | |||
| 645 | start_filldir: | ||
| 646 | lpos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry); | ||
| 596 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) | 647 | if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) |
| 597 | inum = inode->i_ino; | 648 | inum = inode->i_ino; |
| 598 | else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { | 649 | else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { |
| @@ -607,49 +658,17 @@ parse_record: | |||
| 607 | inum = iunique(sb, MSDOS_ROOT_INO); | 658 | inum = iunique(sb, MSDOS_ROOT_INO); |
| 608 | } | 659 | } |
| 609 | 660 | ||
| 610 | if (isvfat) { | ||
| 611 | bufuname[j] = 0x0000; | ||
| 612 | i = utf8 ? utf8_wcstombs(bufname, bufuname, sizeof(bufname)) | ||
| 613 | : uni16_to_x8(bufname, bufuname, sizeof(bufname), uni_xlate, nls_io); | ||
| 614 | } | ||
| 615 | |||
| 616 | fill_name = bufname; | ||
| 617 | fill_len = i; | ||
| 618 | if (!short_only && long_slots) { | ||
| 619 | /* convert the unicode long name. 261 is maximum size | ||
| 620 | * of unicode buffer. (13 * slots + nul) */ | ||
| 621 | void *longname = unicode + 261; | ||
| 622 | int buf_size = PATH_MAX - (261 * sizeof(unicode[0])); | ||
| 623 | int long_len = utf8 | ||
| 624 | ? utf8_wcstombs(longname, unicode, buf_size) | ||
| 625 | : uni16_to_x8(longname, unicode, buf_size, uni_xlate, nls_io); | ||
| 626 | |||
| 627 | if (!both) { | ||
| 628 | fill_name = longname; | ||
| 629 | fill_len = long_len; | ||
| 630 | } else { | ||
| 631 | /* hack for fat_ioctl_filldir() */ | ||
| 632 | struct fat_ioctl_filldir_callback *p = dirent; | ||
| 633 | |||
| 634 | p->longname = longname; | ||
| 635 | p->long_len = long_len; | ||
| 636 | p->shortname = bufname; | ||
| 637 | p->short_len = i; | ||
| 638 | fill_name = NULL; | ||
| 639 | fill_len = 0; | ||
| 640 | } | ||
| 641 | } | ||
| 642 | if (filldir(dirent, fill_name, fill_len, *furrfu, inum, | 661 | if (filldir(dirent, fill_name, fill_len, *furrfu, inum, |
| 643 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) | 662 | (de->attr & ATTR_DIR) ? DT_DIR : DT_REG) < 0) |
| 644 | goto FillFailed; | 663 | goto fill_failed; |
| 645 | 664 | ||
| 646 | RecEnd: | 665 | record_end: |
| 647 | furrfu = &lpos; | 666 | furrfu = &lpos; |
| 648 | filp->f_pos = cpos; | 667 | filp->f_pos = cpos; |
| 649 | goto GetNew; | 668 | goto get_new; |
| 650 | EODir: | 669 | end_of_dir: |
| 651 | filp->f_pos = cpos; | 670 | filp->f_pos = cpos; |
| 652 | FillFailed: | 671 | fill_failed: |
| 653 | brelse(bh); | 672 | brelse(bh); |
| 654 | if (unicode) | 673 | if (unicode) |
| 655 | __putname(unicode); | 674 | __putname(unicode); |
| @@ -715,7 +734,7 @@ efault: \ | |||
| 715 | return -EFAULT; \ | 734 | return -EFAULT; \ |
| 716 | } | 735 | } |
| 717 | 736 | ||
| 718 | FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, dirent) | 737 | FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent) |
| 719 | 738 | ||
| 720 | static int fat_ioctl_readdir(struct inode *inode, struct file *filp, | 739 | static int fat_ioctl_readdir(struct inode *inode, struct file *filp, |
| 721 | void __user *dirent, filldir_t filldir, | 740 | void __user *dirent, filldir_t filldir, |
| @@ -741,7 +760,7 @@ static int fat_ioctl_readdir(struct inode *inode, struct file *filp, | |||
| 741 | static int fat_dir_ioctl(struct inode *inode, struct file *filp, | 760 | static int fat_dir_ioctl(struct inode *inode, struct file *filp, |
| 742 | unsigned int cmd, unsigned long arg) | 761 | unsigned int cmd, unsigned long arg) |
| 743 | { | 762 | { |
| 744 | struct dirent __user *d1 = (struct dirent __user *)arg; | 763 | struct __fat_dirent __user *d1 = (struct __fat_dirent __user *)arg; |
| 745 | int short_only, both; | 764 | int short_only, both; |
| 746 | 765 | ||
| 747 | switch (cmd) { | 766 | switch (cmd) { |
| @@ -757,7 +776,7 @@ static int fat_dir_ioctl(struct inode *inode, struct file *filp, | |||
| 757 | return fat_generic_ioctl(inode, filp, cmd, arg); | 776 | return fat_generic_ioctl(inode, filp, cmd, arg); |
| 758 | } | 777 | } |
| 759 | 778 | ||
| 760 | if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2]))) | 779 | if (!access_ok(VERIFY_WRITE, d1, sizeof(struct __fat_dirent[2]))) |
| 761 | return -EFAULT; | 780 | return -EFAULT; |
| 762 | /* | 781 | /* |
| 763 | * Yes, we don't need this put_user() absolutely. However old | 782 | * Yes, we don't need this put_user() absolutely. However old |
| @@ -1082,7 +1101,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | |||
| 1082 | goto error_free; | 1101 | goto error_free; |
| 1083 | } | 1102 | } |
| 1084 | 1103 | ||
| 1085 | fat_date_unix2dos(ts->tv_sec, &time, &date); | 1104 | fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); |
| 1086 | 1105 | ||
| 1087 | de = (struct msdos_dir_entry *)bhs[0]->b_data; | 1106 | de = (struct msdos_dir_entry *)bhs[0]->b_data; |
| 1088 | /* filling the new directory slots ("." and ".." entries) */ | 1107 | /* filling the new directory slots ("." and ".." entries) */ |
diff --git a/fs/fat/file.c b/fs/fat/file.c index c672df4036e9..ddde37025ca6 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | #include <linux/writeback.h> | 15 | #include <linux/writeback.h> |
| 16 | #include <linux/backing-dev.h> | 16 | #include <linux/backing-dev.h> |
| 17 | #include <linux/blkdev.h> | 17 | #include <linux/blkdev.h> |
| 18 | #include <linux/fsnotify.h> | ||
| 19 | #include <linux/security.h> | ||
| 18 | 20 | ||
| 19 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 21 | int fat_generic_ioctl(struct inode *inode, struct file *filp, |
| 20 | unsigned int cmd, unsigned long arg) | 22 | unsigned int cmd, unsigned long arg) |
| @@ -64,6 +66,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
| 64 | 66 | ||
| 65 | /* Equivalent to a chmod() */ | 67 | /* Equivalent to a chmod() */ |
| 66 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | 68 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; |
| 69 | ia.ia_ctime = current_fs_time(inode->i_sb); | ||
| 67 | if (is_dir) { | 70 | if (is_dir) { |
| 68 | ia.ia_mode = MSDOS_MKMODE(attr, | 71 | ia.ia_mode = MSDOS_MKMODE(attr, |
| 69 | S_IRWXUGO & ~sbi->options.fs_dmask) | 72 | S_IRWXUGO & ~sbi->options.fs_dmask) |
| @@ -90,11 +93,21 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
| 90 | } | 93 | } |
| 91 | } | 94 | } |
| 92 | 95 | ||
| 96 | /* | ||
| 97 | * The security check is questionable... We single | ||
| 98 | * out the RO attribute for checking by the security | ||
| 99 | * module, just because it maps to a file mode. | ||
| 100 | */ | ||
| 101 | err = security_inode_setattr(filp->f_path.dentry, &ia); | ||
| 102 | if (err) | ||
| 103 | goto up; | ||
| 104 | |||
| 93 | /* This MUST be done before doing anything irreversible... */ | 105 | /* This MUST be done before doing anything irreversible... */ |
| 94 | err = notify_change(filp->f_path.dentry, &ia); | 106 | err = fat_setattr(filp->f_path.dentry, &ia); |
| 95 | if (err) | 107 | if (err) |
| 96 | goto up; | 108 | goto up; |
| 97 | 109 | ||
| 110 | fsnotify_change(filp->f_path.dentry, ia.ia_valid); | ||
| 98 | if (sbi->options.sys_immutable) { | 111 | if (sbi->options.sys_immutable) { |
| 99 | if (attr & ATTR_SYS) | 112 | if (attr & ATTR_SYS) |
| 100 | inode->i_flags |= S_IMMUTABLE; | 113 | inode->i_flags |= S_IMMUTABLE; |
| @@ -300,6 +313,8 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | |||
| 300 | return 0; | 313 | return 0; |
| 301 | } | 314 | } |
| 302 | 315 | ||
| 316 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) | ||
| 317 | |||
| 303 | int fat_setattr(struct dentry *dentry, struct iattr *attr) | 318 | int fat_setattr(struct dentry *dentry, struct iattr *attr) |
| 304 | { | 319 | { |
| 305 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 320 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
| @@ -323,9 +338,9 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 323 | 338 | ||
| 324 | /* Check for setting the inode time. */ | 339 | /* Check for setting the inode time. */ |
| 325 | ia_valid = attr->ia_valid; | 340 | ia_valid = attr->ia_valid; |
| 326 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { | 341 | if (ia_valid & TIMES_SET_FLAGS) { |
| 327 | if (fat_allow_set_time(sbi, inode)) | 342 | if (fat_allow_set_time(sbi, inode)) |
| 328 | attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET); | 343 | attr->ia_valid &= ~TIMES_SET_FLAGS; |
| 329 | } | 344 | } |
| 330 | 345 | ||
| 331 | error = inode_change_ok(inode, attr); | 346 | error = inode_change_ok(inode, attr); |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 46a4508ffd2e..80ff3381fa21 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
| @@ -382,17 +382,20 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
| 382 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | 382 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) |
| 383 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | 383 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; |
| 384 | inode->i_mtime.tv_sec = | 384 | inode->i_mtime.tv_sec = |
| 385 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); | 385 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date), |
| 386 | sbi->options.tz_utc); | ||
| 386 | inode->i_mtime.tv_nsec = 0; | 387 | inode->i_mtime.tv_nsec = 0; |
| 387 | if (sbi->options.isvfat) { | 388 | if (sbi->options.isvfat) { |
| 388 | int secs = de->ctime_cs / 100; | 389 | int secs = de->ctime_cs / 100; |
| 389 | int csecs = de->ctime_cs % 100; | 390 | int csecs = de->ctime_cs % 100; |
| 390 | inode->i_ctime.tv_sec = | 391 | inode->i_ctime.tv_sec = |
| 391 | date_dos2unix(le16_to_cpu(de->ctime), | 392 | date_dos2unix(le16_to_cpu(de->ctime), |
| 392 | le16_to_cpu(de->cdate)) + secs; | 393 | le16_to_cpu(de->cdate), |
| 394 | sbi->options.tz_utc) + secs; | ||
| 393 | inode->i_ctime.tv_nsec = csecs * 10000000; | 395 | inode->i_ctime.tv_nsec = csecs * 10000000; |
| 394 | inode->i_atime.tv_sec = | 396 | inode->i_atime.tv_sec = |
| 395 | date_dos2unix(0, le16_to_cpu(de->adate)); | 397 | date_dos2unix(0, le16_to_cpu(de->adate), |
| 398 | sbi->options.tz_utc); | ||
| 396 | inode->i_atime.tv_nsec = 0; | 399 | inode->i_atime.tv_nsec = 0; |
| 397 | } else | 400 | } else |
| 398 | inode->i_ctime = inode->i_atime = inode->i_mtime; | 401 | inode->i_ctime = inode->i_atime = inode->i_mtime; |
| @@ -495,7 +498,7 @@ static void fat_destroy_inode(struct inode *inode) | |||
| 495 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); | 498 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); |
| 496 | } | 499 | } |
| 497 | 500 | ||
| 498 | static void init_once(struct kmem_cache *cachep, void *foo) | 501 | static void init_once(void *foo) |
| 499 | { | 502 | { |
| 500 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; | 503 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; |
| 501 | 504 | ||
| @@ -559,26 +562,23 @@ static int fat_write_inode(struct inode *inode, int wait) | |||
| 559 | struct buffer_head *bh; | 562 | struct buffer_head *bh; |
| 560 | struct msdos_dir_entry *raw_entry; | 563 | struct msdos_dir_entry *raw_entry; |
| 561 | loff_t i_pos; | 564 | loff_t i_pos; |
| 562 | int err = 0; | 565 | int err; |
| 563 | 566 | ||
| 564 | retry: | 567 | retry: |
| 565 | i_pos = MSDOS_I(inode)->i_pos; | 568 | i_pos = MSDOS_I(inode)->i_pos; |
| 566 | if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) | 569 | if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) |
| 567 | return 0; | 570 | return 0; |
| 568 | 571 | ||
| 569 | lock_super(sb); | ||
| 570 | bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); | 572 | bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); |
| 571 | if (!bh) { | 573 | if (!bh) { |
| 572 | printk(KERN_ERR "FAT: unable to read inode block " | 574 | printk(KERN_ERR "FAT: unable to read inode block " |
| 573 | "for updating (i_pos %lld)\n", i_pos); | 575 | "for updating (i_pos %lld)\n", i_pos); |
| 574 | err = -EIO; | 576 | return -EIO; |
| 575 | goto out; | ||
| 576 | } | 577 | } |
| 577 | spin_lock(&sbi->inode_hash_lock); | 578 | spin_lock(&sbi->inode_hash_lock); |
| 578 | if (i_pos != MSDOS_I(inode)->i_pos) { | 579 | if (i_pos != MSDOS_I(inode)->i_pos) { |
| 579 | spin_unlock(&sbi->inode_hash_lock); | 580 | spin_unlock(&sbi->inode_hash_lock); |
| 580 | brelse(bh); | 581 | brelse(bh); |
| 581 | unlock_super(sb); | ||
| 582 | goto retry; | 582 | goto retry; |
| 583 | } | 583 | } |
| 584 | 584 | ||
| @@ -591,21 +591,23 @@ retry: | |||
| 591 | raw_entry->attr = fat_attr(inode); | 591 | raw_entry->attr = fat_attr(inode); |
| 592 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); | 592 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); |
| 593 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); | 593 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); |
| 594 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); | 594 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, |
| 595 | &raw_entry->date, sbi->options.tz_utc); | ||
| 595 | if (sbi->options.isvfat) { | 596 | if (sbi->options.isvfat) { |
| 596 | __le16 atime; | 597 | __le16 atime; |
| 597 | fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); | 598 | fat_date_unix2dos(inode->i_ctime.tv_sec, &raw_entry->ctime, |
| 598 | fat_date_unix2dos(inode->i_atime.tv_sec,&atime,&raw_entry->adate); | 599 | &raw_entry->cdate, sbi->options.tz_utc); |
| 600 | fat_date_unix2dos(inode->i_atime.tv_sec, &atime, | ||
| 601 | &raw_entry->adate, sbi->options.tz_utc); | ||
| 599 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + | 602 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + |
| 600 | inode->i_ctime.tv_nsec / 10000000; | 603 | inode->i_ctime.tv_nsec / 10000000; |
| 601 | } | 604 | } |
| 602 | spin_unlock(&sbi->inode_hash_lock); | 605 | spin_unlock(&sbi->inode_hash_lock); |
| 603 | mark_buffer_dirty(bh); | 606 | mark_buffer_dirty(bh); |
| 607 | err = 0; | ||
| 604 | if (wait) | 608 | if (wait) |
| 605 | err = sync_dirty_buffer(bh); | 609 | err = sync_dirty_buffer(bh); |
| 606 | brelse(bh); | 610 | brelse(bh); |
| 607 | out: | ||
| 608 | unlock_super(sb); | ||
| 609 | return err; | 611 | return err; |
| 610 | } | 612 | } |
| 611 | 613 | ||
| @@ -836,6 +838,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 836 | } | 838 | } |
| 837 | if (sbi->options.flush) | 839 | if (sbi->options.flush) |
| 838 | seq_puts(m, ",flush"); | 840 | seq_puts(m, ",flush"); |
| 841 | if (opts->tz_utc) | ||
| 842 | seq_puts(m, ",tz=UTC"); | ||
| 839 | 843 | ||
| 840 | return 0; | 844 | return 0; |
| 841 | } | 845 | } |
| @@ -848,7 +852,7 @@ enum { | |||
| 848 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 852 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
| 849 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 853 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
| 850 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 854 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
| 851 | Opt_obsolate, Opt_flush, Opt_err, | 855 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err, |
| 852 | }; | 856 | }; |
| 853 | 857 | ||
| 854 | static match_table_t fat_tokens = { | 858 | static match_table_t fat_tokens = { |
| @@ -883,6 +887,7 @@ static match_table_t fat_tokens = { | |||
| 883 | {Opt_obsolate, "cvf_options=%100s"}, | 887 | {Opt_obsolate, "cvf_options=%100s"}, |
| 884 | {Opt_obsolate, "posix"}, | 888 | {Opt_obsolate, "posix"}, |
| 885 | {Opt_flush, "flush"}, | 889 | {Opt_flush, "flush"}, |
| 890 | {Opt_tz_utc, "tz=UTC"}, | ||
| 886 | {Opt_err, NULL}, | 891 | {Opt_err, NULL}, |
| 887 | }; | 892 | }; |
| 888 | static match_table_t msdos_tokens = { | 893 | static match_table_t msdos_tokens = { |
| @@ -947,10 +952,11 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
| 947 | opts->utf8 = opts->unicode_xlate = 0; | 952 | opts->utf8 = opts->unicode_xlate = 0; |
| 948 | opts->numtail = 1; | 953 | opts->numtail = 1; |
| 949 | opts->usefree = opts->nocase = 0; | 954 | opts->usefree = opts->nocase = 0; |
| 955 | opts->tz_utc = 0; | ||
| 950 | *debug = 0; | 956 | *debug = 0; |
| 951 | 957 | ||
| 952 | if (!options) | 958 | if (!options) |
| 953 | return 0; | 959 | goto out; |
| 954 | 960 | ||
| 955 | while ((p = strsep(&options, ",")) != NULL) { | 961 | while ((p = strsep(&options, ",")) != NULL) { |
| 956 | int token; | 962 | int token; |
| @@ -1036,6 +1042,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
| 1036 | case Opt_flush: | 1042 | case Opt_flush: |
| 1037 | opts->flush = 1; | 1043 | opts->flush = 1; |
| 1038 | break; | 1044 | break; |
| 1045 | case Opt_tz_utc: | ||
| 1046 | opts->tz_utc = 1; | ||
| 1047 | break; | ||
| 1039 | 1048 | ||
| 1040 | /* msdos specific */ | 1049 | /* msdos specific */ |
| 1041 | case Opt_dots: | 1050 | case Opt_dots: |
| @@ -1104,10 +1113,13 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
| 1104 | return -EINVAL; | 1113 | return -EINVAL; |
| 1105 | } | 1114 | } |
| 1106 | } | 1115 | } |
| 1116 | |||
| 1117 | out: | ||
| 1107 | /* UTF-8 doesn't provide FAT semantics */ | 1118 | /* UTF-8 doesn't provide FAT semantics */ |
| 1108 | if (!strcmp(opts->iocharset, "utf8")) { | 1119 | if (!strcmp(opts->iocharset, "utf8")) { |
| 1109 | printk(KERN_ERR "FAT: utf8 is not a recommended IO charset" | 1120 | printk(KERN_ERR "FAT: utf8 is not a recommended IO charset" |
| 1110 | " for FAT filesystems, filesystem will be case sensitive!\n"); | 1121 | " for FAT filesystems, filesystem will be " |
| 1122 | "case sensitive!\n"); | ||
| 1111 | } | 1123 | } |
| 1112 | 1124 | ||
| 1113 | /* If user doesn't specify allow_utime, it's initialized from dmask. */ | 1125 | /* If user doesn't specify allow_utime, it's initialized from dmask. */ |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 61f23511eacf..79fb98ad36d4 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
| @@ -142,7 +142,7 @@ static int day_n[] = { | |||
| 142 | }; | 142 | }; |
| 143 | 143 | ||
| 144 | /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ | 144 | /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ |
| 145 | int date_dos2unix(unsigned short time, unsigned short date) | 145 | int date_dos2unix(unsigned short time, unsigned short date, int tz_utc) |
| 146 | { | 146 | { |
| 147 | int month, year, secs; | 147 | int month, year, secs; |
| 148 | 148 | ||
| @@ -156,16 +156,18 @@ int date_dos2unix(unsigned short time, unsigned short date) | |||
| 156 | ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && | 156 | ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && |
| 157 | month < 2 ? 1 : 0)+3653); | 157 | month < 2 ? 1 : 0)+3653); |
| 158 | /* days since 1.1.70 plus 80's leap day */ | 158 | /* days since 1.1.70 plus 80's leap day */ |
| 159 | secs += sys_tz.tz_minuteswest*60; | 159 | if (!tz_utc) |
| 160 | secs += sys_tz.tz_minuteswest*60; | ||
| 160 | return secs; | 161 | return secs; |
| 161 | } | 162 | } |
| 162 | 163 | ||
| 163 | /* Convert linear UNIX date to a MS-DOS time/date pair. */ | 164 | /* Convert linear UNIX date to a MS-DOS time/date pair. */ |
| 164 | void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date) | 165 | void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date, int tz_utc) |
| 165 | { | 166 | { |
| 166 | int day, year, nl_day, month; | 167 | int day, year, nl_day, month; |
| 167 | 168 | ||
| 168 | unix_date -= sys_tz.tz_minuteswest*60; | 169 | if (!tz_utc) |
| 170 | unix_date -= sys_tz.tz_minuteswest*60; | ||
| 169 | 171 | ||
| 170 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ | 172 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ |
| 171 | if (unix_date < 315532800) | 173 | if (unix_date < 315532800) |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 9679fcbdeaa0..ac4f7db9f134 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -49,82 +49,6 @@ static int get_close_on_exec(unsigned int fd) | |||
| 49 | return res; | 49 | return res; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /* | ||
| 53 | * locate_fd finds a free file descriptor in the open_fds fdset, | ||
| 54 | * expanding the fd arrays if necessary. Must be called with the | ||
| 55 | * file_lock held for write. | ||
| 56 | */ | ||
| 57 | |||
| 58 | static int locate_fd(unsigned int orig_start, int cloexec) | ||
| 59 | { | ||
| 60 | struct files_struct *files = current->files; | ||
| 61 | unsigned int newfd; | ||
| 62 | unsigned int start; | ||
| 63 | int error; | ||
| 64 | struct fdtable *fdt; | ||
| 65 | |||
| 66 | spin_lock(&files->file_lock); | ||
| 67 | |||
| 68 | error = -EINVAL; | ||
| 69 | if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | ||
| 70 | goto out; | ||
| 71 | |||
| 72 | repeat: | ||
| 73 | fdt = files_fdtable(files); | ||
| 74 | /* | ||
| 75 | * Someone might have closed fd's in the range | ||
| 76 | * orig_start..fdt->next_fd | ||
| 77 | */ | ||
| 78 | start = orig_start; | ||
| 79 | if (start < files->next_fd) | ||
| 80 | start = files->next_fd; | ||
| 81 | |||
| 82 | newfd = start; | ||
| 83 | if (start < fdt->max_fds) | ||
| 84 | newfd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
| 85 | fdt->max_fds, start); | ||
| 86 | |||
| 87 | error = -EMFILE; | ||
| 88 | if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | ||
| 89 | goto out; | ||
| 90 | |||
| 91 | error = expand_files(files, newfd); | ||
| 92 | if (error < 0) | ||
| 93 | goto out; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * If we needed to expand the fs array we | ||
| 97 | * might have blocked - try again. | ||
| 98 | */ | ||
| 99 | if (error) | ||
| 100 | goto repeat; | ||
| 101 | |||
| 102 | if (start <= files->next_fd) | ||
| 103 | files->next_fd = newfd + 1; | ||
| 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); | ||
| 110 | error = newfd; | ||
| 111 | |||
| 112 | out: | ||
| 113 | spin_unlock(&files->file_lock); | ||
| 114 | return error; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int dupfd(struct file *file, unsigned int start, int cloexec) | ||
| 118 | { | ||
| 119 | int fd = locate_fd(start, cloexec); | ||
| 120 | if (fd >= 0) | ||
| 121 | fd_install(fd, file); | ||
| 122 | else | ||
| 123 | fput(file); | ||
| 124 | |||
| 125 | return fd; | ||
| 126 | } | ||
| 127 | |||
| 128 | asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | 52 | asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) |
| 129 | { | 53 | { |
| 130 | int err = -EBADF; | 54 | int err = -EBADF; |
| @@ -135,35 +59,39 @@ asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | |||
| 135 | if ((flags & ~O_CLOEXEC) != 0) | 59 | if ((flags & ~O_CLOEXEC) != 0) |
| 136 | return -EINVAL; | 60 | return -EINVAL; |
| 137 | 61 | ||
| 138 | spin_lock(&files->file_lock); | 62 | if (unlikely(oldfd == newfd)) |
| 139 | if (!(file = fcheck(oldfd))) | 63 | return -EINVAL; |
| 140 | goto out_unlock; | ||
| 141 | err = newfd; | ||
| 142 | if (newfd == oldfd) | ||
| 143 | goto out_unlock; | ||
| 144 | err = -EBADF; | ||
| 145 | if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | ||
| 146 | goto out_unlock; | ||
| 147 | get_file(file); /* We are now finished with oldfd */ | ||
| 148 | 64 | ||
| 65 | spin_lock(&files->file_lock); | ||
| 149 | err = expand_files(files, newfd); | 66 | err = expand_files(files, newfd); |
| 150 | if (err < 0) | 67 | file = fcheck(oldfd); |
| 151 | goto out_fput; | 68 | if (unlikely(!file)) |
| 152 | 69 | goto Ebadf; | |
| 153 | /* To avoid races with open() and dup(), we will mark the fd as | 70 | if (unlikely(err < 0)) { |
| 154 | * in-use in the open-file bitmap throughout the entire dup2() | 71 | if (err == -EMFILE) |
| 155 | * process. This is quite safe: do_close() uses the fd array | 72 | goto Ebadf; |
| 156 | * entry, not the bitmap, to decide what work needs to be | 73 | goto out_unlock; |
| 157 | * done. --sct */ | 74 | } |
| 158 | /* Doesn't work. open() might be there first. --AV */ | 75 | /* |
| 159 | 76 | * We need to detect attempts to do dup2() over allocated but still | |
| 160 | /* Yes. It's a race. In user space. Nothing sane to do */ | 77 | * not finished descriptor. NB: OpenBSD avoids that at the price of |
| 78 | * extra work in their equivalent of fget() - they insert struct | ||
| 79 | * file immediately after grabbing descriptor, mark it larval if | ||
| 80 | * more work (e.g. actual opening) is needed and make sure that | ||
| 81 | * fget() treats larval files as absent. Potentially interesting, | ||
| 82 | * but while extra work in fget() is trivial, locking implications | ||
| 83 | * and amount of surgery on open()-related paths in VFS are not. | ||
| 84 | * FreeBSD fails with -EBADF in the same situation, NetBSD "solution" | ||
| 85 | * deadlocks in rather amusing ways, AFAICS. All of that is out of | ||
| 86 | * scope of POSIX or SUS, since neither considers shared descriptor | ||
| 87 | * tables and this condition does not arise without those. | ||
| 88 | */ | ||
| 161 | err = -EBUSY; | 89 | err = -EBUSY; |
| 162 | fdt = files_fdtable(files); | 90 | fdt = files_fdtable(files); |
| 163 | tofree = fdt->fd[newfd]; | 91 | tofree = fdt->fd[newfd]; |
| 164 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) | 92 | if (!tofree && FD_ISSET(newfd, fdt->open_fds)) |
| 165 | goto out_fput; | 93 | goto out_unlock; |
| 166 | 94 | get_file(file); | |
| 167 | rcu_assign_pointer(fdt->fd[newfd], file); | 95 | rcu_assign_pointer(fdt->fd[newfd], file); |
| 168 | FD_SET(newfd, fdt->open_fds); | 96 | FD_SET(newfd, fdt->open_fds); |
| 169 | if (flags & O_CLOEXEC) | 97 | if (flags & O_CLOEXEC) |
| @@ -174,31 +102,41 @@ asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags) | |||
| 174 | 102 | ||
| 175 | if (tofree) | 103 | if (tofree) |
| 176 | filp_close(tofree, files); | 104 | filp_close(tofree, files); |
| 177 | err = newfd; | ||
| 178 | out: | ||
| 179 | return err; | ||
| 180 | out_unlock: | ||
| 181 | spin_unlock(&files->file_lock); | ||
| 182 | goto out; | ||
| 183 | 105 | ||
| 184 | out_fput: | 106 | return newfd; |
| 107 | |||
| 108 | Ebadf: | ||
| 109 | err = -EBADF; | ||
| 110 | out_unlock: | ||
| 185 | spin_unlock(&files->file_lock); | 111 | spin_unlock(&files->file_lock); |
| 186 | fput(file); | 112 | return err; |
| 187 | goto out; | ||
| 188 | } | 113 | } |
| 189 | 114 | ||
| 190 | asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) | 115 | asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd) |
| 191 | { | 116 | { |
| 117 | if (unlikely(newfd == oldfd)) { /* corner case */ | ||
| 118 | struct files_struct *files = current->files; | ||
| 119 | rcu_read_lock(); | ||
| 120 | if (!fcheck_files(files, oldfd)) | ||
| 121 | oldfd = -EBADF; | ||
| 122 | rcu_read_unlock(); | ||
| 123 | return oldfd; | ||
| 124 | } | ||
| 192 | return sys_dup3(oldfd, newfd, 0); | 125 | return sys_dup3(oldfd, newfd, 0); |
| 193 | } | 126 | } |
| 194 | 127 | ||
| 195 | asmlinkage long sys_dup(unsigned int fildes) | 128 | asmlinkage long sys_dup(unsigned int fildes) |
| 196 | { | 129 | { |
| 197 | int ret = -EBADF; | 130 | int ret = -EBADF; |
| 198 | struct file * file = fget(fildes); | 131 | struct file *file = fget(fildes); |
| 199 | 132 | ||
| 200 | if (file) | 133 | if (file) { |
| 201 | ret = dupfd(file, 0, 0); | 134 | ret = get_unused_fd(); |
| 135 | if (ret >= 0) | ||
| 136 | fd_install(ret, file); | ||
| 137 | else | ||
| 138 | fput(file); | ||
| 139 | } | ||
| 202 | return ret; | 140 | return ret; |
| 203 | } | 141 | } |
| 204 | 142 | ||
| @@ -321,8 +259,13 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, | |||
| 321 | switch (cmd) { | 259 | switch (cmd) { |
| 322 | case F_DUPFD: | 260 | case F_DUPFD: |
| 323 | case F_DUPFD_CLOEXEC: | 261 | case F_DUPFD_CLOEXEC: |
| 324 | get_file(filp); | 262 | if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) |
| 325 | err = dupfd(filp, arg, cmd == F_DUPFD_CLOEXEC); | 263 | break; |
| 264 | err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0); | ||
| 265 | if (err >= 0) { | ||
| 266 | get_file(filp); | ||
| 267 | fd_install(err, filp); | ||
| 268 | } | ||
| 326 | break; | 269 | break; |
| 327 | case F_GETFD: | 270 | case F_GETFD: |
| 328 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; | 271 | err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; |
| @@ -57,7 +57,7 @@ static int fifo_open(struct inode *inode, struct file *filp) | |||
| 57 | * POSIX.1 says that O_NONBLOCK means return with the FIFO | 57 | * POSIX.1 says that O_NONBLOCK means return with the FIFO |
| 58 | * opened, even when there is no process writing the FIFO. | 58 | * opened, even when there is no process writing the FIFO. |
| 59 | */ | 59 | */ |
| 60 | filp->f_op = &read_fifo_fops; | 60 | filp->f_op = &read_pipefifo_fops; |
| 61 | pipe->r_counter++; | 61 | pipe->r_counter++; |
| 62 | if (pipe->readers++ == 0) | 62 | if (pipe->readers++ == 0) |
| 63 | wake_up_partner(inode); | 63 | wake_up_partner(inode); |
| @@ -86,7 +86,7 @@ static int fifo_open(struct inode *inode, struct file *filp) | |||
| 86 | if ((filp->f_flags & O_NONBLOCK) && !pipe->readers) | 86 | if ((filp->f_flags & O_NONBLOCK) && !pipe->readers) |
| 87 | goto err; | 87 | goto err; |
| 88 | 88 | ||
| 89 | filp->f_op = &write_fifo_fops; | 89 | filp->f_op = &write_pipefifo_fops; |
| 90 | pipe->w_counter++; | 90 | pipe->w_counter++; |
| 91 | if (!pipe->writers++) | 91 | if (!pipe->writers++) |
| 92 | wake_up_partner(inode); | 92 | wake_up_partner(inode); |
| @@ -105,7 +105,7 @@ static int fifo_open(struct inode *inode, struct file *filp) | |||
| 105 | * This implementation will NEVER block on a O_RDWR open, since | 105 | * This implementation will NEVER block on a O_RDWR open, since |
| 106 | * the process can at least talk to itself. | 106 | * the process can at least talk to itself. |
| 107 | */ | 107 | */ |
| 108 | filp->f_op = &rdwr_fifo_fops; | 108 | filp->f_op = &rdwr_pipefifo_fops; |
| 109 | 109 | ||
| 110 | pipe->readers++; | 110 | pipe->readers++; |
| 111 | pipe->writers++; | 111 | pipe->writers++; |
| @@ -151,5 +151,5 @@ err_nocleanup: | |||
| 151 | * depending on the access mode of the file... | 151 | * depending on the access mode of the file... |
| 152 | */ | 152 | */ |
| 153 | const struct file_operations def_fifo_fops = { | 153 | const struct file_operations def_fifo_fops = { |
| 154 | .open = fifo_open, /* will set read or write pipe_fops */ | 154 | .open = fifo_open, /* will set read_ or write_pipefifo_fops */ |
| 155 | }; | 155 | }; |
| @@ -6,6 +6,7 @@ | |||
| 6 | * Manage the dynamic fd arrays in the process files_struct. | 6 | * Manage the dynamic fd arrays in the process files_struct. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/module.h> | ||
| 9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
| 10 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
| 11 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| @@ -250,9 +251,18 @@ int expand_files(struct files_struct *files, int nr) | |||
| 250 | struct fdtable *fdt; | 251 | struct fdtable *fdt; |
| 251 | 252 | ||
| 252 | fdt = files_fdtable(files); | 253 | fdt = files_fdtable(files); |
| 254 | |||
| 255 | /* | ||
| 256 | * N.B. For clone tasks sharing a files structure, this test | ||
| 257 | * will limit the total number of files that can be opened. | ||
| 258 | */ | ||
| 259 | if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | ||
| 260 | return -EMFILE; | ||
| 261 | |||
| 253 | /* Do we need to expand? */ | 262 | /* Do we need to expand? */ |
| 254 | if (nr < fdt->max_fds) | 263 | if (nr < fdt->max_fds) |
| 255 | return 0; | 264 | return 0; |
| 265 | |||
| 256 | /* Can we expand? */ | 266 | /* Can we expand? */ |
| 257 | if (nr >= sysctl_nr_open) | 267 | if (nr >= sysctl_nr_open) |
| 258 | return -EMFILE; | 268 | return -EMFILE; |
| @@ -423,3 +433,63 @@ struct files_struct init_files = { | |||
| 423 | }, | 433 | }, |
| 424 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), | 434 | .file_lock = __SPIN_LOCK_UNLOCKED(init_task.file_lock), |
| 425 | }; | 435 | }; |
| 436 | |||
| 437 | /* | ||
| 438 | * allocate a file descriptor, mark it busy. | ||
| 439 | */ | ||
| 440 | int alloc_fd(unsigned start, unsigned flags) | ||
| 441 | { | ||
| 442 | struct files_struct *files = current->files; | ||
| 443 | unsigned int fd; | ||
| 444 | int error; | ||
| 445 | struct fdtable *fdt; | ||
| 446 | |||
| 447 | spin_lock(&files->file_lock); | ||
| 448 | repeat: | ||
| 449 | fdt = files_fdtable(files); | ||
| 450 | fd = start; | ||
| 451 | if (fd < files->next_fd) | ||
| 452 | fd = files->next_fd; | ||
| 453 | |||
| 454 | if (fd < fdt->max_fds) | ||
| 455 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, | ||
| 456 | fdt->max_fds, fd); | ||
| 457 | |||
| 458 | error = expand_files(files, fd); | ||
| 459 | if (error < 0) | ||
| 460 | goto out; | ||
| 461 | |||
| 462 | /* | ||
| 463 | * If we needed to expand the fs array we | ||
| 464 | * might have blocked - try again. | ||
| 465 | */ | ||
| 466 | if (error) | ||
| 467 | goto repeat; | ||
| 468 | |||
| 469 | if (start <= files->next_fd) | ||
| 470 | files->next_fd = fd + 1; | ||
| 471 | |||
| 472 | FD_SET(fd, fdt->open_fds); | ||
| 473 | if (flags & O_CLOEXEC) | ||
| 474 | FD_SET(fd, fdt->close_on_exec); | ||
| 475 | else | ||
| 476 | FD_CLR(fd, fdt->close_on_exec); | ||
| 477 | error = fd; | ||
| 478 | #if 1 | ||
| 479 | /* Sanity check */ | ||
| 480 | if (rcu_dereference(fdt->fd[fd]) != NULL) { | ||
| 481 | printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); | ||
| 482 | rcu_assign_pointer(fdt->fd[fd], NULL); | ||
| 483 | } | ||
| 484 | #endif | ||
| 485 | |||
| 486 | out: | ||
| 487 | spin_unlock(&files->file_lock); | ||
| 488 | return error; | ||
| 489 | } | ||
| 490 | |||
| 491 | int get_unused_fd(void) | ||
| 492 | { | ||
| 493 | return alloc_fd(0, 0); | ||
| 494 | } | ||
| 495 | EXPORT_SYMBOL(get_unused_fd); | ||
diff --git a/fs/file_table.c b/fs/file_table.c index 83084225b4c3..f45a4493f9e7 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
| @@ -120,7 +120,7 @@ struct file *get_empty_filp(void) | |||
| 120 | 120 | ||
| 121 | tsk = current; | 121 | tsk = current; |
| 122 | INIT_LIST_HEAD(&f->f_u.fu_list); | 122 | INIT_LIST_HEAD(&f->f_u.fu_list); |
| 123 | atomic_set(&f->f_count, 1); | 123 | atomic_long_set(&f->f_count, 1); |
| 124 | rwlock_init(&f->f_owner.lock); | 124 | rwlock_init(&f->f_owner.lock); |
| 125 | f->f_uid = tsk->fsuid; | 125 | f->f_uid = tsk->fsuid; |
| 126 | f->f_gid = tsk->fsgid; | 126 | f->f_gid = tsk->fsgid; |
| @@ -219,7 +219,7 @@ EXPORT_SYMBOL(init_file); | |||
| 219 | 219 | ||
| 220 | void fput(struct file *file) | 220 | void fput(struct file *file) |
| 221 | { | 221 | { |
| 222 | if (atomic_dec_and_test(&file->f_count)) | 222 | if (atomic_long_dec_and_test(&file->f_count)) |
| 223 | __fput(file); | 223 | __fput(file); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| @@ -294,7 +294,7 @@ struct file *fget(unsigned int fd) | |||
| 294 | rcu_read_lock(); | 294 | rcu_read_lock(); |
| 295 | file = fcheck_files(files, fd); | 295 | file = fcheck_files(files, fd); |
| 296 | if (file) { | 296 | if (file) { |
| 297 | if (!atomic_inc_not_zero(&file->f_count)) { | 297 | if (!atomic_long_inc_not_zero(&file->f_count)) { |
| 298 | /* File object ref couldn't be taken */ | 298 | /* File object ref couldn't be taken */ |
| 299 | rcu_read_unlock(); | 299 | rcu_read_unlock(); |
| 300 | return NULL; | 300 | return NULL; |
| @@ -326,7 +326,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed) | |||
| 326 | rcu_read_lock(); | 326 | rcu_read_lock(); |
| 327 | file = fcheck_files(files, fd); | 327 | file = fcheck_files(files, fd); |
| 328 | if (file) { | 328 | if (file) { |
| 329 | if (atomic_inc_not_zero(&file->f_count)) | 329 | if (atomic_long_inc_not_zero(&file->f_count)) |
| 330 | *fput_needed = 1; | 330 | *fput_needed = 1; |
| 331 | else | 331 | else |
| 332 | /* Didn't get the reference, someone's freed */ | 332 | /* Didn't get the reference, someone's freed */ |
| @@ -341,7 +341,7 @@ struct file *fget_light(unsigned int fd, int *fput_needed) | |||
| 341 | 341 | ||
| 342 | void put_filp(struct file *file) | 342 | void put_filp(struct file *file) |
| 343 | { | 343 | { |
| 344 | if (atomic_dec_and_test(&file->f_count)) { | 344 | if (atomic_long_dec_and_test(&file->f_count)) { |
| 345 | security_file_free(file); | 345 | security_file_free(file); |
| 346 | file_kill(file); | 346 | file_kill(file); |
| 347 | file_free(file); | 347 | file_free(file); |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 2060bf06b906..fd03330cadeb 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
| @@ -97,7 +97,7 @@ void fuse_invalidate_attr(struct inode *inode) | |||
| 97 | * timeout is unknown (unlink, rmdir, rename and in some cases | 97 | * timeout is unknown (unlink, rmdir, rename and in some cases |
| 98 | * lookup) | 98 | * lookup) |
| 99 | */ | 99 | */ |
| 100 | static void fuse_invalidate_entry_cache(struct dentry *entry) | 100 | void fuse_invalidate_entry_cache(struct dentry *entry) |
| 101 | { | 101 | { |
| 102 | fuse_dentry_settime(entry, 0); | 102 | fuse_dentry_settime(entry, 0); |
| 103 | } | 103 | } |
| @@ -112,18 +112,16 @@ static void fuse_invalidate_entry(struct dentry *entry) | |||
| 112 | fuse_invalidate_entry_cache(entry); | 112 | fuse_invalidate_entry_cache(entry); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | 115 | static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_req *req, |
| 116 | struct dentry *entry, | 116 | u64 nodeid, struct qstr *name, |
| 117 | struct fuse_entry_out *outarg) | 117 | struct fuse_entry_out *outarg) |
| 118 | { | 118 | { |
| 119 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
| 120 | |||
| 121 | memset(outarg, 0, sizeof(struct fuse_entry_out)); | 119 | memset(outarg, 0, sizeof(struct fuse_entry_out)); |
| 122 | req->in.h.opcode = FUSE_LOOKUP; | 120 | req->in.h.opcode = FUSE_LOOKUP; |
| 123 | req->in.h.nodeid = get_node_id(dir); | 121 | req->in.h.nodeid = nodeid; |
| 124 | req->in.numargs = 1; | 122 | req->in.numargs = 1; |
| 125 | req->in.args[0].size = entry->d_name.len + 1; | 123 | req->in.args[0].size = name->len + 1; |
| 126 | req->in.args[0].value = entry->d_name.name; | 124 | req->in.args[0].value = name->name; |
| 127 | req->out.numargs = 1; | 125 | req->out.numargs = 1; |
| 128 | if (fc->minor < 9) | 126 | if (fc->minor < 9) |
| 129 | req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; | 127 | req->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE; |
| @@ -189,7 +187,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
| 189 | attr_version = fuse_get_attr_version(fc); | 187 | attr_version = fuse_get_attr_version(fc); |
| 190 | 188 | ||
| 191 | parent = dget_parent(entry); | 189 | parent = dget_parent(entry); |
| 192 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); | 190 | fuse_lookup_init(fc, req, get_node_id(parent->d_inode), |
| 191 | &entry->d_name, &outarg); | ||
| 193 | request_send(fc, req); | 192 | request_send(fc, req); |
| 194 | dput(parent); | 193 | dput(parent); |
| 195 | err = req->out.h.error; | 194 | err = req->out.h.error; |
| @@ -225,7 +224,7 @@ static int invalid_nodeid(u64 nodeid) | |||
| 225 | return !nodeid || nodeid == FUSE_ROOT_ID; | 224 | return !nodeid || nodeid == FUSE_ROOT_ID; |
| 226 | } | 225 | } |
| 227 | 226 | ||
| 228 | static struct dentry_operations fuse_dentry_operations = { | 227 | struct dentry_operations fuse_dentry_operations = { |
| 229 | .d_revalidate = fuse_dentry_revalidate, | 228 | .d_revalidate = fuse_dentry_revalidate, |
| 230 | }; | 229 | }; |
| 231 | 230 | ||
| @@ -239,85 +238,127 @@ int fuse_valid_type(int m) | |||
| 239 | * Add a directory inode to a dentry, ensuring that no other dentry | 238 | * Add a directory inode to a dentry, ensuring that no other dentry |
| 240 | * refers to this inode. Called with fc->inst_mutex. | 239 | * refers to this inode. Called with fc->inst_mutex. |
| 241 | */ | 240 | */ |
| 242 | static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) | 241 | static struct dentry *fuse_d_add_directory(struct dentry *entry, |
| 242 | struct inode *inode) | ||
| 243 | { | 243 | { |
| 244 | struct dentry *alias = d_find_alias(inode); | 244 | struct dentry *alias = d_find_alias(inode); |
| 245 | if (alias) { | 245 | if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { |
| 246 | /* This tries to shrink the subtree below alias */ | 246 | /* This tries to shrink the subtree below alias */ |
| 247 | fuse_invalidate_entry(alias); | 247 | fuse_invalidate_entry(alias); |
| 248 | dput(alias); | 248 | dput(alias); |
| 249 | if (!list_empty(&inode->i_dentry)) | 249 | if (!list_empty(&inode->i_dentry)) |
| 250 | return -EBUSY; | 250 | return ERR_PTR(-EBUSY); |
| 251 | } else { | ||
| 252 | dput(alias); | ||
| 251 | } | 253 | } |
| 252 | d_add(entry, inode); | 254 | return d_splice_alias(inode, entry); |
| 253 | return 0; | ||
| 254 | } | 255 | } |
| 255 | 256 | ||
| 256 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 257 | int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, |
| 257 | struct nameidata *nd) | 258 | struct fuse_entry_out *outarg, struct inode **inode) |
| 258 | { | 259 | { |
| 259 | int err; | 260 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
| 260 | struct fuse_entry_out outarg; | ||
| 261 | struct inode *inode = NULL; | ||
| 262 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
| 263 | struct fuse_req *req; | 261 | struct fuse_req *req; |
| 264 | struct fuse_req *forget_req; | 262 | struct fuse_req *forget_req; |
| 265 | u64 attr_version; | 263 | u64 attr_version; |
| 264 | int err; | ||
| 266 | 265 | ||
| 267 | if (entry->d_name.len > FUSE_NAME_MAX) | 266 | *inode = NULL; |
| 268 | return ERR_PTR(-ENAMETOOLONG); | 267 | err = -ENAMETOOLONG; |
| 268 | if (name->len > FUSE_NAME_MAX) | ||
| 269 | goto out; | ||
| 269 | 270 | ||
| 270 | req = fuse_get_req(fc); | 271 | req = fuse_get_req(fc); |
| 272 | err = PTR_ERR(req); | ||
| 271 | if (IS_ERR(req)) | 273 | if (IS_ERR(req)) |
| 272 | return ERR_CAST(req); | 274 | goto out; |
| 273 | 275 | ||
| 274 | forget_req = fuse_get_req(fc); | 276 | forget_req = fuse_get_req(fc); |
| 277 | err = PTR_ERR(forget_req); | ||
| 275 | if (IS_ERR(forget_req)) { | 278 | if (IS_ERR(forget_req)) { |
| 276 | fuse_put_request(fc, req); | 279 | fuse_put_request(fc, req); |
| 277 | return ERR_CAST(forget_req); | 280 | goto out; |
| 278 | } | 281 | } |
| 279 | 282 | ||
| 280 | attr_version = fuse_get_attr_version(fc); | 283 | attr_version = fuse_get_attr_version(fc); |
| 281 | 284 | ||
| 282 | fuse_lookup_init(req, dir, entry, &outarg); | 285 | fuse_lookup_init(fc, req, nodeid, name, outarg); |
| 283 | request_send(fc, req); | 286 | request_send(fc, req); |
| 284 | err = req->out.h.error; | 287 | err = req->out.h.error; |
| 285 | fuse_put_request(fc, req); | 288 | fuse_put_request(fc, req); |
| 286 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ | 289 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ |
| 287 | if (!err && outarg.nodeid && | 290 | if (err || !outarg->nodeid) |
| 288 | (invalid_nodeid(outarg.nodeid) || | 291 | goto out_put_forget; |
| 289 | !fuse_valid_type(outarg.attr.mode))) | 292 | |
| 290 | err = -EIO; | 293 | err = -EIO; |
| 291 | if (!err && outarg.nodeid) { | 294 | if (!outarg->nodeid) |
| 292 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 295 | goto out_put_forget; |
| 293 | &outarg.attr, entry_attr_timeout(&outarg), | 296 | if (!fuse_valid_type(outarg->attr.mode)) |
| 294 | attr_version); | 297 | goto out_put_forget; |
| 295 | if (!inode) { | 298 | |
| 296 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); | 299 | *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, |
| 297 | return ERR_PTR(-ENOMEM); | 300 | &outarg->attr, entry_attr_timeout(outarg), |
| 298 | } | 301 | attr_version); |
| 302 | err = -ENOMEM; | ||
| 303 | if (!*inode) { | ||
| 304 | fuse_send_forget(fc, forget_req, outarg->nodeid, 1); | ||
| 305 | goto out; | ||
| 299 | } | 306 | } |
| 307 | err = 0; | ||
| 308 | |||
| 309 | out_put_forget: | ||
| 300 | fuse_put_request(fc, forget_req); | 310 | fuse_put_request(fc, forget_req); |
| 301 | if (err && err != -ENOENT) | 311 | out: |
| 302 | return ERR_PTR(err); | 312 | return err; |
| 313 | } | ||
| 314 | |||
| 315 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | ||
| 316 | struct nameidata *nd) | ||
| 317 | { | ||
| 318 | int err; | ||
| 319 | struct fuse_entry_out outarg; | ||
| 320 | struct inode *inode; | ||
| 321 | struct dentry *newent; | ||
| 322 | struct fuse_conn *fc = get_fuse_conn(dir); | ||
| 323 | bool outarg_valid = true; | ||
| 324 | |||
| 325 | err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, | ||
| 326 | &outarg, &inode); | ||
| 327 | if (err == -ENOENT) { | ||
| 328 | outarg_valid = false; | ||
| 329 | err = 0; | ||
| 330 | } | ||
| 331 | if (err) | ||
| 332 | goto out_err; | ||
| 333 | |||
| 334 | err = -EIO; | ||
| 335 | if (inode && get_node_id(inode) == FUSE_ROOT_ID) | ||
| 336 | goto out_iput; | ||
| 303 | 337 | ||
| 304 | if (inode && S_ISDIR(inode->i_mode)) { | 338 | if (inode && S_ISDIR(inode->i_mode)) { |
| 305 | mutex_lock(&fc->inst_mutex); | 339 | mutex_lock(&fc->inst_mutex); |
| 306 | err = fuse_d_add_directory(entry, inode); | 340 | newent = fuse_d_add_directory(entry, inode); |
| 307 | mutex_unlock(&fc->inst_mutex); | 341 | mutex_unlock(&fc->inst_mutex); |
| 308 | if (err) { | 342 | err = PTR_ERR(newent); |
| 309 | iput(inode); | 343 | if (IS_ERR(newent)) |
| 310 | return ERR_PTR(err); | 344 | goto out_iput; |
| 311 | } | 345 | } else { |
| 312 | } else | 346 | newent = d_splice_alias(inode, entry); |
| 313 | d_add(entry, inode); | 347 | } |
| 314 | 348 | ||
| 349 | entry = newent ? newent : entry; | ||
| 315 | entry->d_op = &fuse_dentry_operations; | 350 | entry->d_op = &fuse_dentry_operations; |
| 316 | if (!err) | 351 | if (outarg_valid) |
| 317 | fuse_change_entry_timeout(entry, &outarg); | 352 | fuse_change_entry_timeout(entry, &outarg); |
| 318 | else | 353 | else |
| 319 | fuse_invalidate_entry_cache(entry); | 354 | fuse_invalidate_entry_cache(entry); |
| 320 | return NULL; | 355 | |
| 356 | return newent; | ||
| 357 | |||
| 358 | out_iput: | ||
| 359 | iput(inode); | ||
| 360 | out_err: | ||
| 361 | return ERR_PTR(err); | ||
| 321 | } | 362 | } |
| 322 | 363 | ||
| 323 | /* | 364 | /* |
| @@ -857,7 +898,7 @@ static int fuse_access(struct inode *inode, int mask) | |||
| 857 | return PTR_ERR(req); | 898 | return PTR_ERR(req); |
| 858 | 899 | ||
| 859 | memset(&inarg, 0, sizeof(inarg)); | 900 | memset(&inarg, 0, sizeof(inarg)); |
| 860 | inarg.mask = mask; | 901 | inarg.mask = mask & (MAY_READ | MAY_WRITE | MAY_EXEC); |
| 861 | req->in.h.opcode = FUSE_ACCESS; | 902 | req->in.h.opcode = FUSE_ACCESS; |
| 862 | req->in.h.nodeid = get_node_id(inode); | 903 | req->in.h.nodeid = get_node_id(inode); |
| 863 | req->in.numargs = 1; | 904 | req->in.numargs = 1; |
| @@ -886,7 +927,7 @@ static int fuse_access(struct inode *inode, int mask) | |||
| 886 | * access request is sent. Execute permission is still checked | 927 | * access request is sent. Execute permission is still checked |
| 887 | * locally based on file mode. | 928 | * locally based on file mode. |
| 888 | */ | 929 | */ |
| 889 | static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | 930 | static int fuse_permission(struct inode *inode, int mask) |
| 890 | { | 931 | { |
| 891 | struct fuse_conn *fc = get_fuse_conn(inode); | 932 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 892 | bool refreshed = false; | 933 | bool refreshed = false; |
| @@ -921,7 +962,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 921 | exist. So if permissions are revoked this won't be | 962 | exist. So if permissions are revoked this won't be |
| 922 | noticed immediately, only after the attribute | 963 | noticed immediately, only after the attribute |
| 923 | timeout has expired */ | 964 | timeout has expired */ |
| 924 | } else if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR))) { | 965 | } else if (mask & MAY_ACCESS) { |
| 925 | err = fuse_access(inode, mask); | 966 | err = fuse_access(inode, mask); |
| 926 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { | 967 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { |
| 927 | if (!(inode->i_mode & S_IXUGO)) { | 968 | if (!(inode->i_mode & S_IXUGO)) { |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 8092f0d9fd1f..2bada6bbc317 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -893,7 +893,7 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 893 | if (count == 0) | 893 | if (count == 0) |
| 894 | goto out; | 894 | goto out; |
| 895 | 895 | ||
| 896 | err = remove_suid(file->f_path.dentry); | 896 | err = file_remove_suid(file); |
| 897 | if (err) | 897 | if (err) |
| 898 | goto out; | 898 | goto out; |
| 899 | 899 | ||
| @@ -1341,6 +1341,11 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock) | |||
| 1341 | pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0; | 1341 | pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0; |
| 1342 | int err; | 1342 | int err; |
| 1343 | 1343 | ||
| 1344 | if (fl->fl_lmops && fl->fl_lmops->fl_grant) { | ||
| 1345 | /* NLM needs asynchronous locks, which we don't support yet */ | ||
| 1346 | return -ENOLCK; | ||
| 1347 | } | ||
| 1348 | |||
| 1344 | /* Unlock on close is handled by the flush method */ | 1349 | /* Unlock on close is handled by the flush method */ |
| 1345 | if (fl->fl_flags & FL_CLOSE) | 1350 | if (fl->fl_flags & FL_CLOSE) |
| 1346 | return 0; | 1351 | return 0; |
| @@ -1365,7 +1370,9 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) | |||
| 1365 | struct fuse_conn *fc = get_fuse_conn(inode); | 1370 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 1366 | int err; | 1371 | int err; |
| 1367 | 1372 | ||
| 1368 | if (cmd == F_GETLK) { | 1373 | if (cmd == F_CANCELLK) { |
| 1374 | err = 0; | ||
| 1375 | } else if (cmd == F_GETLK) { | ||
| 1369 | if (fc->no_lock) { | 1376 | if (fc->no_lock) { |
| 1370 | posix_test_lock(file, fl); | 1377 | posix_test_lock(file, fl); |
| 1371 | err = 0; | 1378 | err = 0; |
| @@ -1373,7 +1380,7 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) | |||
| 1373 | err = fuse_getlk(file, fl); | 1380 | err = fuse_getlk(file, fl); |
| 1374 | } else { | 1381 | } else { |
| 1375 | if (fc->no_lock) | 1382 | if (fc->no_lock) |
| 1376 | err = posix_lock_file_wait(file, fl); | 1383 | err = posix_lock_file(file, fl, NULL); |
| 1377 | else | 1384 | else |
| 1378 | err = fuse_setlk(file, fl, 0); | 1385 | err = fuse_setlk(file, fl, 0); |
| 1379 | } | 1386 | } |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index bae948657c4f..3a876076bdd1 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -363,6 +363,9 @@ struct fuse_conn { | |||
| 363 | /** Do not send separate SETATTR request before open(O_TRUNC) */ | 363 | /** Do not send separate SETATTR request before open(O_TRUNC) */ |
| 364 | unsigned atomic_o_trunc : 1; | 364 | unsigned atomic_o_trunc : 1; |
| 365 | 365 | ||
| 366 | /** Filesystem supports NFS exporting. Only set in INIT */ | ||
| 367 | unsigned export_support : 1; | ||
| 368 | |||
| 366 | /* | 369 | /* |
| 367 | * The following bitfields are only for optimization purposes | 370 | * The following bitfields are only for optimization purposes |
| 368 | * and hence races in setting them will not cause malfunction | 371 | * and hence races in setting them will not cause malfunction |
| @@ -464,6 +467,8 @@ static inline u64 get_node_id(struct inode *inode) | |||
| 464 | /** Device operations */ | 467 | /** Device operations */ |
| 465 | extern const struct file_operations fuse_dev_operations; | 468 | extern const struct file_operations fuse_dev_operations; |
| 466 | 469 | ||
| 470 | extern struct dentry_operations fuse_dentry_operations; | ||
| 471 | |||
| 467 | /** | 472 | /** |
| 468 | * Get a filled in inode | 473 | * Get a filled in inode |
| 469 | */ | 474 | */ |
| @@ -471,6 +476,9 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
| 471 | int generation, struct fuse_attr *attr, | 476 | int generation, struct fuse_attr *attr, |
| 472 | u64 attr_valid, u64 attr_version); | 477 | u64 attr_valid, u64 attr_version); |
| 473 | 478 | ||
| 479 | int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | ||
| 480 | struct fuse_entry_out *outarg, struct inode **inode); | ||
| 481 | |||
| 474 | /** | 482 | /** |
| 475 | * Send FORGET command | 483 | * Send FORGET command |
| 476 | */ | 484 | */ |
| @@ -604,6 +612,8 @@ void fuse_abort_conn(struct fuse_conn *fc); | |||
| 604 | */ | 612 | */ |
| 605 | void fuse_invalidate_attr(struct inode *inode); | 613 | void fuse_invalidate_attr(struct inode *inode); |
| 606 | 614 | ||
| 615 | void fuse_invalidate_entry_cache(struct dentry *entry); | ||
| 616 | |||
| 607 | /** | 617 | /** |
| 608 | * Acquire reference to fuse_conn | 618 | * Acquire reference to fuse_conn |
| 609 | */ | 619 | */ |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 3141690558c8..d2249f174e20 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/statfs.h> | 18 | #include <linux/statfs.h> |
| 19 | #include <linux/random.h> | 19 | #include <linux/random.h> |
| 20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
| 21 | #include <linux/exportfs.h> | ||
| 21 | 22 | ||
| 22 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | 23 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); |
| 23 | MODULE_DESCRIPTION("Filesystem in Userspace"); | 24 | MODULE_DESCRIPTION("Filesystem in Userspace"); |
| @@ -552,6 +553,174 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | |||
| 552 | return fuse_iget(sb, 1, 0, &attr, 0, 0); | 553 | return fuse_iget(sb, 1, 0, &attr, 0, 0); |
| 553 | } | 554 | } |
| 554 | 555 | ||
| 556 | struct fuse_inode_handle | ||
| 557 | { | ||
| 558 | u64 nodeid; | ||
| 559 | u32 generation; | ||
| 560 | }; | ||
| 561 | |||
| 562 | static struct dentry *fuse_get_dentry(struct super_block *sb, | ||
| 563 | struct fuse_inode_handle *handle) | ||
| 564 | { | ||
| 565 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
| 566 | struct inode *inode; | ||
| 567 | struct dentry *entry; | ||
| 568 | int err = -ESTALE; | ||
| 569 | |||
| 570 | if (handle->nodeid == 0) | ||
| 571 | goto out_err; | ||
| 572 | |||
| 573 | inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); | ||
| 574 | if (!inode) { | ||
| 575 | struct fuse_entry_out outarg; | ||
| 576 | struct qstr name; | ||
| 577 | |||
| 578 | if (!fc->export_support) | ||
| 579 | goto out_err; | ||
| 580 | |||
| 581 | name.len = 1; | ||
| 582 | name.name = "."; | ||
| 583 | err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg, | ||
| 584 | &inode); | ||
| 585 | if (err && err != -ENOENT) | ||
| 586 | goto out_err; | ||
| 587 | if (err || !inode) { | ||
| 588 | err = -ESTALE; | ||
| 589 | goto out_err; | ||
| 590 | } | ||
| 591 | err = -EIO; | ||
| 592 | if (get_node_id(inode) != handle->nodeid) | ||
| 593 | goto out_iput; | ||
| 594 | } | ||
| 595 | err = -ESTALE; | ||
| 596 | if (inode->i_generation != handle->generation) | ||
| 597 | goto out_iput; | ||
| 598 | |||
| 599 | entry = d_alloc_anon(inode); | ||
| 600 | err = -ENOMEM; | ||
| 601 | if (!entry) | ||
| 602 | goto out_iput; | ||
| 603 | |||
| 604 | if (get_node_id(inode) != FUSE_ROOT_ID) { | ||
| 605 | entry->d_op = &fuse_dentry_operations; | ||
| 606 | fuse_invalidate_entry_cache(entry); | ||
| 607 | } | ||
| 608 | |||
| 609 | return entry; | ||
| 610 | |||
| 611 | out_iput: | ||
| 612 | iput(inode); | ||
| 613 | out_err: | ||
| 614 | return ERR_PTR(err); | ||
| 615 | } | ||
| 616 | |||
| 617 | static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, | ||
| 618 | int connectable) | ||
| 619 | { | ||
| 620 | struct inode *inode = dentry->d_inode; | ||
| 621 | bool encode_parent = connectable && !S_ISDIR(inode->i_mode); | ||
| 622 | int len = encode_parent ? 6 : 3; | ||
| 623 | u64 nodeid; | ||
| 624 | u32 generation; | ||
| 625 | |||
| 626 | if (*max_len < len) | ||
| 627 | return 255; | ||
| 628 | |||
| 629 | nodeid = get_fuse_inode(inode)->nodeid; | ||
| 630 | generation = inode->i_generation; | ||
| 631 | |||
| 632 | fh[0] = (u32)(nodeid >> 32); | ||
| 633 | fh[1] = (u32)(nodeid & 0xffffffff); | ||
| 634 | fh[2] = generation; | ||
| 635 | |||
| 636 | if (encode_parent) { | ||
| 637 | struct inode *parent; | ||
| 638 | |||
| 639 | spin_lock(&dentry->d_lock); | ||
| 640 | parent = dentry->d_parent->d_inode; | ||
| 641 | nodeid = get_fuse_inode(parent)->nodeid; | ||
| 642 | generation = parent->i_generation; | ||
| 643 | spin_unlock(&dentry->d_lock); | ||
| 644 | |||
| 645 | fh[3] = (u32)(nodeid >> 32); | ||
| 646 | fh[4] = (u32)(nodeid & 0xffffffff); | ||
| 647 | fh[5] = generation; | ||
| 648 | } | ||
| 649 | |||
| 650 | *max_len = len; | ||
| 651 | return encode_parent ? 0x82 : 0x81; | ||
| 652 | } | ||
| 653 | |||
| 654 | static struct dentry *fuse_fh_to_dentry(struct super_block *sb, | ||
| 655 | struct fid *fid, int fh_len, int fh_type) | ||
| 656 | { | ||
| 657 | struct fuse_inode_handle handle; | ||
| 658 | |||
| 659 | if ((fh_type != 0x81 && fh_type != 0x82) || fh_len < 3) | ||
| 660 | return NULL; | ||
| 661 | |||
| 662 | handle.nodeid = (u64) fid->raw[0] << 32; | ||
| 663 | handle.nodeid |= (u64) fid->raw[1]; | ||
| 664 | handle.generation = fid->raw[2]; | ||
| 665 | return fuse_get_dentry(sb, &handle); | ||
| 666 | } | ||
| 667 | |||
| 668 | static struct dentry *fuse_fh_to_parent(struct super_block *sb, | ||
| 669 | struct fid *fid, int fh_len, int fh_type) | ||
| 670 | { | ||
| 671 | struct fuse_inode_handle parent; | ||
| 672 | |||
| 673 | if (fh_type != 0x82 || fh_len < 6) | ||
| 674 | return NULL; | ||
| 675 | |||
| 676 | parent.nodeid = (u64) fid->raw[3] << 32; | ||
| 677 | parent.nodeid |= (u64) fid->raw[4]; | ||
| 678 | parent.generation = fid->raw[5]; | ||
| 679 | return fuse_get_dentry(sb, &parent); | ||
| 680 | } | ||
| 681 | |||
| 682 | static struct dentry *fuse_get_parent(struct dentry *child) | ||
| 683 | { | ||
| 684 | struct inode *child_inode = child->d_inode; | ||
| 685 | struct fuse_conn *fc = get_fuse_conn(child_inode); | ||
| 686 | struct inode *inode; | ||
| 687 | struct dentry *parent; | ||
| 688 | struct fuse_entry_out outarg; | ||
| 689 | struct qstr name; | ||
| 690 | int err; | ||
| 691 | |||
| 692 | if (!fc->export_support) | ||
| 693 | return ERR_PTR(-ESTALE); | ||
| 694 | |||
| 695 | name.len = 2; | ||
| 696 | name.name = ".."; | ||
| 697 | err = fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode), | ||
| 698 | &name, &outarg, &inode); | ||
| 699 | if (err && err != -ENOENT) | ||
| 700 | return ERR_PTR(err); | ||
| 701 | if (err || !inode) | ||
| 702 | return ERR_PTR(-ESTALE); | ||
| 703 | |||
| 704 | parent = d_alloc_anon(inode); | ||
| 705 | if (!parent) { | ||
| 706 | iput(inode); | ||
| 707 | return ERR_PTR(-ENOMEM); | ||
| 708 | } | ||
| 709 | if (get_node_id(inode) != FUSE_ROOT_ID) { | ||
| 710 | parent->d_op = &fuse_dentry_operations; | ||
| 711 | fuse_invalidate_entry_cache(parent); | ||
| 712 | } | ||
| 713 | |||
| 714 | return parent; | ||
| 715 | } | ||
| 716 | |||
| 717 | static const struct export_operations fuse_export_operations = { | ||
| 718 | .fh_to_dentry = fuse_fh_to_dentry, | ||
| 719 | .fh_to_parent = fuse_fh_to_parent, | ||
| 720 | .encode_fh = fuse_encode_fh, | ||
| 721 | .get_parent = fuse_get_parent, | ||
| 722 | }; | ||
| 723 | |||
| 555 | static const struct super_operations fuse_super_operations = { | 724 | static const struct super_operations fuse_super_operations = { |
| 556 | .alloc_inode = fuse_alloc_inode, | 725 | .alloc_inode = fuse_alloc_inode, |
| 557 | .destroy_inode = fuse_destroy_inode, | 726 | .destroy_inode = fuse_destroy_inode, |
| @@ -581,6 +750,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
| 581 | fc->no_lock = 1; | 750 | fc->no_lock = 1; |
| 582 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) | 751 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) |
| 583 | fc->atomic_o_trunc = 1; | 752 | fc->atomic_o_trunc = 1; |
| 753 | if (arg->minor >= 9) { | ||
| 754 | /* LOOKUP has dependency on proto version */ | ||
| 755 | if (arg->flags & FUSE_EXPORT_SUPPORT) | ||
| 756 | fc->export_support = 1; | ||
| 757 | } | ||
| 584 | if (arg->flags & FUSE_BIG_WRITES) | 758 | if (arg->flags & FUSE_BIG_WRITES) |
| 585 | fc->big_writes = 1; | 759 | fc->big_writes = 1; |
| 586 | } else { | 760 | } else { |
| @@ -607,7 +781,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
| 607 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 781 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
| 608 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 782 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
| 609 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | | 783 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | |
| 610 | FUSE_BIG_WRITES; | 784 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES; |
| 611 | req->in.h.opcode = FUSE_INIT; | 785 | req->in.h.opcode = FUSE_INIT; |
| 612 | req->in.numargs = 1; | 786 | req->in.numargs = 1; |
| 613 | req->in.args[0].size = sizeof(*arg); | 787 | req->in.args[0].size = sizeof(*arg); |
| @@ -652,6 +826,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
| 652 | sb->s_magic = FUSE_SUPER_MAGIC; | 826 | sb->s_magic = FUSE_SUPER_MAGIC; |
| 653 | sb->s_op = &fuse_super_operations; | 827 | sb->s_op = &fuse_super_operations; |
| 654 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 828 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
| 829 | sb->s_export_op = &fuse_export_operations; | ||
| 655 | 830 | ||
| 656 | file = fget(d.fd); | 831 | file = fget(d.fd); |
| 657 | if (!file) | 832 | if (!file) |
| @@ -781,7 +956,7 @@ static inline void unregister_fuseblk(void) | |||
| 781 | } | 956 | } |
| 782 | #endif | 957 | #endif |
| 783 | 958 | ||
| 784 | static void fuse_inode_init_once(struct kmem_cache *cachep, void *foo) | 959 | static void fuse_inode_init_once(void *foo) |
| 785 | { | 960 | { |
| 786 | struct inode * inode = foo; | 961 | struct inode * inode = foo; |
| 787 | 962 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 6da0ab355b8a..8b0806a32948 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
| @@ -448,7 +448,7 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) | |||
| 448 | struct qstr qstr; | 448 | struct qstr qstr; |
| 449 | struct inode *inode; | 449 | struct inode *inode; |
| 450 | gfs2_str2qstr(&qstr, name); | 450 | gfs2_str2qstr(&qstr, name); |
| 451 | inode = gfs2_lookupi(dip, &qstr, 1, NULL); | 451 | inode = gfs2_lookupi(dip, &qstr, 1); |
| 452 | /* gfs2_lookupi has inconsistent callers: vfs | 452 | /* gfs2_lookupi has inconsistent callers: vfs |
| 453 | * related routines expect NULL for no entry found, | 453 | * related routines expect NULL for no entry found, |
| 454 | * gfs2_lookup_simple callers expect ENOENT | 454 | * gfs2_lookup_simple callers expect ENOENT |
| @@ -477,7 +477,7 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name) | |||
| 477 | */ | 477 | */ |
| 478 | 478 | ||
| 479 | struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | 479 | struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, |
| 480 | int is_root, struct nameidata *nd) | 480 | int is_root) |
| 481 | { | 481 | { |
| 482 | struct super_block *sb = dir->i_sb; | 482 | struct super_block *sb = dir->i_sb; |
| 483 | struct gfs2_inode *dip = GFS2_I(dir); | 483 | struct gfs2_inode *dip = GFS2_I(dir); |
| @@ -1173,7 +1173,7 @@ int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to) | |||
| 1173 | break; | 1173 | break; |
| 1174 | } | 1174 | } |
| 1175 | 1175 | ||
| 1176 | tmp = gfs2_lookupi(dir, &dotdot, 1, NULL); | 1176 | tmp = gfs2_lookupi(dir, &dotdot, 1); |
| 1177 | if (IS_ERR(tmp)) { | 1177 | if (IS_ERR(tmp)) { |
| 1178 | error = PTR_ERR(tmp); | 1178 | error = PTR_ERR(tmp); |
| 1179 | break; | 1179 | break; |
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index 6074c2506f75..58f9607d6a86 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h | |||
| @@ -83,7 +83,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip); | |||
| 83 | int gfs2_dinode_dealloc(struct gfs2_inode *inode); | 83 | int gfs2_dinode_dealloc(struct gfs2_inode *inode); |
| 84 | int gfs2_change_nlink(struct gfs2_inode *ip, int diff); | 84 | int gfs2_change_nlink(struct gfs2_inode *ip, int diff); |
| 85 | struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | 85 | struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, |
| 86 | int is_root, struct nameidata *nd); | 86 | int is_root); |
| 87 | struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, | 87 | struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name, |
| 88 | unsigned int mode, dev_t dev); | 88 | unsigned int mode, dev_t dev); |
| 89 | int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, | 89 | int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name, |
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c index bcc668d0fadd..bb2cc303ac29 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c | |||
| @@ -24,7 +24,7 @@ | |||
| 24 | #include "util.h" | 24 | #include "util.h" |
| 25 | #include "glock.h" | 25 | #include "glock.h" |
| 26 | 26 | ||
| 27 | static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo) | 27 | static void gfs2_init_inode_once(void *foo) |
| 28 | { | 28 | { |
| 29 | struct gfs2_inode *ip = foo; | 29 | struct gfs2_inode *ip = foo; |
| 30 | 30 | ||
| @@ -33,7 +33,7 @@ static void gfs2_init_inode_once(struct kmem_cache *cachep, void *foo) | |||
| 33 | ip->i_alloc = NULL; | 33 | ip->i_alloc = NULL; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | static void gfs2_init_glock_once(struct kmem_cache *cachep, void *foo) | 36 | static void gfs2_init_glock_once(void *foo) |
| 37 | { | 37 | { |
| 38 | struct gfs2_glock *gl = foo; | 38 | struct gfs2_glock *gl = foo; |
| 39 | 39 | ||
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 990d9f4bc463..9cda8536530c 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c | |||
| @@ -134,7 +134,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child) | |||
| 134 | struct dentry *dentry; | 134 | struct dentry *dentry; |
| 135 | 135 | ||
| 136 | gfs2_str2qstr(&dotdot, ".."); | 136 | gfs2_str2qstr(&dotdot, ".."); |
| 137 | inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL); | 137 | inode = gfs2_lookupi(child->d_inode, &dotdot, 1); |
| 138 | 138 | ||
| 139 | if (!inode) | 139 | if (!inode) |
| 140 | return ERR_PTR(-ENOENT); | 140 | return ERR_PTR(-ENOENT); |
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 1e252dfc5294..e2c62f73a778 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
| @@ -74,7 +74,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry, | |||
| 74 | return PTR_ERR(inode); | 74 | return PTR_ERR(inode); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); | 77 | inode = gfs2_lookupi(dir, &dentry->d_name, 0); |
| 78 | if (inode) { | 78 | if (inode) { |
| 79 | if (!IS_ERR(inode)) { | 79 | if (!IS_ERR(inode)) { |
| 80 | gfs2_holder_uninit(ghs); | 80 | gfs2_holder_uninit(ghs); |
| @@ -109,7 +109,7 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, | |||
| 109 | 109 | ||
| 110 | dentry->d_op = &gfs2_dops; | 110 | dentry->d_op = &gfs2_dops; |
| 111 | 111 | ||
| 112 | inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd); | 112 | inode = gfs2_lookupi(dir, &dentry->d_name, 0); |
| 113 | if (inode && IS_ERR(inode)) | 113 | if (inode && IS_ERR(inode)) |
| 114 | return ERR_CAST(inode); | 114 | return ERR_CAST(inode); |
| 115 | 115 | ||
| @@ -915,12 +915,6 @@ int gfs2_permission(struct inode *inode, int mask) | |||
| 915 | return error; | 915 | return error; |
| 916 | } | 916 | } |
| 917 | 917 | ||
| 918 | static int gfs2_iop_permission(struct inode *inode, int mask, | ||
| 919 | struct nameidata *nd) | ||
| 920 | { | ||
| 921 | return gfs2_permission(inode, mask); | ||
| 922 | } | ||
| 923 | |||
| 924 | static int setattr_size(struct inode *inode, struct iattr *attr) | 918 | static int setattr_size(struct inode *inode, struct iattr *attr) |
| 925 | { | 919 | { |
| 926 | struct gfs2_inode *ip = GFS2_I(inode); | 920 | struct gfs2_inode *ip = GFS2_I(inode); |
| @@ -1150,7 +1144,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) | |||
| 1150 | } | 1144 | } |
| 1151 | 1145 | ||
| 1152 | const struct inode_operations gfs2_file_iops = { | 1146 | const struct inode_operations gfs2_file_iops = { |
| 1153 | .permission = gfs2_iop_permission, | 1147 | .permission = gfs2_permission, |
| 1154 | .setattr = gfs2_setattr, | 1148 | .setattr = gfs2_setattr, |
| 1155 | .getattr = gfs2_getattr, | 1149 | .getattr = gfs2_getattr, |
| 1156 | .setxattr = gfs2_setxattr, | 1150 | .setxattr = gfs2_setxattr, |
| @@ -1169,7 +1163,7 @@ const struct inode_operations gfs2_dir_iops = { | |||
| 1169 | .rmdir = gfs2_rmdir, | 1163 | .rmdir = gfs2_rmdir, |
| 1170 | .mknod = gfs2_mknod, | 1164 | .mknod = gfs2_mknod, |
| 1171 | .rename = gfs2_rename, | 1165 | .rename = gfs2_rename, |
| 1172 | .permission = gfs2_iop_permission, | 1166 | .permission = gfs2_permission, |
| 1173 | .setattr = gfs2_setattr, | 1167 | .setattr = gfs2_setattr, |
| 1174 | .getattr = gfs2_getattr, | 1168 | .getattr = gfs2_getattr, |
| 1175 | .setxattr = gfs2_setxattr, | 1169 | .setxattr = gfs2_setxattr, |
| @@ -1181,7 +1175,7 @@ const struct inode_operations gfs2_dir_iops = { | |||
| 1181 | const struct inode_operations gfs2_symlink_iops = { | 1175 | const struct inode_operations gfs2_symlink_iops = { |
| 1182 | .readlink = gfs2_readlink, | 1176 | .readlink = gfs2_readlink, |
| 1183 | .follow_link = gfs2_follow_link, | 1177 | .follow_link = gfs2_follow_link, |
| 1184 | .permission = gfs2_iop_permission, | 1178 | .permission = gfs2_permission, |
| 1185 | .setattr = gfs2_setattr, | 1179 | .setattr = gfs2_setattr, |
| 1186 | .getattr = gfs2_getattr, | 1180 | .getattr = gfs2_getattr, |
| 1187 | .setxattr = gfs2_setxattr, | 1181 | .setxattr = gfs2_setxattr, |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 63a8a902d9db..ca831991cbc2 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -389,7 +389,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh) | |||
| 389 | break; | 389 | break; |
| 390 | 390 | ||
| 391 | INIT_LIST_HEAD(&jd->extent_list); | 391 | INIT_LIST_HEAD(&jd->extent_list); |
| 392 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL); | 392 | jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1); |
| 393 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { | 393 | if (!jd->jd_inode || IS_ERR(jd->jd_inode)) { |
| 394 | if (!jd->jd_inode) | 394 | if (!jd->jd_inode) |
| 395 | error = -ENOENT; | 395 | error = -ENOENT; |
diff --git a/fs/hfs/bitmap.c b/fs/hfs/bitmap.c index 24e75798ddf0..c6e97366e8ac 100644 --- a/fs/hfs/bitmap.c +++ b/fs/hfs/bitmap.c | |||
| @@ -145,7 +145,7 @@ u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits) | |||
| 145 | if (!*num_bits) | 145 | if (!*num_bits) |
| 146 | return 0; | 146 | return 0; |
| 147 | 147 | ||
| 148 | down(&HFS_SB(sb)->bitmap_lock); | 148 | mutex_lock(&HFS_SB(sb)->bitmap_lock); |
| 149 | bitmap = HFS_SB(sb)->bitmap; | 149 | bitmap = HFS_SB(sb)->bitmap; |
| 150 | 150 | ||
| 151 | pos = hfs_find_set_zero_bits(bitmap, HFS_SB(sb)->fs_ablocks, goal, num_bits); | 151 | pos = hfs_find_set_zero_bits(bitmap, HFS_SB(sb)->fs_ablocks, goal, num_bits); |
| @@ -162,7 +162,7 @@ u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits) | |||
| 162 | HFS_SB(sb)->free_ablocks -= *num_bits; | 162 | HFS_SB(sb)->free_ablocks -= *num_bits; |
| 163 | hfs_bitmap_dirty(sb); | 163 | hfs_bitmap_dirty(sb); |
| 164 | out: | 164 | out: |
| 165 | up(&HFS_SB(sb)->bitmap_lock); | 165 | mutex_unlock(&HFS_SB(sb)->bitmap_lock); |
| 166 | return pos; | 166 | return pos; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| @@ -205,7 +205,7 @@ int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count) | |||
| 205 | if ((start + count) > HFS_SB(sb)->fs_ablocks) | 205 | if ((start + count) > HFS_SB(sb)->fs_ablocks) |
| 206 | return -2; | 206 | return -2; |
| 207 | 207 | ||
| 208 | down(&HFS_SB(sb)->bitmap_lock); | 208 | mutex_lock(&HFS_SB(sb)->bitmap_lock); |
| 209 | /* bitmap is always on a 32-bit boundary */ | 209 | /* bitmap is always on a 32-bit boundary */ |
| 210 | curr = HFS_SB(sb)->bitmap + (start / 32); | 210 | curr = HFS_SB(sb)->bitmap + (start / 32); |
| 211 | len = count; | 211 | len = count; |
| @@ -236,7 +236,7 @@ int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count) | |||
| 236 | } | 236 | } |
| 237 | out: | 237 | out: |
| 238 | HFS_SB(sb)->free_ablocks += len; | 238 | HFS_SB(sb)->free_ablocks += len; |
| 239 | up(&HFS_SB(sb)->bitmap_lock); | 239 | mutex_unlock(&HFS_SB(sb)->bitmap_lock); |
| 240 | hfs_bitmap_dirty(sb); | 240 | hfs_bitmap_dirty(sb); |
| 241 | 241 | ||
| 242 | return 0; | 242 | return 0; |
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index f6621a785202..9b9d6395bad3 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c | |||
| @@ -40,7 +40,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke | |||
| 40 | { | 40 | { |
| 41 | struct hfs_mdb *mdb = HFS_SB(sb)->mdb; | 41 | struct hfs_mdb *mdb = HFS_SB(sb)->mdb; |
| 42 | HFS_I(tree->inode)->flags = 0; | 42 | HFS_I(tree->inode)->flags = 0; |
| 43 | init_MUTEX(&HFS_I(tree->inode)->extents_lock); | 43 | mutex_init(&HFS_I(tree->inode)->extents_lock); |
| 44 | switch (id) { | 44 | switch (id) { |
| 45 | case HFS_EXT_CNID: | 45 | case HFS_EXT_CNID: |
| 46 | hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize, | 46 | hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize, |
diff --git a/fs/hfs/extent.c b/fs/hfs/extent.c index c176f67ba0a5..2c16316d2917 100644 --- a/fs/hfs/extent.c +++ b/fs/hfs/extent.c | |||
| @@ -343,16 +343,16 @@ int hfs_get_block(struct inode *inode, sector_t block, | |||
| 343 | goto done; | 343 | goto done; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | down(&HFS_I(inode)->extents_lock); | 346 | mutex_lock(&HFS_I(inode)->extents_lock); |
| 347 | res = hfs_ext_read_extent(inode, ablock); | 347 | res = hfs_ext_read_extent(inode, ablock); |
| 348 | if (!res) | 348 | if (!res) |
| 349 | dblock = hfs_ext_find_block(HFS_I(inode)->cached_extents, | 349 | dblock = hfs_ext_find_block(HFS_I(inode)->cached_extents, |
| 350 | ablock - HFS_I(inode)->cached_start); | 350 | ablock - HFS_I(inode)->cached_start); |
| 351 | else { | 351 | else { |
| 352 | up(&HFS_I(inode)->extents_lock); | 352 | mutex_unlock(&HFS_I(inode)->extents_lock); |
| 353 | return -EIO; | 353 | return -EIO; |
| 354 | } | 354 | } |
| 355 | up(&HFS_I(inode)->extents_lock); | 355 | mutex_unlock(&HFS_I(inode)->extents_lock); |
| 356 | 356 | ||
| 357 | done: | 357 | done: |
| 358 | map_bh(bh_result, sb, HFS_SB(sb)->fs_start + | 358 | map_bh(bh_result, sb, HFS_SB(sb)->fs_start + |
| @@ -375,7 +375,7 @@ int hfs_extend_file(struct inode *inode) | |||
| 375 | u32 start, len, goal; | 375 | u32 start, len, goal; |
| 376 | int res; | 376 | int res; |
| 377 | 377 | ||
| 378 | down(&HFS_I(inode)->extents_lock); | 378 | mutex_lock(&HFS_I(inode)->extents_lock); |
| 379 | if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks) | 379 | if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks) |
| 380 | goal = hfs_ext_lastblock(HFS_I(inode)->first_extents); | 380 | goal = hfs_ext_lastblock(HFS_I(inode)->first_extents); |
| 381 | else { | 381 | else { |
| @@ -425,7 +425,7 @@ int hfs_extend_file(struct inode *inode) | |||
| 425 | goto insert_extent; | 425 | goto insert_extent; |
| 426 | } | 426 | } |
| 427 | out: | 427 | out: |
| 428 | up(&HFS_I(inode)->extents_lock); | 428 | mutex_unlock(&HFS_I(inode)->extents_lock); |
| 429 | if (!res) { | 429 | if (!res) { |
| 430 | HFS_I(inode)->alloc_blocks += len; | 430 | HFS_I(inode)->alloc_blocks += len; |
| 431 | mark_inode_dirty(inode); | 431 | mark_inode_dirty(inode); |
| @@ -487,7 +487,7 @@ void hfs_file_truncate(struct inode *inode) | |||
| 487 | if (blk_cnt == alloc_cnt) | 487 | if (blk_cnt == alloc_cnt) |
| 488 | goto out; | 488 | goto out; |
| 489 | 489 | ||
| 490 | down(&HFS_I(inode)->extents_lock); | 490 | mutex_lock(&HFS_I(inode)->extents_lock); |
| 491 | hfs_find_init(HFS_SB(sb)->ext_tree, &fd); | 491 | hfs_find_init(HFS_SB(sb)->ext_tree, &fd); |
| 492 | while (1) { | 492 | while (1) { |
| 493 | if (alloc_cnt == HFS_I(inode)->first_blocks) { | 493 | if (alloc_cnt == HFS_I(inode)->first_blocks) { |
| @@ -514,7 +514,7 @@ void hfs_file_truncate(struct inode *inode) | |||
| 514 | hfs_brec_remove(&fd); | 514 | hfs_brec_remove(&fd); |
| 515 | } | 515 | } |
| 516 | hfs_find_exit(&fd); | 516 | hfs_find_exit(&fd); |
| 517 | up(&HFS_I(inode)->extents_lock); | 517 | mutex_unlock(&HFS_I(inode)->extents_lock); |
| 518 | 518 | ||
| 519 | HFS_I(inode)->alloc_blocks = blk_cnt; | 519 | HFS_I(inode)->alloc_blocks = blk_cnt; |
| 520 | out: | 520 | out: |
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index 147374b6f675..9955232fdf8c 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 14 | #include <linux/mutex.h> | ||
| 14 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
| 15 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
| 16 | 17 | ||
| @@ -53,7 +54,7 @@ struct hfs_inode_info { | |||
| 53 | struct list_head open_dir_list; | 54 | struct list_head open_dir_list; |
| 54 | struct inode *rsrc_inode; | 55 | struct inode *rsrc_inode; |
| 55 | 56 | ||
| 56 | struct semaphore extents_lock; | 57 | struct mutex extents_lock; |
| 57 | 58 | ||
| 58 | u16 alloc_blocks, clump_blocks; | 59 | u16 alloc_blocks, clump_blocks; |
| 59 | sector_t fs_blocks; | 60 | sector_t fs_blocks; |
| @@ -139,7 +140,7 @@ struct hfs_sb_info { | |||
| 139 | 140 | ||
| 140 | struct nls_table *nls_io, *nls_disk; | 141 | struct nls_table *nls_io, *nls_disk; |
| 141 | 142 | ||
| 142 | struct semaphore bitmap_lock; | 143 | struct mutex bitmap_lock; |
| 143 | 144 | ||
| 144 | unsigned long flags; | 145 | unsigned long flags; |
| 145 | 146 | ||
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 97f8446c4ff4..7e19835efa2e 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
| @@ -150,7 +150,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode) | |||
| 150 | if (!inode) | 150 | if (!inode) |
| 151 | return NULL; | 151 | return NULL; |
| 152 | 152 | ||
| 153 | init_MUTEX(&HFS_I(inode)->extents_lock); | 153 | mutex_init(&HFS_I(inode)->extents_lock); |
| 154 | INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); | 154 | INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); |
| 155 | hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); | 155 | hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); |
| 156 | inode->i_ino = HFS_SB(sb)->next_id++; | 156 | inode->i_ino = HFS_SB(sb)->next_id++; |
| @@ -281,7 +281,7 @@ static int hfs_read_inode(struct inode *inode, void *data) | |||
| 281 | 281 | ||
| 282 | HFS_I(inode)->flags = 0; | 282 | HFS_I(inode)->flags = 0; |
| 283 | HFS_I(inode)->rsrc_inode = NULL; | 283 | HFS_I(inode)->rsrc_inode = NULL; |
| 284 | init_MUTEX(&HFS_I(inode)->extents_lock); | 284 | mutex_init(&HFS_I(inode)->extents_lock); |
| 285 | INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); | 285 | INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); |
| 286 | 286 | ||
| 287 | /* Initialize the inode */ | 287 | /* Initialize the inode */ |
| @@ -511,8 +511,7 @@ void hfs_clear_inode(struct inode *inode) | |||
| 511 | } | 511 | } |
| 512 | } | 512 | } |
| 513 | 513 | ||
| 514 | static int hfs_permission(struct inode *inode, int mask, | 514 | static int hfs_permission(struct inode *inode, int mask) |
| 515 | struct nameidata *nd) | ||
| 516 | { | 515 | { |
| 517 | if (S_ISREG(inode->i_mode) && mask & MAY_EXEC) | 516 | if (S_ISREG(inode->i_mode) && mask & MAY_EXEC) |
| 518 | return 0; | 517 | return 0; |
| @@ -523,8 +522,6 @@ static int hfs_file_open(struct inode *inode, struct file *file) | |||
| 523 | { | 522 | { |
| 524 | if (HFS_IS_RSRC(inode)) | 523 | if (HFS_IS_RSRC(inode)) |
| 525 | inode = HFS_I(inode)->rsrc_inode; | 524 | inode = HFS_I(inode)->rsrc_inode; |
| 526 | if (atomic_read(&file->f_count) != 1) | ||
| 527 | return 0; | ||
| 528 | atomic_inc(&HFS_I(inode)->opencnt); | 525 | atomic_inc(&HFS_I(inode)->opencnt); |
| 529 | return 0; | 526 | return 0; |
| 530 | } | 527 | } |
| @@ -535,8 +532,6 @@ static int hfs_file_release(struct inode *inode, struct file *file) | |||
| 535 | 532 | ||
| 536 | if (HFS_IS_RSRC(inode)) | 533 | if (HFS_IS_RSRC(inode)) |
| 537 | inode = HFS_I(inode)->rsrc_inode; | 534 | inode = HFS_I(inode)->rsrc_inode; |
| 538 | if (atomic_read(&file->f_count) != 0) | ||
| 539 | return 0; | ||
| 540 | if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) { | 535 | if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) { |
| 541 | mutex_lock(&inode->i_mutex); | 536 | mutex_lock(&inode->i_mutex); |
| 542 | hfs_file_truncate(inode); | 537 | hfs_file_truncate(inode); |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 8cf67974adf6..4abb1047c689 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
| @@ -372,7 +372,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 372 | 372 | ||
| 373 | sb->s_op = &hfs_super_operations; | 373 | sb->s_op = &hfs_super_operations; |
| 374 | sb->s_flags |= MS_NODIRATIME; | 374 | sb->s_flags |= MS_NODIRATIME; |
| 375 | init_MUTEX(&sbi->bitmap_lock); | 375 | mutex_init(&sbi->bitmap_lock); |
| 376 | 376 | ||
| 377 | res = hfs_mdb_get(sb); | 377 | res = hfs_mdb_get(sb); |
| 378 | if (res) { | 378 | if (res) { |
| @@ -432,7 +432,7 @@ static struct file_system_type hfs_fs_type = { | |||
| 432 | .fs_flags = FS_REQUIRES_DEV, | 432 | .fs_flags = FS_REQUIRES_DEV, |
| 433 | }; | 433 | }; |
| 434 | 434 | ||
| 435 | static void hfs_init_once(struct kmem_cache *cachep, void *p) | 435 | static void hfs_init_once(void *p) |
| 436 | { | 436 | { |
| 437 | struct hfs_inode_info *i = p; | 437 | struct hfs_inode_info *i = p; |
| 438 | 438 | ||
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index 12e899cd7886..fec8f61227ff 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
| @@ -199,16 +199,16 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
| 199 | goto done; | 199 | goto done; |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | down(&HFSPLUS_I(inode).extents_lock); | 202 | mutex_lock(&HFSPLUS_I(inode).extents_lock); |
| 203 | res = hfsplus_ext_read_extent(inode, ablock); | 203 | res = hfsplus_ext_read_extent(inode, ablock); |
| 204 | if (!res) { | 204 | if (!res) { |
| 205 | dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).cached_extents, ablock - | 205 | dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).cached_extents, ablock - |
| 206 | HFSPLUS_I(inode).cached_start); | 206 | HFSPLUS_I(inode).cached_start); |
| 207 | } else { | 207 | } else { |
| 208 | up(&HFSPLUS_I(inode).extents_lock); | 208 | mutex_unlock(&HFSPLUS_I(inode).extents_lock); |
| 209 | return -EIO; | 209 | return -EIO; |
| 210 | } | 210 | } |
| 211 | up(&HFSPLUS_I(inode).extents_lock); | 211 | mutex_unlock(&HFSPLUS_I(inode).extents_lock); |
| 212 | 212 | ||
| 213 | done: | 213 | done: |
| 214 | dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock); | 214 | dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock); |
| @@ -355,7 +355,7 @@ int hfsplus_file_extend(struct inode *inode) | |||
| 355 | return -ENOSPC; | 355 | return -ENOSPC; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | down(&HFSPLUS_I(inode).extents_lock); | 358 | mutex_lock(&HFSPLUS_I(inode).extents_lock); |
| 359 | if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks) | 359 | if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks) |
| 360 | goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents); | 360 | goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents); |
| 361 | else { | 361 | else { |
| @@ -408,7 +408,7 @@ int hfsplus_file_extend(struct inode *inode) | |||
| 408 | goto insert_extent; | 408 | goto insert_extent; |
| 409 | } | 409 | } |
| 410 | out: | 410 | out: |
| 411 | up(&HFSPLUS_I(inode).extents_lock); | 411 | mutex_unlock(&HFSPLUS_I(inode).extents_lock); |
| 412 | if (!res) { | 412 | if (!res) { |
| 413 | HFSPLUS_I(inode).alloc_blocks += len; | 413 | HFSPLUS_I(inode).alloc_blocks += len; |
| 414 | mark_inode_dirty(inode); | 414 | mark_inode_dirty(inode); |
| @@ -465,7 +465,7 @@ void hfsplus_file_truncate(struct inode *inode) | |||
| 465 | if (blk_cnt == alloc_cnt) | 465 | if (blk_cnt == alloc_cnt) |
| 466 | goto out; | 466 | goto out; |
| 467 | 467 | ||
| 468 | down(&HFSPLUS_I(inode).extents_lock); | 468 | mutex_lock(&HFSPLUS_I(inode).extents_lock); |
| 469 | hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); | 469 | hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd); |
| 470 | while (1) { | 470 | while (1) { |
| 471 | if (alloc_cnt == HFSPLUS_I(inode).first_blocks) { | 471 | if (alloc_cnt == HFSPLUS_I(inode).first_blocks) { |
| @@ -492,7 +492,7 @@ void hfsplus_file_truncate(struct inode *inode) | |||
| 492 | hfs_brec_remove(&fd); | 492 | hfs_brec_remove(&fd); |
| 493 | } | 493 | } |
| 494 | hfs_find_exit(&fd); | 494 | hfs_find_exit(&fd); |
| 495 | up(&HFSPLUS_I(inode).extents_lock); | 495 | mutex_unlock(&HFSPLUS_I(inode).extents_lock); |
| 496 | 496 | ||
| 497 | HFSPLUS_I(inode).alloc_blocks = blk_cnt; | 497 | HFSPLUS_I(inode).alloc_blocks = blk_cnt; |
| 498 | out: | 498 | out: |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 9e59537b43d5..f027a905225f 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #define _LINUX_HFSPLUS_FS_H | 11 | #define _LINUX_HFSPLUS_FS_H |
| 12 | 12 | ||
| 13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
| 14 | #include <linux/mutex.h> | ||
| 14 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
| 15 | #include "hfsplus_raw.h" | 16 | #include "hfsplus_raw.h" |
| 16 | 17 | ||
| @@ -154,7 +155,7 @@ struct hfsplus_sb_info { | |||
| 154 | 155 | ||
| 155 | 156 | ||
| 156 | struct hfsplus_inode_info { | 157 | struct hfsplus_inode_info { |
| 157 | struct semaphore extents_lock; | 158 | struct mutex extents_lock; |
| 158 | u32 clump_blocks, alloc_blocks; | 159 | u32 clump_blocks, alloc_blocks; |
| 159 | sector_t fs_blocks; | 160 | sector_t fs_blocks; |
| 160 | /* Allocation extents from catalog record or volume header */ | 161 | /* Allocation extents from catalog record or volume header */ |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 67e1c8b467c4..b085d64a2b67 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
| @@ -163,7 +163,7 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent | |||
| 163 | 163 | ||
| 164 | inode->i_ino = dir->i_ino; | 164 | inode->i_ino = dir->i_ino; |
| 165 | INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); | 165 | INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); |
| 166 | init_MUTEX(&HFSPLUS_I(inode).extents_lock); | 166 | mutex_init(&HFSPLUS_I(inode).extents_lock); |
| 167 | HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC; | 167 | HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC; |
| 168 | 168 | ||
| 169 | hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); | 169 | hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd); |
| @@ -238,7 +238,7 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms) | |||
| 238 | perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev); | 238 | perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | static int hfsplus_permission(struct inode *inode, int mask, struct nameidata *nd) | 241 | static int hfsplus_permission(struct inode *inode, int mask) |
| 242 | { | 242 | { |
| 243 | /* MAY_EXEC is also used for lookup, if no x bit is set allow lookup, | 243 | /* MAY_EXEC is also used for lookup, if no x bit is set allow lookup, |
| 244 | * open_exec has the same test, so it's still not executable, if a x bit | 244 | * open_exec has the same test, so it's still not executable, if a x bit |
| @@ -254,8 +254,6 @@ static int hfsplus_file_open(struct inode *inode, struct file *file) | |||
| 254 | { | 254 | { |
| 255 | if (HFSPLUS_IS_RSRC(inode)) | 255 | if (HFSPLUS_IS_RSRC(inode)) |
| 256 | inode = HFSPLUS_I(inode).rsrc_inode; | 256 | inode = HFSPLUS_I(inode).rsrc_inode; |
| 257 | if (atomic_read(&file->f_count) != 1) | ||
| 258 | return 0; | ||
| 259 | atomic_inc(&HFSPLUS_I(inode).opencnt); | 257 | atomic_inc(&HFSPLUS_I(inode).opencnt); |
| 260 | return 0; | 258 | return 0; |
| 261 | } | 259 | } |
| @@ -266,8 +264,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) | |||
| 266 | 264 | ||
| 267 | if (HFSPLUS_IS_RSRC(inode)) | 265 | if (HFSPLUS_IS_RSRC(inode)) |
| 268 | inode = HFSPLUS_I(inode).rsrc_inode; | 266 | inode = HFSPLUS_I(inode).rsrc_inode; |
| 269 | if (atomic_read(&file->f_count) != 0) | ||
| 270 | return 0; | ||
| 271 | if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) { | 267 | if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) { |
| 272 | mutex_lock(&inode->i_mutex); | 268 | mutex_lock(&inode->i_mutex); |
| 273 | hfsplus_file_truncate(inode); | 269 | hfsplus_file_truncate(inode); |
| @@ -316,7 +312,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode) | |||
| 316 | inode->i_nlink = 1; | 312 | inode->i_nlink = 1; |
| 317 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; | 313 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; |
| 318 | INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); | 314 | INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); |
| 319 | init_MUTEX(&HFSPLUS_I(inode).extents_lock); | 315 | mutex_init(&HFSPLUS_I(inode).extents_lock); |
| 320 | atomic_set(&HFSPLUS_I(inode).opencnt, 0); | 316 | atomic_set(&HFSPLUS_I(inode).opencnt, 0); |
| 321 | HFSPLUS_I(inode).flags = 0; | 317 | HFSPLUS_I(inode).flags = 0; |
| 322 | memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec)); | 318 | memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec)); |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index ce97a54518d8..e834e578c93f 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -34,7 +34,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino) | |||
| 34 | return inode; | 34 | return inode; |
| 35 | 35 | ||
| 36 | INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); | 36 | INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list); |
| 37 | init_MUTEX(&HFSPLUS_I(inode).extents_lock); | 37 | mutex_init(&HFSPLUS_I(inode).extents_lock); |
| 38 | HFSPLUS_I(inode).flags = 0; | 38 | HFSPLUS_I(inode).flags = 0; |
| 39 | HFSPLUS_I(inode).rsrc_inode = NULL; | 39 | HFSPLUS_I(inode).rsrc_inode = NULL; |
| 40 | atomic_set(&HFSPLUS_I(inode).opencnt, 0); | 40 | atomic_set(&HFSPLUS_I(inode).opencnt, 0); |
| @@ -485,7 +485,7 @@ static struct file_system_type hfsplus_fs_type = { | |||
| 485 | .fs_flags = FS_REQUIRES_DEV, | 485 | .fs_flags = FS_REQUIRES_DEV, |
| 486 | }; | 486 | }; |
| 487 | 487 | ||
| 488 | static void hfsplus_init_once(struct kmem_cache *cachep, void *p) | 488 | static void hfsplus_init_once(void *p) |
| 489 | { | 489 | { |
| 490 | struct hfsplus_inode_info *i = p; | 490 | struct hfsplus_inode_info *i = p; |
| 491 | 491 | ||
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 5222345ddccf..d6ecabf4d231 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
| @@ -822,7 +822,7 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from, | |||
| 822 | return err; | 822 | return err; |
| 823 | } | 823 | } |
| 824 | 824 | ||
| 825 | int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd) | 825 | int hostfs_permission(struct inode *ino, int desired) |
| 826 | { | 826 | { |
| 827 | char *name; | 827 | char *name; |
| 828 | int r = 0, w = 0, x = 0, err; | 828 | int r = 0, w = 0, x = 0, err; |
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index d256559b4104..d9c59a775449 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c | |||
| @@ -415,7 +415,7 @@ again: | |||
| 415 | d_drop(dentry); | 415 | d_drop(dentry); |
| 416 | spin_lock(&dentry->d_lock); | 416 | spin_lock(&dentry->d_lock); |
| 417 | if (atomic_read(&dentry->d_count) > 1 || | 417 | if (atomic_read(&dentry->d_count) > 1 || |
| 418 | permission(inode, MAY_WRITE, NULL) || | 418 | generic_permission(inode, MAY_WRITE, NULL) || |
| 419 | !S_ISREG(inode->i_mode) || | 419 | !S_ISREG(inode->i_mode) || |
| 420 | get_write_access(inode)) { | 420 | get_write_access(inode)) { |
| 421 | spin_unlock(&dentry->d_lock); | 421 | spin_unlock(&dentry->d_lock); |
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index f63a699ec659..b8ae9c90ada0 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
| @@ -173,7 +173,7 @@ static void hpfs_destroy_inode(struct inode *inode) | |||
| 173 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); | 173 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | static void init_once(struct kmem_cache *cachep, void *foo) | 176 | static void init_once(void *foo) |
| 177 | { | 177 | { |
| 178 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; | 178 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; |
| 179 | 179 | ||
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 65077aa90f0a..2b3d1828db99 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c | |||
| @@ -655,20 +655,13 @@ static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 655 | return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); | 655 | return proc_dentry->d_inode->i_op->follow_link(proc_dentry, nd); |
| 656 | } | 656 | } |
| 657 | 657 | ||
| 658 | int hppfs_permission(struct inode *inode, int mask, struct nameidata *nd) | ||
| 659 | { | ||
| 660 | return generic_permission(inode, mask, NULL); | ||
| 661 | } | ||
| 662 | |||
| 663 | static const struct inode_operations hppfs_dir_iops = { | 658 | static const struct inode_operations hppfs_dir_iops = { |
| 664 | .lookup = hppfs_lookup, | 659 | .lookup = hppfs_lookup, |
| 665 | .permission = hppfs_permission, | ||
| 666 | }; | 660 | }; |
| 667 | 661 | ||
| 668 | static const struct inode_operations hppfs_link_iops = { | 662 | static const struct inode_operations hppfs_link_iops = { |
| 669 | .readlink = hppfs_readlink, | 663 | .readlink = hppfs_readlink, |
| 670 | .follow_link = hppfs_follow_link, | 664 | .follow_link = hppfs_follow_link, |
| 671 | .permission = hppfs_permission, | ||
| 672 | }; | 665 | }; |
| 673 | 666 | ||
| 674 | static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) | 667 | static struct inode *get_inode(struct super_block *sb, struct dentry *dentry) |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index dbd01d262ca4..3f58923fb39b 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
| @@ -705,7 +705,7 @@ static const struct address_space_operations hugetlbfs_aops = { | |||
| 705 | }; | 705 | }; |
| 706 | 706 | ||
| 707 | 707 | ||
| 708 | static void init_once(struct kmem_cache *cachep, void *foo) | 708 | static void init_once(void *foo) |
| 709 | { | 709 | { |
| 710 | struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo; | 710 | struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo; |
| 711 | 711 | ||
diff --git a/fs/inode.c b/fs/inode.c index c36d9480335c..0487ddba1397 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -166,6 +166,7 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
| 166 | mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE); | 166 | mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE); |
| 167 | mapping->assoc_mapping = NULL; | 167 | mapping->assoc_mapping = NULL; |
| 168 | mapping->backing_dev_info = &default_backing_dev_info; | 168 | mapping->backing_dev_info = &default_backing_dev_info; |
| 169 | mapping->writeback_index = 0; | ||
| 169 | 170 | ||
| 170 | /* | 171 | /* |
| 171 | * If the block_device provides a backing_dev_info for client | 172 | * If the block_device provides a backing_dev_info for client |
| @@ -209,7 +210,7 @@ void inode_init_once(struct inode *inode) | |||
| 209 | INIT_LIST_HEAD(&inode->i_dentry); | 210 | INIT_LIST_HEAD(&inode->i_dentry); |
| 210 | INIT_LIST_HEAD(&inode->i_devices); | 211 | INIT_LIST_HEAD(&inode->i_devices); |
| 211 | INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); | 212 | INIT_RADIX_TREE(&inode->i_data.page_tree, GFP_ATOMIC); |
| 212 | rwlock_init(&inode->i_data.tree_lock); | 213 | spin_lock_init(&inode->i_data.tree_lock); |
| 213 | spin_lock_init(&inode->i_data.i_mmap_lock); | 214 | spin_lock_init(&inode->i_data.i_mmap_lock); |
| 214 | INIT_LIST_HEAD(&inode->i_data.private_list); | 215 | INIT_LIST_HEAD(&inode->i_data.private_list); |
| 215 | spin_lock_init(&inode->i_data.private_lock); | 216 | spin_lock_init(&inode->i_data.private_lock); |
| @@ -224,7 +225,7 @@ void inode_init_once(struct inode *inode) | |||
| 224 | 225 | ||
| 225 | EXPORT_SYMBOL(inode_init_once); | 226 | EXPORT_SYMBOL(inode_init_once); |
| 226 | 227 | ||
| 227 | static void init_once(struct kmem_cache * cachep, void *foo) | 228 | static void init_once(void *foo) |
| 228 | { | 229 | { |
| 229 | struct inode * inode = (struct inode *) foo; | 230 | struct inode * inode = (struct inode *) foo; |
| 230 | 231 | ||
diff --git a/fs/inotify_user.c b/fs/inotify_user.c index fe79c25d95dc..60249429a253 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c | |||
| @@ -354,20 +354,20 @@ static void inotify_dev_event_dequeue(struct inotify_device *dev) | |||
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | /* | 356 | /* |
| 357 | * find_inode - resolve a user-given path to a specific inode and return a nd | 357 | * find_inode - resolve a user-given path to a specific inode |
| 358 | */ | 358 | */ |
| 359 | static int find_inode(const char __user *dirname, struct nameidata *nd, | 359 | static int find_inode(const char __user *dirname, struct path *path, |
| 360 | unsigned flags) | 360 | unsigned flags) |
| 361 | { | 361 | { |
| 362 | int error; | 362 | int error; |
| 363 | 363 | ||
| 364 | error = __user_walk(dirname, flags, nd); | 364 | error = user_path_at(AT_FDCWD, dirname, flags, path); |
| 365 | if (error) | 365 | if (error) |
| 366 | return error; | 366 | return error; |
| 367 | /* you can only watch an inode if you have read permissions on it */ | 367 | /* you can only watch an inode if you have read permissions on it */ |
| 368 | error = vfs_permission(nd, MAY_READ); | 368 | error = inode_permission(path->dentry->d_inode, MAY_READ); |
| 369 | if (error) | 369 | if (error) |
| 370 | path_put(&nd->path); | 370 | path_put(path); |
| 371 | return error; | 371 | return error; |
| 372 | } | 372 | } |
| 373 | 373 | ||
| @@ -650,11 +650,11 @@ asmlinkage long sys_inotify_init(void) | |||
| 650 | return sys_inotify_init1(0); | 650 | return sys_inotify_init1(0); |
| 651 | } | 651 | } |
| 652 | 652 | ||
| 653 | asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) | 653 | asmlinkage long sys_inotify_add_watch(int fd, const char __user *pathname, u32 mask) |
| 654 | { | 654 | { |
| 655 | struct inode *inode; | 655 | struct inode *inode; |
| 656 | struct inotify_device *dev; | 656 | struct inotify_device *dev; |
| 657 | struct nameidata nd; | 657 | struct path path; |
| 658 | struct file *filp; | 658 | struct file *filp; |
| 659 | int ret, fput_needed; | 659 | int ret, fput_needed; |
| 660 | unsigned flags = 0; | 660 | unsigned flags = 0; |
| @@ -674,12 +674,12 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) | |||
| 674 | if (mask & IN_ONLYDIR) | 674 | if (mask & IN_ONLYDIR) |
| 675 | flags |= LOOKUP_DIRECTORY; | 675 | flags |= LOOKUP_DIRECTORY; |
| 676 | 676 | ||
| 677 | ret = find_inode(path, &nd, flags); | 677 | ret = find_inode(pathname, &path, flags); |
| 678 | if (unlikely(ret)) | 678 | if (unlikely(ret)) |
| 679 | goto fput_and_out; | 679 | goto fput_and_out; |
| 680 | 680 | ||
| 681 | /* inode held in place by reference to nd; dev by fget on fd */ | 681 | /* inode held in place by reference to path; dev by fget on fd */ |
| 682 | inode = nd.path.dentry->d_inode; | 682 | inode = path.dentry->d_inode; |
| 683 | dev = filp->private_data; | 683 | dev = filp->private_data; |
| 684 | 684 | ||
| 685 | mutex_lock(&dev->up_mutex); | 685 | mutex_lock(&dev->up_mutex); |
| @@ -688,7 +688,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) | |||
| 688 | ret = create_watch(dev, inode, mask); | 688 | ret = create_watch(dev, inode, mask); |
| 689 | mutex_unlock(&dev->up_mutex); | 689 | mutex_unlock(&dev->up_mutex); |
| 690 | 690 | ||
| 691 | path_put(&nd.path); | 691 | path_put(&path); |
| 692 | fput_and_out: | 692 | fput_and_out: |
| 693 | fput_light(filp, fput_needed); | 693 | fput_light(filp, fput_needed); |
| 694 | return ret; | 694 | return ret; |
diff --git a/fs/ioprio.c b/fs/ioprio.c index c4a1c3c65aac..da3cc460d4df 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c | |||
| @@ -115,11 +115,11 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) | |||
| 115 | pgrp = task_pgrp(current); | 115 | pgrp = task_pgrp(current); |
| 116 | else | 116 | else |
| 117 | pgrp = find_vpid(who); | 117 | pgrp = find_vpid(who); |
| 118 | do_each_pid_task(pgrp, PIDTYPE_PGID, p) { | 118 | do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { |
| 119 | ret = set_task_ioprio(p, ioprio); | 119 | ret = set_task_ioprio(p, ioprio); |
| 120 | if (ret) | 120 | if (ret) |
| 121 | break; | 121 | break; |
| 122 | } while_each_pid_task(pgrp, PIDTYPE_PGID, p); | 122 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 123 | break; | 123 | break; |
| 124 | case IOPRIO_WHO_USER: | 124 | case IOPRIO_WHO_USER: |
| 125 | if (!who) | 125 | if (!who) |
| @@ -204,7 +204,7 @@ asmlinkage long sys_ioprio_get(int which, int who) | |||
| 204 | pgrp = task_pgrp(current); | 204 | pgrp = task_pgrp(current); |
| 205 | else | 205 | else |
| 206 | pgrp = find_vpid(who); | 206 | pgrp = find_vpid(who); |
| 207 | do_each_pid_task(pgrp, PIDTYPE_PGID, p) { | 207 | do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { |
| 208 | tmpio = get_task_ioprio(p); | 208 | tmpio = get_task_ioprio(p); |
| 209 | if (tmpio < 0) | 209 | if (tmpio < 0) |
| 210 | continue; | 210 | continue; |
| @@ -212,7 +212,7 @@ asmlinkage long sys_ioprio_get(int which, int who) | |||
| 212 | ret = tmpio; | 212 | ret = tmpio; |
| 213 | else | 213 | else |
| 214 | ret = ioprio_best(ret, tmpio); | 214 | ret = ioprio_best(ret, tmpio); |
| 215 | } while_each_pid_task(pgrp, PIDTYPE_PGID, p); | 215 | } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); |
| 216 | break; | 216 | break; |
| 217 | case IOPRIO_WHO_USER: | 217 | case IOPRIO_WHO_USER: |
| 218 | if (!who) | 218 | if (!who) |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 044a254d526b..26948a6033b6 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -73,7 +73,7 @@ static void isofs_destroy_inode(struct inode *inode) | |||
| 73 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); | 73 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | static void init_once(struct kmem_cache *cachep, void *foo) | 76 | static void init_once(void *foo) |
| 77 | { | 77 | { |
| 78 | struct iso_inode_info *ei = foo; | 78 | struct iso_inode_info *ei = foo; |
| 79 | 79 | ||
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 6bd48f0a7047..c2fb2dd0131f 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c | |||
| @@ -209,6 +209,11 @@ repeat: | |||
| 209 | 209 | ||
| 210 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ | 210 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
| 211 | rr = (struct rock_ridge *)rs.chr; | 211 | rr = (struct rock_ridge *)rs.chr; |
| 212 | /* | ||
| 213 | * Ignore rock ridge info if rr->len is out of range, but | ||
| 214 | * don't return -EIO because that would make the file | ||
| 215 | * invisible. | ||
| 216 | */ | ||
| 212 | if (rr->len < 3) | 217 | if (rr->len < 3) |
| 213 | goto out; /* Something got screwed up here */ | 218 | goto out; /* Something got screwed up here */ |
| 214 | sig = isonum_721(rs.chr); | 219 | sig = isonum_721(rs.chr); |
| @@ -216,8 +221,12 @@ repeat: | |||
| 216 | goto eio; | 221 | goto eio; |
| 217 | rs.chr += rr->len; | 222 | rs.chr += rr->len; |
| 218 | rs.len -= rr->len; | 223 | rs.len -= rr->len; |
| 224 | /* | ||
| 225 | * As above, just ignore the rock ridge info if rr->len | ||
| 226 | * is bogus. | ||
| 227 | */ | ||
| 219 | if (rs.len < 0) | 228 | if (rs.len < 0) |
| 220 | goto eio; /* corrupted isofs */ | 229 | goto out; /* Something got screwed up here */ |
| 221 | 230 | ||
| 222 | switch (sig) { | 231 | switch (sig) { |
| 223 | case SIG('R', 'R'): | 232 | case SIG('R', 'R'): |
| @@ -307,6 +316,11 @@ parse_rock_ridge_inode_internal(struct iso_directory_record *de, | |||
| 307 | repeat: | 316 | repeat: |
| 308 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ | 317 | while (rs.len > 2) { /* There may be one byte for padding somewhere */ |
| 309 | rr = (struct rock_ridge *)rs.chr; | 318 | rr = (struct rock_ridge *)rs.chr; |
| 319 | /* | ||
| 320 | * Ignore rock ridge info if rr->len is out of range, but | ||
| 321 | * don't return -EIO because that would make the file | ||
| 322 | * invisible. | ||
| 323 | */ | ||
| 310 | if (rr->len < 3) | 324 | if (rr->len < 3) |
| 311 | goto out; /* Something got screwed up here */ | 325 | goto out; /* Something got screwed up here */ |
| 312 | sig = isonum_721(rs.chr); | 326 | sig = isonum_721(rs.chr); |
| @@ -314,8 +328,12 @@ repeat: | |||
| 314 | goto eio; | 328 | goto eio; |
| 315 | rs.chr += rr->len; | 329 | rs.chr += rr->len; |
| 316 | rs.len -= rr->len; | 330 | rs.len -= rr->len; |
| 331 | /* | ||
| 332 | * As above, just ignore the rock ridge info if rr->len | ||
| 333 | * is bogus. | ||
| 334 | */ | ||
| 317 | if (rs.len < 0) | 335 | if (rs.len < 0) |
| 318 | goto eio; /* corrupted isofs */ | 336 | goto out; /* Something got screwed up here */ |
| 319 | 337 | ||
| 320 | switch (sig) { | 338 | switch (sig) { |
| 321 | #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ | 339 | #ifndef CONFIG_ZISOFS /* No flag for SF or ZF */ |
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 5a8ca61498ca..ae08c057e751 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
| @@ -36,7 +36,7 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
| 36 | 36 | ||
| 37 | /* | 37 | /* |
| 38 | * When an ext3-ordered file is truncated, it is possible that many pages are | 38 | * When an ext3-ordered file is truncated, it is possible that many pages are |
| 39 | * not sucessfully freed, because they are attached to a committing transaction. | 39 | * not successfully freed, because they are attached to a committing transaction. |
| 40 | * After the transaction commits, these pages are left on the LRU, with no | 40 | * After the transaction commits, these pages are left on the LRU, with no |
| 41 | * ->mapping, and with attached buffers. These pages are trivially reclaimable | 41 | * ->mapping, and with attached buffers. These pages are trivially reclaimable |
| 42 | * by the VM, but their apparent absence upsets the VM accounting, and it makes | 42 | * by the VM, but their apparent absence upsets the VM accounting, and it makes |
| @@ -45,8 +45,8 @@ static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) | |||
| 45 | * So here, we have a buffer which has just come off the forget list. Look to | 45 | * So here, we have a buffer which has just come off the forget list. Look to |
| 46 | * see if we can strip all buffers from the backing page. | 46 | * see if we can strip all buffers from the backing page. |
| 47 | * | 47 | * |
| 48 | * Called under lock_journal(), and possibly under journal_datalist_lock. The | 48 | * Called under journal->j_list_lock. The caller provided us with a ref |
| 49 | * caller provided us with a ref against the buffer, and we drop that here. | 49 | * against the buffer, and we drop that here. |
| 50 | */ | 50 | */ |
| 51 | static void release_buffer_page(struct buffer_head *bh) | 51 | static void release_buffer_page(struct buffer_head *bh) |
| 52 | { | 52 | { |
| @@ -63,7 +63,7 @@ static void release_buffer_page(struct buffer_head *bh) | |||
| 63 | goto nope; | 63 | goto nope; |
| 64 | 64 | ||
| 65 | /* OK, it's a truncated page */ | 65 | /* OK, it's a truncated page */ |
| 66 | if (TestSetPageLocked(page)) | 66 | if (!trylock_page(page)) |
| 67 | goto nope; | 67 | goto nope; |
| 68 | 68 | ||
| 69 | page_cache_get(page); | 69 | page_cache_get(page); |
| @@ -78,6 +78,19 @@ nope: | |||
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | /* | 80 | /* |
| 81 | * Decrement reference counter for data buffer. If it has been marked | ||
| 82 | * 'BH_Freed', release it and the page to which it belongs if possible. | ||
| 83 | */ | ||
| 84 | static void release_data_buffer(struct buffer_head *bh) | ||
| 85 | { | ||
| 86 | if (buffer_freed(bh)) { | ||
| 87 | clear_buffer_freed(bh); | ||
| 88 | release_buffer_page(bh); | ||
| 89 | } else | ||
| 90 | put_bh(bh); | ||
| 91 | } | ||
| 92 | |||
| 93 | /* | ||
| 81 | * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is | 94 | * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is |
| 82 | * held. For ranking reasons we must trylock. If we lose, schedule away and | 95 | * held. For ranking reasons we must trylock. If we lose, schedule away and |
| 83 | * return 0. j_list_lock is dropped in this case. | 96 | * return 0. j_list_lock is dropped in this case. |
| @@ -172,7 +185,7 @@ static void journal_do_submit_data(struct buffer_head **wbuf, int bufs) | |||
| 172 | /* | 185 | /* |
| 173 | * Submit all the data buffers to disk | 186 | * Submit all the data buffers to disk |
| 174 | */ | 187 | */ |
| 175 | static void journal_submit_data_buffers(journal_t *journal, | 188 | static int journal_submit_data_buffers(journal_t *journal, |
| 176 | transaction_t *commit_transaction) | 189 | transaction_t *commit_transaction) |
| 177 | { | 190 | { |
| 178 | struct journal_head *jh; | 191 | struct journal_head *jh; |
| @@ -180,6 +193,7 @@ static void journal_submit_data_buffers(journal_t *journal, | |||
| 180 | int locked; | 193 | int locked; |
| 181 | int bufs = 0; | 194 | int bufs = 0; |
| 182 | struct buffer_head **wbuf = journal->j_wbuf; | 195 | struct buffer_head **wbuf = journal->j_wbuf; |
| 196 | int err = 0; | ||
| 183 | 197 | ||
| 184 | /* | 198 | /* |
| 185 | * Whenever we unlock the journal and sleep, things can get added | 199 | * Whenever we unlock the journal and sleep, things can get added |
| @@ -207,7 +221,7 @@ write_out_data: | |||
| 207 | * blocking lock_buffer(). | 221 | * blocking lock_buffer(). |
| 208 | */ | 222 | */ |
| 209 | if (buffer_dirty(bh)) { | 223 | if (buffer_dirty(bh)) { |
| 210 | if (test_set_buffer_locked(bh)) { | 224 | if (!trylock_buffer(bh)) { |
| 211 | BUFFER_TRACE(bh, "needs blocking lock"); | 225 | BUFFER_TRACE(bh, "needs blocking lock"); |
| 212 | spin_unlock(&journal->j_list_lock); | 226 | spin_unlock(&journal->j_list_lock); |
| 213 | /* Write out all data to prevent deadlocks */ | 227 | /* Write out all data to prevent deadlocks */ |
| @@ -231,7 +245,7 @@ write_out_data: | |||
| 231 | if (locked) | 245 | if (locked) |
| 232 | unlock_buffer(bh); | 246 | unlock_buffer(bh); |
| 233 | BUFFER_TRACE(bh, "already cleaned up"); | 247 | BUFFER_TRACE(bh, "already cleaned up"); |
| 234 | put_bh(bh); | 248 | release_data_buffer(bh); |
| 235 | continue; | 249 | continue; |
| 236 | } | 250 | } |
| 237 | if (locked && test_clear_buffer_dirty(bh)) { | 251 | if (locked && test_clear_buffer_dirty(bh)) { |
| @@ -253,15 +267,17 @@ write_out_data: | |||
| 253 | put_bh(bh); | 267 | put_bh(bh); |
| 254 | } else { | 268 | } else { |
| 255 | BUFFER_TRACE(bh, "writeout complete: unfile"); | 269 | BUFFER_TRACE(bh, "writeout complete: unfile"); |
| 270 | if (unlikely(!buffer_uptodate(bh))) | ||
| 271 | err = -EIO; | ||
| 256 | __journal_unfile_buffer(jh); | 272 | __journal_unfile_buffer(jh); |
| 257 | jbd_unlock_bh_state(bh); | 273 | jbd_unlock_bh_state(bh); |
| 258 | if (locked) | 274 | if (locked) |
| 259 | unlock_buffer(bh); | 275 | unlock_buffer(bh); |
| 260 | journal_remove_journal_head(bh); | 276 | journal_remove_journal_head(bh); |
| 261 | /* Once for our safety reference, once for | 277 | /* One for our safety reference, other for |
| 262 | * journal_remove_journal_head() */ | 278 | * journal_remove_journal_head() */ |
| 263 | put_bh(bh); | 279 | put_bh(bh); |
| 264 | put_bh(bh); | 280 | release_data_buffer(bh); |
| 265 | } | 281 | } |
| 266 | 282 | ||
| 267 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { | 283 | if (need_resched() || spin_needbreak(&journal->j_list_lock)) { |
| @@ -271,6 +287,8 @@ write_out_data: | |||
| 271 | } | 287 | } |
| 272 | spin_unlock(&journal->j_list_lock); | 288 | spin_unlock(&journal->j_list_lock); |
| 273 | journal_do_submit_data(wbuf, bufs); | 289 | journal_do_submit_data(wbuf, bufs); |
| 290 | |||
| 291 | return err; | ||
| 274 | } | 292 | } |
| 275 | 293 | ||
| 276 | /* | 294 | /* |
| @@ -410,8 +428,7 @@ void journal_commit_transaction(journal_t *journal) | |||
| 410 | * Now start flushing things to disk, in the order they appear | 428 | * Now start flushing things to disk, in the order they appear |
| 411 | * on the transaction lists. Data blocks go first. | 429 | * on the transaction lists. Data blocks go first. |
| 412 | */ | 430 | */ |
| 413 | err = 0; | 431 | err = journal_submit_data_buffers(journal, commit_transaction); |
| 414 | journal_submit_data_buffers(journal, commit_transaction); | ||
| 415 | 432 | ||
| 416 | /* | 433 | /* |
| 417 | * Wait for all previously submitted IO to complete. | 434 | * Wait for all previously submitted IO to complete. |
| @@ -426,10 +443,21 @@ void journal_commit_transaction(journal_t *journal) | |||
| 426 | if (buffer_locked(bh)) { | 443 | if (buffer_locked(bh)) { |
| 427 | spin_unlock(&journal->j_list_lock); | 444 | spin_unlock(&journal->j_list_lock); |
| 428 | wait_on_buffer(bh); | 445 | wait_on_buffer(bh); |
| 429 | if (unlikely(!buffer_uptodate(bh))) | ||
| 430 | err = -EIO; | ||
| 431 | spin_lock(&journal->j_list_lock); | 446 | spin_lock(&journal->j_list_lock); |
| 432 | } | 447 | } |
| 448 | if (unlikely(!buffer_uptodate(bh))) { | ||
| 449 | if (!trylock_page(bh->b_page)) { | ||
| 450 | spin_unlock(&journal->j_list_lock); | ||
| 451 | lock_page(bh->b_page); | ||
| 452 | spin_lock(&journal->j_list_lock); | ||
| 453 | } | ||
| 454 | if (bh->b_page->mapping) | ||
| 455 | set_bit(AS_EIO, &bh->b_page->mapping->flags); | ||
| 456 | |||
| 457 | unlock_page(bh->b_page); | ||
| 458 | SetPageError(bh->b_page); | ||
| 459 | err = -EIO; | ||
| 460 | } | ||
| 433 | if (!inverted_lock(journal, bh)) { | 461 | if (!inverted_lock(journal, bh)) { |
| 434 | put_bh(bh); | 462 | put_bh(bh); |
| 435 | spin_lock(&journal->j_list_lock); | 463 | spin_lock(&journal->j_list_lock); |
| @@ -443,17 +471,21 @@ void journal_commit_transaction(journal_t *journal) | |||
| 443 | } else { | 471 | } else { |
| 444 | jbd_unlock_bh_state(bh); | 472 | jbd_unlock_bh_state(bh); |
| 445 | } | 473 | } |
| 446 | put_bh(bh); | 474 | release_data_buffer(bh); |
| 447 | cond_resched_lock(&journal->j_list_lock); | 475 | cond_resched_lock(&journal->j_list_lock); |
| 448 | } | 476 | } |
| 449 | spin_unlock(&journal->j_list_lock); | 477 | spin_unlock(&journal->j_list_lock); |
| 450 | 478 | ||
| 451 | if (err) | 479 | if (err) { |
| 452 | journal_abort(journal, err); | 480 | char b[BDEVNAME_SIZE]; |
| 453 | 481 | ||
| 454 | journal_write_revoke_records(journal, commit_transaction); | 482 | printk(KERN_WARNING |
| 483 | "JBD: Detected IO errors while flushing file data " | ||
| 484 | "on %s\n", bdevname(journal->j_fs_dev, b)); | ||
| 485 | err = 0; | ||
| 486 | } | ||
| 455 | 487 | ||
| 456 | jbd_debug(3, "JBD: commit phase 2\n"); | 488 | journal_write_revoke_records(journal, commit_transaction); |
| 457 | 489 | ||
| 458 | /* | 490 | /* |
| 459 | * If we found any dirty or locked buffers, then we should have | 491 | * If we found any dirty or locked buffers, then we should have |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index b99c3b3654c4..aa7143a8349b 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
| @@ -68,7 +68,6 @@ EXPORT_SYMBOL(journal_set_features); | |||
| 68 | EXPORT_SYMBOL(journal_create); | 68 | EXPORT_SYMBOL(journal_create); |
| 69 | EXPORT_SYMBOL(journal_load); | 69 | EXPORT_SYMBOL(journal_load); |
| 70 | EXPORT_SYMBOL(journal_destroy); | 70 | EXPORT_SYMBOL(journal_destroy); |
| 71 | EXPORT_SYMBOL(journal_update_superblock); | ||
| 72 | EXPORT_SYMBOL(journal_abort); | 71 | EXPORT_SYMBOL(journal_abort); |
| 73 | EXPORT_SYMBOL(journal_errno); | 72 | EXPORT_SYMBOL(journal_errno); |
| 74 | EXPORT_SYMBOL(journal_ack_err); | 73 | EXPORT_SYMBOL(journal_ack_err); |
| @@ -1636,9 +1635,10 @@ static int journal_init_journal_head_cache(void) | |||
| 1636 | 1635 | ||
| 1637 | static void journal_destroy_journal_head_cache(void) | 1636 | static void journal_destroy_journal_head_cache(void) |
| 1638 | { | 1637 | { |
| 1639 | J_ASSERT(journal_head_cache != NULL); | 1638 | if (journal_head_cache) { |
| 1640 | kmem_cache_destroy(journal_head_cache); | 1639 | kmem_cache_destroy(journal_head_cache); |
| 1641 | journal_head_cache = NULL; | 1640 | journal_head_cache = NULL; |
| 1641 | } | ||
| 1642 | } | 1642 | } |
| 1643 | 1643 | ||
| 1644 | /* | 1644 | /* |
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index 1bb43e987f4b..c7bd649bbbdc 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c | |||
| @@ -166,138 +166,123 @@ static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, | |||
| 166 | return NULL; | 166 | return NULL; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | void journal_destroy_revoke_caches(void) | ||
| 170 | { | ||
| 171 | if (revoke_record_cache) { | ||
| 172 | kmem_cache_destroy(revoke_record_cache); | ||
| 173 | revoke_record_cache = NULL; | ||
| 174 | } | ||
| 175 | if (revoke_table_cache) { | ||
| 176 | kmem_cache_destroy(revoke_table_cache); | ||
| 177 | revoke_table_cache = NULL; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 169 | int __init journal_init_revoke_caches(void) | 181 | int __init journal_init_revoke_caches(void) |
| 170 | { | 182 | { |
| 183 | J_ASSERT(!revoke_record_cache); | ||
| 184 | J_ASSERT(!revoke_table_cache); | ||
| 185 | |||
| 171 | revoke_record_cache = kmem_cache_create("revoke_record", | 186 | revoke_record_cache = kmem_cache_create("revoke_record", |
| 172 | sizeof(struct jbd_revoke_record_s), | 187 | sizeof(struct jbd_revoke_record_s), |
| 173 | 0, | 188 | 0, |
| 174 | SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, | 189 | SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, |
| 175 | NULL); | 190 | NULL); |
| 176 | if (!revoke_record_cache) | 191 | if (!revoke_record_cache) |
| 177 | return -ENOMEM; | 192 | goto record_cache_failure; |
| 178 | 193 | ||
| 179 | revoke_table_cache = kmem_cache_create("revoke_table", | 194 | revoke_table_cache = kmem_cache_create("revoke_table", |
| 180 | sizeof(struct jbd_revoke_table_s), | 195 | sizeof(struct jbd_revoke_table_s), |
| 181 | 0, SLAB_TEMPORARY, NULL); | 196 | 0, SLAB_TEMPORARY, NULL); |
| 182 | if (!revoke_table_cache) { | 197 | if (!revoke_table_cache) |
| 183 | kmem_cache_destroy(revoke_record_cache); | 198 | goto table_cache_failure; |
| 184 | revoke_record_cache = NULL; | 199 | |
| 185 | return -ENOMEM; | ||
| 186 | } | ||
| 187 | return 0; | 200 | return 0; |
| 188 | } | ||
| 189 | 201 | ||
| 190 | void journal_destroy_revoke_caches(void) | 202 | table_cache_failure: |
| 191 | { | 203 | journal_destroy_revoke_caches(); |
| 192 | kmem_cache_destroy(revoke_record_cache); | 204 | record_cache_failure: |
| 193 | revoke_record_cache = NULL; | 205 | return -ENOMEM; |
| 194 | kmem_cache_destroy(revoke_table_cache); | ||
| 195 | revoke_table_cache = NULL; | ||
| 196 | } | 206 | } |
| 197 | 207 | ||
| 198 | /* Initialise the revoke table for a given journal to a given size. */ | 208 | static struct jbd_revoke_table_s *journal_init_revoke_table(int hash_size) |
| 199 | |||
| 200 | int journal_init_revoke(journal_t *journal, int hash_size) | ||
| 201 | { | 209 | { |
| 202 | int shift, tmp; | 210 | int shift = 0; |
| 211 | int tmp = hash_size; | ||
| 212 | struct jbd_revoke_table_s *table; | ||
| 203 | 213 | ||
| 204 | J_ASSERT (journal->j_revoke_table[0] == NULL); | 214 | table = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); |
| 215 | if (!table) | ||
| 216 | goto out; | ||
| 205 | 217 | ||
| 206 | shift = 0; | ||
| 207 | tmp = hash_size; | ||
| 208 | while((tmp >>= 1UL) != 0UL) | 218 | while((tmp >>= 1UL) != 0UL) |
| 209 | shift++; | 219 | shift++; |
| 210 | 220 | ||
| 211 | journal->j_revoke_table[0] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); | 221 | table->hash_size = hash_size; |
| 212 | if (!journal->j_revoke_table[0]) | 222 | table->hash_shift = shift; |
| 213 | return -ENOMEM; | 223 | table->hash_table = |
| 214 | journal->j_revoke = journal->j_revoke_table[0]; | ||
| 215 | |||
| 216 | /* Check that the hash_size is a power of two */ | ||
| 217 | J_ASSERT(is_power_of_2(hash_size)); | ||
| 218 | |||
| 219 | journal->j_revoke->hash_size = hash_size; | ||
| 220 | |||
| 221 | journal->j_revoke->hash_shift = shift; | ||
| 222 | |||
| 223 | journal->j_revoke->hash_table = | ||
| 224 | kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); | 224 | kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); |
| 225 | if (!journal->j_revoke->hash_table) { | 225 | if (!table->hash_table) { |
| 226 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); | 226 | kmem_cache_free(revoke_table_cache, table); |
| 227 | journal->j_revoke = NULL; | 227 | table = NULL; |
| 228 | return -ENOMEM; | 228 | goto out; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | for (tmp = 0; tmp < hash_size; tmp++) | 231 | for (tmp = 0; tmp < hash_size; tmp++) |
| 232 | INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); | 232 | INIT_LIST_HEAD(&table->hash_table[tmp]); |
| 233 | 233 | ||
| 234 | journal->j_revoke_table[1] = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); | 234 | out: |
| 235 | if (!journal->j_revoke_table[1]) { | 235 | return table; |
| 236 | kfree(journal->j_revoke_table[0]->hash_table); | 236 | } |
| 237 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); | 237 | |
| 238 | return -ENOMEM; | 238 | static void journal_destroy_revoke_table(struct jbd_revoke_table_s *table) |
| 239 | { | ||
| 240 | int i; | ||
| 241 | struct list_head *hash_list; | ||
| 242 | |||
| 243 | for (i = 0; i < table->hash_size; i++) { | ||
| 244 | hash_list = &table->hash_table[i]; | ||
| 245 | J_ASSERT(list_empty(hash_list)); | ||
| 239 | } | 246 | } |
| 240 | 247 | ||
| 241 | journal->j_revoke = journal->j_revoke_table[1]; | 248 | kfree(table->hash_table); |
| 249 | kmem_cache_free(revoke_table_cache, table); | ||
| 250 | } | ||
| 242 | 251 | ||
| 243 | /* Check that the hash_size is a power of two */ | 252 | /* Initialise the revoke table for a given journal to a given size. */ |
| 253 | int journal_init_revoke(journal_t *journal, int hash_size) | ||
| 254 | { | ||
| 255 | J_ASSERT(journal->j_revoke_table[0] == NULL); | ||
| 244 | J_ASSERT(is_power_of_2(hash_size)); | 256 | J_ASSERT(is_power_of_2(hash_size)); |
| 245 | 257 | ||
| 246 | journal->j_revoke->hash_size = hash_size; | 258 | journal->j_revoke_table[0] = journal_init_revoke_table(hash_size); |
| 259 | if (!journal->j_revoke_table[0]) | ||
| 260 | goto fail0; | ||
| 247 | 261 | ||
| 248 | journal->j_revoke->hash_shift = shift; | 262 | journal->j_revoke_table[1] = journal_init_revoke_table(hash_size); |
| 263 | if (!journal->j_revoke_table[1]) | ||
| 264 | goto fail1; | ||
| 249 | 265 | ||
| 250 | journal->j_revoke->hash_table = | 266 | journal->j_revoke = journal->j_revoke_table[1]; |
| 251 | kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); | ||
| 252 | if (!journal->j_revoke->hash_table) { | ||
| 253 | kfree(journal->j_revoke_table[0]->hash_table); | ||
| 254 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[0]); | ||
| 255 | kmem_cache_free(revoke_table_cache, journal->j_revoke_table[1]); | ||
| 256 | journal->j_revoke = NULL; | ||
| 257 | return -ENOMEM; | ||
| 258 | } | ||
| 259 | |||
| 260 | for (tmp = 0; tmp < hash_size; tmp++) | ||
| 261 | INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); | ||
| 262 | 267 | ||
| 263 | spin_lock_init(&journal->j_revoke_lock); | 268 | spin_lock_init(&journal->j_revoke_lock); |
| 264 | 269 | ||
| 265 | return 0; | 270 | return 0; |
| 266 | } | ||
| 267 | 271 | ||
| 268 | /* Destoy a journal's revoke table. The table must already be empty! */ | 272 | fail1: |
| 273 | journal_destroy_revoke_table(journal->j_revoke_table[0]); | ||
| 274 | fail0: | ||
| 275 | return -ENOMEM; | ||
| 276 | } | ||
| 269 | 277 | ||
| 278 | /* Destroy a journal's revoke table. The table must already be empty! */ | ||
| 270 | void journal_destroy_revoke(journal_t *journal) | 279 | void journal_destroy_revoke(journal_t *journal) |
| 271 | { | 280 | { |
| 272 | struct jbd_revoke_table_s *table; | ||
| 273 | struct list_head *hash_list; | ||
| 274 | int i; | ||
| 275 | |||
| 276 | table = journal->j_revoke_table[0]; | ||
| 277 | if (!table) | ||
| 278 | return; | ||
| 279 | |||
| 280 | for (i=0; i<table->hash_size; i++) { | ||
| 281 | hash_list = &table->hash_table[i]; | ||
| 282 | J_ASSERT (list_empty(hash_list)); | ||
| 283 | } | ||
| 284 | |||
| 285 | kfree(table->hash_table); | ||
| 286 | kmem_cache_free(revoke_table_cache, table); | ||
| 287 | journal->j_revoke = NULL; | ||
| 288 | |||
| 289 | table = journal->j_revoke_table[1]; | ||
| 290 | if (!table) | ||
| 291 | return; | ||
| 292 | |||
| 293 | for (i=0; i<table->hash_size; i++) { | ||
| 294 | hash_list = &table->hash_table[i]; | ||
| 295 | J_ASSERT (list_empty(hash_list)); | ||
| 296 | } | ||
| 297 | |||
| 298 | kfree(table->hash_table); | ||
| 299 | kmem_cache_free(revoke_table_cache, table); | ||
| 300 | journal->j_revoke = NULL; | 281 | journal->j_revoke = NULL; |
| 282 | if (journal->j_revoke_table[0]) | ||
| 283 | journal_destroy_revoke_table(journal->j_revoke_table[0]); | ||
| 284 | if (journal->j_revoke_table[1]) | ||
| 285 | journal_destroy_revoke_table(journal->j_revoke_table[1]); | ||
| 301 | } | 286 | } |
| 302 | 287 | ||
| 303 | 288 | ||
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index 67ff2024c23c..0540ca27a446 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
| @@ -291,7 +291,7 @@ handle_t *journal_start(journal_t *journal, int nblocks) | |||
| 291 | goto out; | 291 | goto out; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_); | 294 | lock_map_acquire(&handle->h_lockdep_map); |
| 295 | 295 | ||
| 296 | out: | 296 | out: |
| 297 | return handle; | 297 | return handle; |
| @@ -1448,7 +1448,7 @@ int journal_stop(handle_t *handle) | |||
| 1448 | spin_unlock(&journal->j_state_lock); | 1448 | spin_unlock(&journal->j_state_lock); |
| 1449 | } | 1449 | } |
| 1450 | 1450 | ||
| 1451 | lock_release(&handle->h_lockdep_map, 1, _THIS_IP_); | 1451 | lock_map_release(&handle->h_lockdep_map); |
| 1452 | 1452 | ||
| 1453 | jbd_free_handle(handle); | 1453 | jbd_free_handle(handle); |
| 1454 | return err; | 1454 | return err; |
| @@ -1648,12 +1648,42 @@ out: | |||
| 1648 | return; | 1648 | return; |
| 1649 | } | 1649 | } |
| 1650 | 1650 | ||
| 1651 | /* | ||
| 1652 | * journal_try_to_free_buffers() could race with journal_commit_transaction() | ||
| 1653 | * The latter might still hold the a count on buffers when inspecting | ||
| 1654 | * them on t_syncdata_list or t_locked_list. | ||
| 1655 | * | ||
| 1656 | * journal_try_to_free_buffers() will call this function to | ||
| 1657 | * wait for the current transaction to finish syncing data buffers, before | ||
| 1658 | * tryinf to free that buffer. | ||
| 1659 | * | ||
| 1660 | * Called with journal->j_state_lock held. | ||
| 1661 | */ | ||
| 1662 | static void journal_wait_for_transaction_sync_data(journal_t *journal) | ||
| 1663 | { | ||
| 1664 | transaction_t *transaction = NULL; | ||
| 1665 | tid_t tid; | ||
| 1666 | |||
| 1667 | spin_lock(&journal->j_state_lock); | ||
| 1668 | transaction = journal->j_committing_transaction; | ||
| 1669 | |||
| 1670 | if (!transaction) { | ||
| 1671 | spin_unlock(&journal->j_state_lock); | ||
| 1672 | return; | ||
| 1673 | } | ||
| 1674 | |||
| 1675 | tid = transaction->t_tid; | ||
| 1676 | spin_unlock(&journal->j_state_lock); | ||
| 1677 | log_wait_commit(journal, tid); | ||
| 1678 | } | ||
| 1651 | 1679 | ||
| 1652 | /** | 1680 | /** |
| 1653 | * int journal_try_to_free_buffers() - try to free page buffers. | 1681 | * int journal_try_to_free_buffers() - try to free page buffers. |
| 1654 | * @journal: journal for operation | 1682 | * @journal: journal for operation |
| 1655 | * @page: to try and free | 1683 | * @page: to try and free |
| 1656 | * @unused_gfp_mask: unused | 1684 | * @gfp_mask: we use the mask to detect how hard should we try to release |
| 1685 | * buffers. If __GFP_WAIT and __GFP_FS is set, we wait for commit code to | ||
| 1686 | * release the buffers. | ||
| 1657 | * | 1687 | * |
| 1658 | * | 1688 | * |
| 1659 | * For all the buffers on this page, | 1689 | * For all the buffers on this page, |
| @@ -1682,9 +1712,11 @@ out: | |||
| 1682 | * journal_try_to_free_buffer() is changing its state. But that | 1712 | * journal_try_to_free_buffer() is changing its state. But that |
| 1683 | * cannot happen because we never reallocate freed data as metadata | 1713 | * cannot happen because we never reallocate freed data as metadata |
| 1684 | * while the data is part of a transaction. Yes? | 1714 | * while the data is part of a transaction. Yes? |
| 1715 | * | ||
| 1716 | * Return 0 on failure, 1 on success | ||
| 1685 | */ | 1717 | */ |
| 1686 | int journal_try_to_free_buffers(journal_t *journal, | 1718 | int journal_try_to_free_buffers(journal_t *journal, |
| 1687 | struct page *page, gfp_t unused_gfp_mask) | 1719 | struct page *page, gfp_t gfp_mask) |
| 1688 | { | 1720 | { |
| 1689 | struct buffer_head *head; | 1721 | struct buffer_head *head; |
| 1690 | struct buffer_head *bh; | 1722 | struct buffer_head *bh; |
| @@ -1713,7 +1745,28 @@ int journal_try_to_free_buffers(journal_t *journal, | |||
| 1713 | if (buffer_jbd(bh)) | 1745 | if (buffer_jbd(bh)) |
| 1714 | goto busy; | 1746 | goto busy; |
| 1715 | } while ((bh = bh->b_this_page) != head); | 1747 | } while ((bh = bh->b_this_page) != head); |
| 1748 | |||
| 1716 | ret = try_to_free_buffers(page); | 1749 | ret = try_to_free_buffers(page); |
| 1750 | |||
| 1751 | /* | ||
| 1752 | * There are a number of places where journal_try_to_free_buffers() | ||
| 1753 | * could race with journal_commit_transaction(), the later still | ||
| 1754 | * holds the reference to the buffers to free while processing them. | ||
| 1755 | * try_to_free_buffers() failed to free those buffers. Some of the | ||
| 1756 | * caller of releasepage() request page buffers to be dropped, otherwise | ||
| 1757 | * treat the fail-to-free as errors (such as generic_file_direct_IO()) | ||
| 1758 | * | ||
| 1759 | * So, if the caller of try_to_release_page() wants the synchronous | ||
| 1760 | * behaviour(i.e make sure buffers are dropped upon return), | ||
| 1761 | * let's wait for the current transaction to finish flush of | ||
| 1762 | * dirty data buffers, then try to free those buffers again, | ||
| 1763 | * with the journal locked. | ||
| 1764 | */ | ||
| 1765 | if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { | ||
| 1766 | journal_wait_for_transaction_sync_data(journal); | ||
| 1767 | ret = try_to_free_buffers(page); | ||
| 1768 | } | ||
| 1769 | |||
| 1717 | busy: | 1770 | busy: |
| 1718 | return ret; | 1771 | return ret; |
| 1719 | } | 1772 | } |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index f8b3be873226..f2ad061e95ec 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
| @@ -67,7 +67,7 @@ static void release_buffer_page(struct buffer_head *bh) | |||
| 67 | goto nope; | 67 | goto nope; |
| 68 | 68 | ||
| 69 | /* OK, it's a truncated page */ | 69 | /* OK, it's a truncated page */ |
| 70 | if (TestSetPageLocked(page)) | 70 | if (!trylock_page(page)) |
| 71 | goto nope; | 71 | goto nope; |
| 72 | 72 | ||
| 73 | page_cache_get(page); | 73 | page_cache_get(page); |
| @@ -262,8 +262,18 @@ static int journal_finish_inode_data_buffers(journal_t *journal, | |||
| 262 | jinode->i_flags |= JI_COMMIT_RUNNING; | 262 | jinode->i_flags |= JI_COMMIT_RUNNING; |
| 263 | spin_unlock(&journal->j_list_lock); | 263 | spin_unlock(&journal->j_list_lock); |
| 264 | err = filemap_fdatawait(jinode->i_vfs_inode->i_mapping); | 264 | err = filemap_fdatawait(jinode->i_vfs_inode->i_mapping); |
| 265 | if (!ret) | 265 | if (err) { |
| 266 | ret = err; | 266 | /* |
| 267 | * Because AS_EIO is cleared by | ||
| 268 | * wait_on_page_writeback_range(), set it again so | ||
| 269 | * that user process can get -EIO from fsync(). | ||
| 270 | */ | ||
| 271 | set_bit(AS_EIO, | ||
| 272 | &jinode->i_vfs_inode->i_mapping->flags); | ||
| 273 | |||
| 274 | if (!ret) | ||
| 275 | ret = err; | ||
| 276 | } | ||
| 267 | spin_lock(&journal->j_list_lock); | 277 | spin_lock(&journal->j_list_lock); |
| 268 | jinode->i_flags &= ~JI_COMMIT_RUNNING; | 278 | jinode->i_flags &= ~JI_COMMIT_RUNNING; |
| 269 | wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); | 279 | wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); |
| @@ -670,8 +680,14 @@ start_journal_io: | |||
| 670 | * commit block, which happens below in such setting. | 680 | * commit block, which happens below in such setting. |
| 671 | */ | 681 | */ |
| 672 | err = journal_finish_inode_data_buffers(journal, commit_transaction); | 682 | err = journal_finish_inode_data_buffers(journal, commit_transaction); |
| 673 | if (err) | 683 | if (err) { |
| 674 | jbd2_journal_abort(journal, err); | 684 | char b[BDEVNAME_SIZE]; |
| 685 | |||
| 686 | printk(KERN_WARNING | ||
| 687 | "JBD2: Detected IO errors while flushing file data " | ||
| 688 | "on %s\n", bdevname(journal->j_fs_dev, b)); | ||
| 689 | err = 0; | ||
| 690 | } | ||
| 675 | 691 | ||
| 676 | /* Lo and behold: we have just managed to send a transaction to | 692 | /* Lo and behold: we have just managed to send a transaction to |
| 677 | the log. Before we can commit it, wait for the IO so far to | 693 | the log. Before we can commit it, wait for the IO so far to |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index b26c6d9fe6ae..8207a01c4edb 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
| @@ -68,7 +68,6 @@ EXPORT_SYMBOL(jbd2_journal_set_features); | |||
| 68 | EXPORT_SYMBOL(jbd2_journal_create); | 68 | EXPORT_SYMBOL(jbd2_journal_create); |
| 69 | EXPORT_SYMBOL(jbd2_journal_load); | 69 | EXPORT_SYMBOL(jbd2_journal_load); |
| 70 | EXPORT_SYMBOL(jbd2_journal_destroy); | 70 | EXPORT_SYMBOL(jbd2_journal_destroy); |
| 71 | EXPORT_SYMBOL(jbd2_journal_update_superblock); | ||
| 72 | EXPORT_SYMBOL(jbd2_journal_abort); | 71 | EXPORT_SYMBOL(jbd2_journal_abort); |
| 73 | EXPORT_SYMBOL(jbd2_journal_errno); | 72 | EXPORT_SYMBOL(jbd2_journal_errno); |
| 74 | EXPORT_SYMBOL(jbd2_journal_ack_err); | 73 | EXPORT_SYMBOL(jbd2_journal_ack_err); |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 4f7cadbb19fa..e5d540588fa9 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
| @@ -301,7 +301,7 @@ handle_t *jbd2_journal_start(journal_t *journal, int nblocks) | |||
| 301 | goto out; | 301 | goto out; |
| 302 | } | 302 | } |
| 303 | 303 | ||
| 304 | lock_acquire(&handle->h_lockdep_map, 0, 0, 0, 2, _THIS_IP_); | 304 | lock_map_acquire(&handle->h_lockdep_map); |
| 305 | out: | 305 | out: |
| 306 | return handle; | 306 | return handle; |
| 307 | } | 307 | } |
| @@ -1279,7 +1279,7 @@ int jbd2_journal_stop(handle_t *handle) | |||
| 1279 | spin_unlock(&journal->j_state_lock); | 1279 | spin_unlock(&journal->j_state_lock); |
| 1280 | } | 1280 | } |
| 1281 | 1281 | ||
| 1282 | lock_release(&handle->h_lockdep_map, 1, _THIS_IP_); | 1282 | lock_map_release(&handle->h_lockdep_map); |
| 1283 | 1283 | ||
| 1284 | jbd2_free_handle(handle); | 1284 | jbd2_free_handle(handle); |
| 1285 | return err; | 1285 | return err; |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 4c80404a9aba..d98713777a1b 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
| @@ -314,7 +314,7 @@ static int jffs2_check_acl(struct inode *inode, int mask) | |||
| 314 | return -EAGAIN; | 314 | return -EAGAIN; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd) | 317 | int jffs2_permission(struct inode *inode, int mask) |
| 318 | { | 318 | { |
| 319 | return generic_permission(inode, mask, jffs2_check_acl); | 319 | return generic_permission(inode, mask, jffs2_check_acl); |
| 320 | } | 320 | } |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 0bb7f003fd80..8ca058aed384 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
| @@ -28,7 +28,7 @@ struct jffs2_acl_header { | |||
| 28 | 28 | ||
| 29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) | 29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) |
| 30 | 30 | ||
| 31 | extern int jffs2_permission(struct inode *, int, struct nameidata *); | 31 | extern int jffs2_permission(struct inode *, int); |
| 32 | extern int jffs2_acl_chmod(struct inode *); | 32 | extern int jffs2_acl_chmod(struct inode *); |
| 33 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); | 33 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); |
| 34 | extern int jffs2_init_acl_post(struct inode *); | 34 | extern int jffs2_init_acl_post(struct inode *); |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index c0c141f6fde1..cd219ef55254 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
| @@ -38,7 +38,7 @@ const struct file_operations jffs2_dir_operations = | |||
| 38 | { | 38 | { |
| 39 | .read = generic_read_dir, | 39 | .read = generic_read_dir, |
| 40 | .readdir = jffs2_readdir, | 40 | .readdir = jffs2_readdir, |
| 41 | .ioctl = jffs2_ioctl, | 41 | .unlocked_ioctl=jffs2_ioctl, |
| 42 | .fsync = jffs2_fsync | 42 | .fsync = jffs2_fsync |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 5e920343b2c5..5a98aa87c853 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
| @@ -46,7 +46,7 @@ const struct file_operations jffs2_file_operations = | |||
| 46 | .aio_read = generic_file_aio_read, | 46 | .aio_read = generic_file_aio_read, |
| 47 | .write = do_sync_write, | 47 | .write = do_sync_write, |
| 48 | .aio_write = generic_file_aio_write, | 48 | .aio_write = generic_file_aio_write, |
| 49 | .ioctl = jffs2_ioctl, | 49 | .unlocked_ioctl=jffs2_ioctl, |
| 50 | .mmap = generic_file_readonly_mmap, | 50 | .mmap = generic_file_readonly_mmap, |
| 51 | .fsync = jffs2_fsync, | 51 | .fsync = jffs2_fsync, |
| 52 | .splice_read = generic_file_splice_read, | 52 | .splice_read = generic_file_splice_read, |
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index e2177210f621..9d41f43e47bb 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
| 13 | #include "nodelist.h" | 13 | #include "nodelist.h" |
| 14 | 14 | ||
| 15 | int jffs2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 15 | long jffs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 16 | unsigned long arg) | ||
| 17 | { | 16 | { |
| 18 | /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which | 17 | /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which |
| 19 | will include compression support etc. */ | 18 | will include compression support etc. */ |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 31559f45fdde..4c41db91eaa4 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #ifndef _JFFS2_FS_I | 12 | #ifndef _JFFS2_FS_I |
| 13 | #define _JFFS2_FS_I | 13 | #define _JFFS2_FS_I |
| 14 | 14 | ||
| 15 | #include <linux/version.h> | ||
| 16 | #include <linux/rbtree.h> | 15 | #include <linux/rbtree.h> |
| 17 | #include <linux/posix_acl.h> | 16 | #include <linux/posix_acl.h> |
| 18 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 2cc866cf134f..5e194a5c8e29 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
| @@ -167,7 +167,7 @@ int jffs2_fsync(struct file *, struct dentry *, int); | |||
| 167 | int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); | 167 | int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); |
| 168 | 168 | ||
| 169 | /* ioctl.c */ | 169 | /* ioctl.c */ |
| 170 | int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | 170 | long jffs2_ioctl(struct file *, unsigned int, unsigned long); |
| 171 | 171 | ||
| 172 | /* symlink.c */ | 172 | /* symlink.c */ |
| 173 | extern const struct inode_operations jffs2_symlink_inode_operations; | 173 | extern const struct inode_operations jffs2_symlink_inode_operations; |
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 629af01e5ade..6caf1e1ee26d 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | 23 | ||
| 24 | int jffs2_sum_init(struct jffs2_sb_info *c) | 24 | int jffs2_sum_init(struct jffs2_sb_info *c) |
| 25 | { | 25 | { |
| 26 | uint32_t sum_size = max_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE); | ||
| 27 | |||
| 26 | c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | 28 | c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); |
| 27 | 29 | ||
| 28 | if (!c->summary) { | 30 | if (!c->summary) { |
| @@ -30,7 +32,7 @@ int jffs2_sum_init(struct jffs2_sb_info *c) | |||
| 30 | return -ENOMEM; | 32 | return -ENOMEM; |
| 31 | } | 33 | } |
| 32 | 34 | ||
| 33 | c->summary->sum_buf = vmalloc(c->sector_size); | 35 | c->summary->sum_buf = kmalloc(sum_size, GFP_KERNEL); |
| 34 | 36 | ||
| 35 | if (!c->summary->sum_buf) { | 37 | if (!c->summary->sum_buf) { |
| 36 | JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n"); | 38 | JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n"); |
| @@ -49,7 +51,7 @@ void jffs2_sum_exit(struct jffs2_sb_info *c) | |||
| 49 | 51 | ||
| 50 | jffs2_sum_disable_collecting(c->summary); | 52 | jffs2_sum_disable_collecting(c->summary); |
| 51 | 53 | ||
| 52 | vfree(c->summary->sum_buf); | 54 | kfree(c->summary->sum_buf); |
| 53 | c->summary->sum_buf = NULL; | 55 | c->summary->sum_buf = NULL; |
| 54 | 56 | ||
| 55 | kfree(c->summary); | 57 | kfree(c->summary); |
| @@ -665,7 +667,7 @@ crc_err: | |||
| 665 | /* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */ | 667 | /* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */ |
| 666 | 668 | ||
| 667 | static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 669 | static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
| 668 | uint32_t infosize, uint32_t datasize, int padsize) | 670 | uint32_t infosize, uint32_t datasize, int padsize) |
| 669 | { | 671 | { |
| 670 | struct jffs2_raw_summary isum; | 672 | struct jffs2_raw_summary isum; |
| 671 | union jffs2_sum_mem *temp; | 673 | union jffs2_sum_mem *temp; |
| @@ -676,6 +678,26 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
| 676 | int ret; | 678 | int ret; |
| 677 | size_t retlen; | 679 | size_t retlen; |
| 678 | 680 | ||
| 681 | if (padsize + datasize > MAX_SUMMARY_SIZE) { | ||
| 682 | /* It won't fit in the buffer. Abort summary for this jeb */ | ||
| 683 | jffs2_sum_disable_collecting(c->summary); | ||
| 684 | |||
| 685 | JFFS2_WARNING("Summary too big (%d data, %d pad) in eraseblock at %08x\n", | ||
| 686 | datasize, padsize, jeb->offset); | ||
| 687 | /* Non-fatal */ | ||
| 688 | return 0; | ||
| 689 | } | ||
| 690 | /* Is there enough space for summary? */ | ||
| 691 | if (padsize < 0) { | ||
| 692 | /* don't try to write out summary for this jeb */ | ||
| 693 | jffs2_sum_disable_collecting(c->summary); | ||
| 694 | |||
| 695 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", | ||
| 696 | padsize); | ||
| 697 | /* Non-fatal */ | ||
| 698 | return 0; | ||
| 699 | } | ||
| 700 | |||
| 679 | memset(c->summary->sum_buf, 0xff, datasize); | 701 | memset(c->summary->sum_buf, 0xff, datasize); |
| 680 | memset(&isum, 0, sizeof(isum)); | 702 | memset(&isum, 0, sizeof(isum)); |
| 681 | 703 | ||
| @@ -821,7 +843,7 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | |||
| 821 | { | 843 | { |
| 822 | int datasize, infosize, padsize; | 844 | int datasize, infosize, padsize; |
| 823 | struct jffs2_eraseblock *jeb; | 845 | struct jffs2_eraseblock *jeb; |
| 824 | int ret; | 846 | int ret = 0; |
| 825 | 847 | ||
| 826 | dbg_summary("called\n"); | 848 | dbg_summary("called\n"); |
| 827 | 849 | ||
| @@ -841,16 +863,6 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | |||
| 841 | infosize += padsize; | 863 | infosize += padsize; |
| 842 | datasize += padsize; | 864 | datasize += padsize; |
| 843 | 865 | ||
| 844 | /* Is there enough space for summary? */ | ||
| 845 | if (padsize < 0) { | ||
| 846 | /* don't try to write out summary for this jeb */ | ||
| 847 | jffs2_sum_disable_collecting(c->summary); | ||
| 848 | |||
| 849 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); | ||
| 850 | spin_lock(&c->erase_completion_lock); | ||
| 851 | return 0; | ||
| 852 | } | ||
| 853 | |||
| 854 | ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); | 866 | ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); |
| 855 | spin_lock(&c->erase_completion_lock); | 867 | spin_lock(&c->erase_completion_lock); |
| 856 | return ret; | 868 | return ret; |
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index 8bf34f2fa5ce..60207a2ae952 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h | |||
| @@ -13,6 +13,12 @@ | |||
| 13 | #ifndef JFFS2_SUMMARY_H | 13 | #ifndef JFFS2_SUMMARY_H |
| 14 | #define JFFS2_SUMMARY_H | 14 | #define JFFS2_SUMMARY_H |
| 15 | 15 | ||
| 16 | /* Limit summary size to 64KiB so that we can kmalloc it. If the summary | ||
| 17 | is larger than that, we have to just ditch it and avoid using summary | ||
| 18 | for the eraseblock in question... and it probably doesn't hurt us much | ||
| 19 | anyway. */ | ||
| 20 | #define MAX_SUMMARY_SIZE 65536 | ||
| 21 | |||
| 16 | #include <linux/uio.h> | 22 | #include <linux/uio.h> |
| 17 | #include <linux/jffs2.h> | 23 | #include <linux/jffs2.h> |
| 18 | 24 | ||
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 7da69eae49e4..efd401257ed9 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
| @@ -44,7 +44,7 @@ static void jffs2_destroy_inode(struct inode *inode) | |||
| 44 | kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); | 44 | kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo) | 47 | static void jffs2_i_init_once(void *foo) |
| 48 | { | 48 | { |
| 49 | struct jffs2_inode_info *f = foo; | 49 | struct jffs2_inode_info *f = foo; |
| 50 | 50 | ||
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 4d84bdc88299..d3e5c33665de 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
| @@ -140,7 +140,7 @@ static int jfs_check_acl(struct inode *inode, int mask) | |||
| 140 | return -EAGAIN; | 140 | return -EAGAIN; |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | int jfs_permission(struct inode *inode, int mask, struct nameidata *nd) | 143 | int jfs_permission(struct inode *inode, int mask) |
| 144 | { | 144 | { |
| 145 | return generic_permission(inode, mask, jfs_check_acl); | 145 | return generic_permission(inode, mask, jfs_check_acl); |
| 146 | } | 146 | } |
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index 455fa4292045..88475f10a389 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | #ifdef CONFIG_JFS_POSIX_ACL | 21 | #ifdef CONFIG_JFS_POSIX_ACL |
| 22 | 22 | ||
| 23 | int jfs_permission(struct inode *, int, struct nameidata *); | 23 | int jfs_permission(struct inode *, int); |
| 24 | int jfs_init_acl(tid_t, struct inode *, struct inode *); | 24 | int jfs_init_acl(tid_t, struct inode *, struct inode *); |
| 25 | int jfs_setattr(struct dentry *, struct iattr *); | 25 | int jfs_setattr(struct dentry *, struct iattr *); |
| 26 | 26 | ||
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 854ff0ec574f..c350057087dd 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c | |||
| @@ -182,7 +182,7 @@ static inline void remove_metapage(struct page *page, struct metapage *mp) | |||
| 182 | 182 | ||
| 183 | #endif | 183 | #endif |
| 184 | 184 | ||
| 185 | static void init_once(struct kmem_cache *cachep, void *foo) | 185 | static void init_once(void *foo) |
| 186 | { | 186 | { |
| 187 | struct metapage *mp = (struct metapage *)foo; | 187 | struct metapage *mp = (struct metapage *)foo; |
| 188 | 188 | ||
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 0288e6d7936a..3630718be395 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include <linux/parser.h> | 22 | #include <linux/parser.h> |
| 23 | #include <linux/completion.h> | 23 | #include <linux/completion.h> |
| 24 | #include <linux/vfs.h> | 24 | #include <linux/vfs.h> |
| 25 | #include <linux/quotaops.h> | ||
| 25 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
| 26 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
| 27 | #include <linux/kthread.h> | 28 | #include <linux/kthread.h> |
| @@ -759,7 +760,7 @@ static struct file_system_type jfs_fs_type = { | |||
| 759 | .fs_flags = FS_REQUIRES_DEV, | 760 | .fs_flags = FS_REQUIRES_DEV, |
| 760 | }; | 761 | }; |
| 761 | 762 | ||
| 762 | static void init_once(struct kmem_cache *cachep, void *foo) | 763 | static void init_once(void *foo) |
| 763 | { | 764 | { |
| 764 | struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; | 765 | struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo; |
| 765 | 766 | ||
diff --git a/fs/libfs.c b/fs/libfs.c index baeb71ee1cde..1add676a19df 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -216,8 +216,8 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name, | |||
| 216 | 216 | ||
| 217 | s->s_flags = MS_NOUSER; | 217 | s->s_flags = MS_NOUSER; |
| 218 | s->s_maxbytes = ~0ULL; | 218 | s->s_maxbytes = ~0ULL; |
| 219 | s->s_blocksize = 1024; | 219 | s->s_blocksize = PAGE_SIZE; |
| 220 | s->s_blocksize_bits = 10; | 220 | s->s_blocksize_bits = PAGE_SHIFT; |
| 221 | s->s_magic = magic; | 221 | s->s_magic = magic; |
| 222 | s->s_op = ops ? ops : &simple_super_operations; | 222 | s->s_op = ops ? ops : &simple_super_operations; |
| 223 | s->s_time_gran = 1; | 223 | s->s_time_gran = 1; |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 1f6dc518505c..31668b690e03 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
| @@ -582,7 +582,15 @@ again: | |||
| 582 | } | 582 | } |
| 583 | if (status < 0) | 583 | if (status < 0) |
| 584 | goto out_unlock; | 584 | goto out_unlock; |
| 585 | status = nlm_stat_to_errno(resp->status); | 585 | /* |
| 586 | * EAGAIN doesn't make sense for sleeping locks, and in some | ||
| 587 | * cases NLM_LCK_DENIED is returned for a permanent error. So | ||
| 588 | * turn it into an ENOLCK. | ||
| 589 | */ | ||
| 590 | if (resp->status == nlm_lck_denied && (fl_flags & FL_SLEEP)) | ||
| 591 | status = -ENOLCK; | ||
| 592 | else | ||
| 593 | status = nlm_stat_to_errno(resp->status); | ||
| 586 | out_unblock: | 594 | out_unblock: |
| 587 | nlmclnt_finish_block(block); | 595 | nlmclnt_finish_block(block); |
| 588 | out: | 596 | out: |
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 399444639337..4a714f64515b 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
| @@ -83,7 +83,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
| 83 | { | 83 | { |
| 84 | struct nlm_host *host; | 84 | struct nlm_host *host; |
| 85 | struct nlm_file *file; | 85 | struct nlm_file *file; |
| 86 | int rc = rpc_success; | 86 | __be32 rc = rpc_success; |
| 87 | 87 | ||
| 88 | dprintk("lockd: TEST4 called\n"); | 88 | dprintk("lockd: TEST4 called\n"); |
| 89 | resp->cookie = argp->cookie; | 89 | resp->cookie = argp->cookie; |
| @@ -116,7 +116,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
| 116 | { | 116 | { |
| 117 | struct nlm_host *host; | 117 | struct nlm_host *host; |
| 118 | struct nlm_file *file; | 118 | struct nlm_file *file; |
| 119 | int rc = rpc_success; | 119 | __be32 rc = rpc_success; |
| 120 | 120 | ||
| 121 | dprintk("lockd: LOCK called\n"); | 121 | dprintk("lockd: LOCK called\n"); |
| 122 | 122 | ||
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 821b9acdfb66..cf0d5c2c318d 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
| @@ -418,8 +418,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
| 418 | goto out; | 418 | goto out; |
| 419 | case -EAGAIN: | 419 | case -EAGAIN: |
| 420 | ret = nlm_lck_denied; | 420 | ret = nlm_lck_denied; |
| 421 | break; | 421 | goto out; |
| 422 | case -EINPROGRESS: | 422 | case FILE_LOCK_DEFERRED: |
| 423 | if (wait) | 423 | if (wait) |
| 424 | break; | 424 | break; |
| 425 | /* Filesystem lock operation is in progress | 425 | /* Filesystem lock operation is in progress |
| @@ -434,10 +434,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
| 434 | goto out; | 434 | goto out; |
| 435 | } | 435 | } |
| 436 | 436 | ||
| 437 | ret = nlm_lck_denied; | ||
| 438 | if (!wait) | ||
| 439 | goto out; | ||
| 440 | |||
| 441 | ret = nlm_lck_blocked; | 437 | ret = nlm_lck_blocked; |
| 442 | 438 | ||
| 443 | /* Append to list of blocked */ | 439 | /* Append to list of blocked */ |
| @@ -507,7 +503,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, | |||
| 507 | } | 503 | } |
| 508 | 504 | ||
| 509 | error = vfs_test_lock(file->f_file, &lock->fl); | 505 | error = vfs_test_lock(file->f_file, &lock->fl); |
| 510 | if (error == -EINPROGRESS) { | 506 | if (error == FILE_LOCK_DEFERRED) { |
| 511 | ret = nlmsvc_defer_lock_rqst(rqstp, block); | 507 | ret = nlmsvc_defer_lock_rqst(rqstp, block); |
| 512 | goto out; | 508 | goto out; |
| 513 | } | 509 | } |
| @@ -731,8 +727,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) | |||
| 731 | switch (error) { | 727 | switch (error) { |
| 732 | case 0: | 728 | case 0: |
| 733 | break; | 729 | break; |
| 734 | case -EAGAIN: | 730 | case FILE_LOCK_DEFERRED: |
| 735 | case -EINPROGRESS: | ||
| 736 | dprintk("lockd: lock still blocked error %d\n", error); | 731 | dprintk("lockd: lock still blocked error %d\n", error); |
| 737 | nlmsvc_insert_block(block, NLM_NEVER); | 732 | nlmsvc_insert_block(block, NLM_NEVER); |
| 738 | nlmsvc_release_block(block); | 733 | nlmsvc_release_block(block); |
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 76019d2ff72d..76262c1986f2 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
| @@ -112,7 +112,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
| 112 | { | 112 | { |
| 113 | struct nlm_host *host; | 113 | struct nlm_host *host; |
| 114 | struct nlm_file *file; | 114 | struct nlm_file *file; |
| 115 | int rc = rpc_success; | 115 | __be32 rc = rpc_success; |
| 116 | 116 | ||
| 117 | dprintk("lockd: TEST called\n"); | 117 | dprintk("lockd: TEST called\n"); |
| 118 | resp->cookie = argp->cookie; | 118 | resp->cookie = argp->cookie; |
| @@ -146,7 +146,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, | |||
| 146 | { | 146 | { |
| 147 | struct nlm_host *host; | 147 | struct nlm_host *host; |
| 148 | struct nlm_file *file; | 148 | struct nlm_file *file; |
| 149 | int rc = rpc_success; | 149 | __be32 rc = rpc_success; |
| 150 | 150 | ||
| 151 | dprintk("lockd: LOCK called\n"); | 151 | dprintk("lockd: LOCK called\n"); |
| 152 | 152 | ||
diff --git a/fs/locks.c b/fs/locks.c index dce8c747371c..5eb259e3cd38 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -201,7 +201,7 @@ EXPORT_SYMBOL(locks_init_lock); | |||
| 201 | * Initialises the fields of the file lock which are invariant for | 201 | * Initialises the fields of the file lock which are invariant for |
| 202 | * free file_locks. | 202 | * free file_locks. |
| 203 | */ | 203 | */ |
| 204 | static void init_once(struct kmem_cache *cache, void *foo) | 204 | static void init_once(void *foo) |
| 205 | { | 205 | { |
| 206 | struct file_lock *lock = (struct file_lock *) foo; | 206 | struct file_lock *lock = (struct file_lock *) foo; |
| 207 | 207 | ||
| @@ -779,8 +779,10 @@ find_conflict: | |||
| 779 | if (!flock_locks_conflict(request, fl)) | 779 | if (!flock_locks_conflict(request, fl)) |
| 780 | continue; | 780 | continue; |
| 781 | error = -EAGAIN; | 781 | error = -EAGAIN; |
| 782 | if (request->fl_flags & FL_SLEEP) | 782 | if (!(request->fl_flags & FL_SLEEP)) |
| 783 | locks_insert_block(fl, request); | 783 | goto out; |
| 784 | error = FILE_LOCK_DEFERRED; | ||
| 785 | locks_insert_block(fl, request); | ||
| 784 | goto out; | 786 | goto out; |
| 785 | } | 787 | } |
| 786 | if (request->fl_flags & FL_ACCESS) | 788 | if (request->fl_flags & FL_ACCESS) |
| @@ -836,7 +838,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str | |||
| 836 | error = -EDEADLK; | 838 | error = -EDEADLK; |
| 837 | if (posix_locks_deadlock(request, fl)) | 839 | if (posix_locks_deadlock(request, fl)) |
| 838 | goto out; | 840 | goto out; |
| 839 | error = -EAGAIN; | 841 | error = FILE_LOCK_DEFERRED; |
| 840 | locks_insert_block(fl, request); | 842 | locks_insert_block(fl, request); |
| 841 | goto out; | 843 | goto out; |
| 842 | } | 844 | } |
| @@ -1035,7 +1037,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) | |||
| 1035 | might_sleep (); | 1037 | might_sleep (); |
| 1036 | for (;;) { | 1038 | for (;;) { |
| 1037 | error = posix_lock_file(filp, fl, NULL); | 1039 | error = posix_lock_file(filp, fl, NULL); |
| 1038 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) | 1040 | if (error != FILE_LOCK_DEFERRED) |
| 1039 | break; | 1041 | break; |
| 1040 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | 1042 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
| 1041 | if (!error) | 1043 | if (!error) |
| @@ -1107,9 +1109,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, | |||
| 1107 | 1109 | ||
| 1108 | for (;;) { | 1110 | for (;;) { |
| 1109 | error = __posix_lock_file(inode, &fl, NULL); | 1111 | error = __posix_lock_file(inode, &fl, NULL); |
| 1110 | if (error != -EAGAIN) | 1112 | if (error != FILE_LOCK_DEFERRED) |
| 1111 | break; | ||
| 1112 | if (!(fl.fl_flags & FL_SLEEP)) | ||
| 1113 | break; | 1113 | break; |
| 1114 | error = wait_event_interruptible(fl.fl_wait, !fl.fl_next); | 1114 | error = wait_event_interruptible(fl.fl_wait, !fl.fl_next); |
| 1115 | if (!error) { | 1115 | if (!error) { |
| @@ -1531,7 +1531,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl) | |||
| 1531 | might_sleep(); | 1531 | might_sleep(); |
| 1532 | for (;;) { | 1532 | for (;;) { |
| 1533 | error = flock_lock_file(filp, fl); | 1533 | error = flock_lock_file(filp, fl); |
| 1534 | if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) | 1534 | if (error != FILE_LOCK_DEFERRED) |
| 1535 | break; | 1535 | break; |
| 1536 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | 1536 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); |
| 1537 | if (!error) | 1537 | if (!error) |
| @@ -1716,17 +1716,17 @@ out: | |||
| 1716 | * fl_grant is set. Callers expecting ->lock() to return asynchronously | 1716 | * fl_grant is set. Callers expecting ->lock() to return asynchronously |
| 1717 | * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) | 1717 | * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) |
| 1718 | * the request is for a blocking lock. When ->lock() does return asynchronously, | 1718 | * the request is for a blocking lock. When ->lock() does return asynchronously, |
| 1719 | * it must return -EINPROGRESS, and call ->fl_grant() when the lock | 1719 | * it must return FILE_LOCK_DEFERRED, and call ->fl_grant() when the lock |
| 1720 | * request completes. | 1720 | * request completes. |
| 1721 | * If the request is for non-blocking lock the file system should return | 1721 | * If the request is for non-blocking lock the file system should return |
| 1722 | * -EINPROGRESS then try to get the lock and call the callback routine with | 1722 | * FILE_LOCK_DEFERRED then try to get the lock and call the callback routine |
| 1723 | * the result. If the request timed out the callback routine will return a | 1723 | * with the result. If the request timed out the callback routine will return a |
| 1724 | * nonzero return code and the file system should release the lock. The file | 1724 | * nonzero return code and the file system should release the lock. The file |
| 1725 | * system is also responsible to keep a corresponding posix lock when it | 1725 | * system is also responsible to keep a corresponding posix lock when it |
| 1726 | * grants a lock so the VFS can find out which locks are locally held and do | 1726 | * grants a lock so the VFS can find out which locks are locally held and do |
| 1727 | * the correct lock cleanup when required. | 1727 | * the correct lock cleanup when required. |
| 1728 | * The underlying filesystem must not drop the kernel lock or call | 1728 | * The underlying filesystem must not drop the kernel lock or call |
| 1729 | * ->fl_grant() before returning to the caller with a -EINPROGRESS | 1729 | * ->fl_grant() before returning to the caller with a FILE_LOCK_DEFERRED |
| 1730 | * return code. | 1730 | * return code. |
| 1731 | */ | 1731 | */ |
| 1732 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) | 1732 | int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) |
| @@ -1738,6 +1738,30 @@ int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, str | |||
| 1738 | } | 1738 | } |
| 1739 | EXPORT_SYMBOL_GPL(vfs_lock_file); | 1739 | EXPORT_SYMBOL_GPL(vfs_lock_file); |
| 1740 | 1740 | ||
| 1741 | static int do_lock_file_wait(struct file *filp, unsigned int cmd, | ||
| 1742 | struct file_lock *fl) | ||
| 1743 | { | ||
| 1744 | int error; | ||
| 1745 | |||
| 1746 | error = security_file_lock(filp, fl->fl_type); | ||
| 1747 | if (error) | ||
| 1748 | return error; | ||
| 1749 | |||
| 1750 | for (;;) { | ||
| 1751 | error = vfs_lock_file(filp, cmd, fl, NULL); | ||
| 1752 | if (error != FILE_LOCK_DEFERRED) | ||
| 1753 | break; | ||
| 1754 | error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); | ||
| 1755 | if (!error) | ||
| 1756 | continue; | ||
| 1757 | |||
| 1758 | locks_delete_block(fl); | ||
| 1759 | break; | ||
| 1760 | } | ||
| 1761 | |||
| 1762 | return error; | ||
| 1763 | } | ||
| 1764 | |||
| 1741 | /* Apply the lock described by l to an open file descriptor. | 1765 | /* Apply the lock described by l to an open file descriptor. |
| 1742 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). | 1766 | * This implements both the F_SETLK and F_SETLKW commands of fcntl(). |
| 1743 | */ | 1767 | */ |
| @@ -1795,26 +1819,7 @@ again: | |||
| 1795 | goto out; | 1819 | goto out; |
| 1796 | } | 1820 | } |
| 1797 | 1821 | ||
| 1798 | error = security_file_lock(filp, file_lock->fl_type); | 1822 | error = do_lock_file_wait(filp, cmd, file_lock); |
| 1799 | if (error) | ||
| 1800 | goto out; | ||
| 1801 | |||
| 1802 | if (filp->f_op && filp->f_op->lock != NULL) | ||
| 1803 | error = filp->f_op->lock(filp, cmd, file_lock); | ||
| 1804 | else { | ||
| 1805 | for (;;) { | ||
| 1806 | error = posix_lock_file(filp, file_lock, NULL); | ||
| 1807 | if (error != -EAGAIN || cmd == F_SETLK) | ||
| 1808 | break; | ||
| 1809 | error = wait_event_interruptible(file_lock->fl_wait, | ||
| 1810 | !file_lock->fl_next); | ||
| 1811 | if (!error) | ||
| 1812 | continue; | ||
| 1813 | |||
| 1814 | locks_delete_block(file_lock); | ||
| 1815 | break; | ||
| 1816 | } | ||
| 1817 | } | ||
| 1818 | 1823 | ||
| 1819 | /* | 1824 | /* |
| 1820 | * Attempt to detect a close/fcntl race and recover by | 1825 | * Attempt to detect a close/fcntl race and recover by |
| @@ -1932,26 +1937,7 @@ again: | |||
| 1932 | goto out; | 1937 | goto out; |
| 1933 | } | 1938 | } |
| 1934 | 1939 | ||
| 1935 | error = security_file_lock(filp, file_lock->fl_type); | 1940 | error = do_lock_file_wait(filp, cmd, file_lock); |
| 1936 | if (error) | ||
| 1937 | goto out; | ||
| 1938 | |||
| 1939 | if (filp->f_op && filp->f_op->lock != NULL) | ||
| 1940 | error = filp->f_op->lock(filp, cmd, file_lock); | ||
| 1941 | else { | ||
| 1942 | for (;;) { | ||
| 1943 | error = posix_lock_file(filp, file_lock, NULL); | ||
| 1944 | if (error != -EAGAIN || cmd == F_SETLK64) | ||
| 1945 | break; | ||
| 1946 | error = wait_event_interruptible(file_lock->fl_wait, | ||
| 1947 | !file_lock->fl_next); | ||
| 1948 | if (!error) | ||
| 1949 | continue; | ||
| 1950 | |||
| 1951 | locks_delete_block(file_lock); | ||
| 1952 | break; | ||
| 1953 | } | ||
| 1954 | } | ||
| 1955 | 1941 | ||
| 1956 | /* | 1942 | /* |
| 1957 | * Attempt to detect a close/fcntl race and recover by | 1943 | * Attempt to detect a close/fcntl race and recover by |
diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 84f6242ba6fc..d1d1eb84679d 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c | |||
| @@ -68,7 +68,7 @@ static void minix_destroy_inode(struct inode *inode) | |||
| 68 | kmem_cache_free(minix_inode_cachep, minix_i(inode)); | 68 | kmem_cache_free(minix_inode_cachep, minix_i(inode)); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static void init_once(struct kmem_cache * cachep, void *foo) | 71 | static void init_once(void *foo) |
| 72 | { | 72 | { |
| 73 | struct minix_inode_info *ei = (struct minix_inode_info *) foo; | 73 | struct minix_inode_info *ei = (struct minix_inode_info *) foo; |
| 74 | 74 | ||
| @@ -256,9 +256,6 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) | |||
| 256 | if (!s->s_root) | 256 | if (!s->s_root) |
| 257 | goto out_iput; | 257 | goto out_iput; |
| 258 | 258 | ||
| 259 | if (!NO_TRUNCATE) | ||
| 260 | s->s_root->d_op = &minix_dentry_operations; | ||
| 261 | |||
| 262 | if (!(s->s_flags & MS_RDONLY)) { | 259 | if (!(s->s_flags & MS_RDONLY)) { |
| 263 | if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ | 260 | if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ |
| 264 | ms->s_state &= ~MINIX_VALID_FS; | 261 | ms->s_state &= ~MINIX_VALID_FS; |
diff --git a/fs/minix/minix.h b/fs/minix/minix.h index 326edfe96108..e6a0b193bea4 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h | |||
| @@ -2,11 +2,6 @@ | |||
| 2 | #include <linux/pagemap.h> | 2 | #include <linux/pagemap.h> |
| 3 | #include <linux/minix_fs.h> | 3 | #include <linux/minix_fs.h> |
| 4 | 4 | ||
| 5 | /* | ||
| 6 | * change the define below to 0 if you want names > info->s_namelen chars to be | ||
| 7 | * truncated. Else they will be disallowed (ENAMETOOLONG). | ||
| 8 | */ | ||
| 9 | #define NO_TRUNCATE 1 | ||
| 10 | #define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version | 5 | #define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version |
| 11 | #define MINIX_V1 0x0001 /* original minix fs */ | 6 | #define MINIX_V1 0x0001 /* original minix fs */ |
| 12 | #define MINIX_V2 0x0002 /* minix V2 fs */ | 7 | #define MINIX_V2 0x0002 /* minix V2 fs */ |
| @@ -83,7 +78,6 @@ extern const struct inode_operations minix_file_inode_operations; | |||
| 83 | extern const struct inode_operations minix_dir_inode_operations; | 78 | extern const struct inode_operations minix_dir_inode_operations; |
| 84 | extern const struct file_operations minix_file_operations; | 79 | extern const struct file_operations minix_file_operations; |
| 85 | extern const struct file_operations minix_dir_operations; | 80 | extern const struct file_operations minix_dir_operations; |
| 86 | extern struct dentry_operations minix_dentry_operations; | ||
| 87 | 81 | ||
| 88 | static inline struct minix_sb_info *minix_sb(struct super_block *sb) | 82 | static inline struct minix_sb_info *minix_sb(struct super_block *sb) |
| 89 | { | 83 | { |
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 102241bc9c79..32b131cd6121 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c | |||
| @@ -18,30 +18,6 @@ static int add_nondir(struct dentry *dentry, struct inode *inode) | |||
| 18 | return err; | 18 | return err; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | static int minix_hash(struct dentry *dentry, struct qstr *qstr) | ||
| 22 | { | ||
| 23 | unsigned long hash; | ||
| 24 | int i; | ||
| 25 | const unsigned char *name; | ||
| 26 | |||
| 27 | i = minix_sb(dentry->d_inode->i_sb)->s_namelen; | ||
| 28 | if (i >= qstr->len) | ||
| 29 | return 0; | ||
| 30 | /* Truncate the name in place, avoids having to define a compare | ||
| 31 | function. */ | ||
| 32 | qstr->len = i; | ||
| 33 | name = qstr->name; | ||
| 34 | hash = init_name_hash(); | ||
| 35 | while (i--) | ||
| 36 | hash = partial_name_hash(*name++, hash); | ||
| 37 | qstr->hash = end_name_hash(hash); | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | struct dentry_operations minix_dentry_operations = { | ||
| 42 | .d_hash = minix_hash, | ||
| 43 | }; | ||
| 44 | |||
| 45 | static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) | 21 | static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd) |
| 46 | { | 22 | { |
| 47 | struct inode * inode = NULL; | 23 | struct inode * inode = NULL; |
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 1f7f2956412a..e844b9809d27 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c | |||
| @@ -14,12 +14,7 @@ | |||
| 14 | 14 | ||
| 15 | /* Characters that are undesirable in an MS-DOS file name */ | 15 | /* Characters that are undesirable in an MS-DOS file name */ |
| 16 | static unsigned char bad_chars[] = "*?<>|\""; | 16 | static unsigned char bad_chars[] = "*?<>|\""; |
| 17 | static unsigned char bad_if_strict_pc[] = "+=,; "; | 17 | static unsigned char bad_if_strict[] = "+=,; "; |
| 18 | /* GEMDOS is less restrictive */ | ||
| 19 | static unsigned char bad_if_strict_atari[] = " "; | ||
| 20 | |||
| 21 | #define bad_if_strict(opts) \ | ||
| 22 | ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc) | ||
| 23 | 18 | ||
| 24 | /***** Formats an MS-DOS file name. Rejects invalid names. */ | 19 | /***** Formats an MS-DOS file name. Rejects invalid names. */ |
| 25 | static int msdos_format_name(const unsigned char *name, int len, | 20 | static int msdos_format_name(const unsigned char *name, int len, |
| @@ -40,21 +35,20 @@ static int msdos_format_name(const unsigned char *name, int len, | |||
| 40 | /* Get rid of dot - test for it elsewhere */ | 35 | /* Get rid of dot - test for it elsewhere */ |
| 41 | name++; | 36 | name++; |
| 42 | len--; | 37 | len--; |
| 43 | } else if (!opts->atari) | 38 | } else |
| 44 | return -EINVAL; | 39 | return -EINVAL; |
| 45 | } | 40 | } |
| 46 | /* | 41 | /* |
| 47 | * disallow names that _really_ start with a dot for MS-DOS, | 42 | * disallow names that _really_ start with a dot |
| 48 | * GEMDOS does not care | ||
| 49 | */ | 43 | */ |
| 50 | space = !opts->atari; | 44 | space = 1; |
| 51 | c = 0; | 45 | c = 0; |
| 52 | for (walk = res; len && walk - res < 8; walk++) { | 46 | for (walk = res; len && walk - res < 8; walk++) { |
| 53 | c = *name++; | 47 | c = *name++; |
| 54 | len--; | 48 | len--; |
| 55 | if (opts->name_check != 'r' && strchr(bad_chars, c)) | 49 | if (opts->name_check != 'r' && strchr(bad_chars, c)) |
| 56 | return -EINVAL; | 50 | return -EINVAL; |
| 57 | if (opts->name_check == 's' && strchr(bad_if_strict(opts), c)) | 51 | if (opts->name_check == 's' && strchr(bad_if_strict, c)) |
| 58 | return -EINVAL; | 52 | return -EINVAL; |
| 59 | if (c >= 'A' && c <= 'Z' && opts->name_check == 's') | 53 | if (c >= 'A' && c <= 'Z' && opts->name_check == 's') |
| 60 | return -EINVAL; | 54 | return -EINVAL; |
| @@ -94,7 +88,7 @@ static int msdos_format_name(const unsigned char *name, int len, | |||
| 94 | if (opts->name_check != 'r' && strchr(bad_chars, c)) | 88 | if (opts->name_check != 'r' && strchr(bad_chars, c)) |
| 95 | return -EINVAL; | 89 | return -EINVAL; |
| 96 | if (opts->name_check == 's' && | 90 | if (opts->name_check == 's' && |
| 97 | strchr(bad_if_strict(opts), c)) | 91 | strchr(bad_if_strict, c)) |
| 98 | return -EINVAL; | 92 | return -EINVAL; |
| 99 | if (c < ' ' || c == ':' || c == '\\') | 93 | if (c < ' ' || c == ':' || c == '\\') |
| 100 | return -EINVAL; | 94 | return -EINVAL; |
| @@ -243,6 +237,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name, | |||
| 243 | int is_dir, int is_hid, int cluster, | 237 | int is_dir, int is_hid, int cluster, |
| 244 | struct timespec *ts, struct fat_slot_info *sinfo) | 238 | struct timespec *ts, struct fat_slot_info *sinfo) |
| 245 | { | 239 | { |
| 240 | struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); | ||
| 246 | struct msdos_dir_entry de; | 241 | struct msdos_dir_entry de; |
| 247 | __le16 time, date; | 242 | __le16 time, date; |
| 248 | int err; | 243 | int err; |
| @@ -252,7 +247,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name, | |||
| 252 | if (is_hid) | 247 | if (is_hid) |
| 253 | de.attr |= ATTR_HIDDEN; | 248 | de.attr |= ATTR_HIDDEN; |
| 254 | de.lcase = 0; | 249 | de.lcase = 0; |
| 255 | fat_date_unix2dos(ts->tv_sec, &time, &date); | 250 | fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); |
| 256 | de.cdate = de.adate = 0; | 251 | de.cdate = de.adate = 0; |
| 257 | de.ctime = 0; | 252 | de.ctime = 0; |
| 258 | de.ctime_cs = 0; | 253 | de.ctime_cs = 0; |
diff --git a/fs/namei.c b/fs/namei.c index 01e67dddcc3d..4ea63ed5e791 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | #include <linux/file.h> | 31 | #include <linux/file.h> |
| 32 | #include <linux/fcntl.h> | 32 | #include <linux/fcntl.h> |
| 33 | #include <linux/device_cgroup.h> | 33 | #include <linux/device_cgroup.h> |
| 34 | #include <asm/namei.h> | ||
| 35 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
| 36 | 35 | ||
| 37 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) | 36 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) |
| @@ -185,6 +184,8 @@ int generic_permission(struct inode *inode, int mask, | |||
| 185 | { | 184 | { |
| 186 | umode_t mode = inode->i_mode; | 185 | umode_t mode = inode->i_mode; |
| 187 | 186 | ||
| 187 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | ||
| 188 | |||
| 188 | if (current->fsuid == inode->i_uid) | 189 | if (current->fsuid == inode->i_uid) |
| 189 | mode >>= 6; | 190 | mode >>= 6; |
| 190 | else { | 191 | else { |
| @@ -203,7 +204,7 @@ int generic_permission(struct inode *inode, int mask, | |||
| 203 | /* | 204 | /* |
| 204 | * If the DACs are ok we don't need any capability check. | 205 | * If the DACs are ok we don't need any capability check. |
| 205 | */ | 206 | */ |
| 206 | if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask)) | 207 | if ((mask & ~mode) == 0) |
| 207 | return 0; | 208 | return 0; |
| 208 | 209 | ||
| 209 | check_capabilities: | 210 | check_capabilities: |
| @@ -226,13 +227,9 @@ int generic_permission(struct inode *inode, int mask, | |||
| 226 | return -EACCES; | 227 | return -EACCES; |
| 227 | } | 228 | } |
| 228 | 229 | ||
| 229 | int permission(struct inode *inode, int mask, struct nameidata *nd) | 230 | int inode_permission(struct inode *inode, int mask) |
| 230 | { | 231 | { |
| 231 | int retval, submask; | 232 | int retval; |
| 232 | struct vfsmount *mnt = NULL; | ||
| 233 | |||
| 234 | if (nd) | ||
| 235 | mnt = nd->path.mnt; | ||
| 236 | 233 | ||
| 237 | if (mask & MAY_WRITE) { | 234 | if (mask & MAY_WRITE) { |
| 238 | umode_t mode = inode->i_mode; | 235 | umode_t mode = inode->i_mode; |
| @@ -251,19 +248,9 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 251 | return -EACCES; | 248 | return -EACCES; |
| 252 | } | 249 | } |
| 253 | 250 | ||
| 254 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { | ||
| 255 | /* | ||
| 256 | * MAY_EXEC on regular files is denied if the fs is mounted | ||
| 257 | * with the "noexec" flag. | ||
| 258 | */ | ||
| 259 | if (mnt && (mnt->mnt_flags & MNT_NOEXEC)) | ||
| 260 | return -EACCES; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* Ordinary permission routines do not understand MAY_APPEND. */ | 251 | /* Ordinary permission routines do not understand MAY_APPEND. */ |
| 264 | submask = mask & ~MAY_APPEND; | ||
| 265 | if (inode->i_op && inode->i_op->permission) { | 252 | if (inode->i_op && inode->i_op->permission) { |
| 266 | retval = inode->i_op->permission(inode, submask, nd); | 253 | retval = inode->i_op->permission(inode, mask); |
| 267 | if (!retval) { | 254 | if (!retval) { |
| 268 | /* | 255 | /* |
| 269 | * Exec permission on a regular file is denied if none | 256 | * Exec permission on a regular file is denied if none |
| @@ -277,7 +264,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 277 | return -EACCES; | 264 | return -EACCES; |
| 278 | } | 265 | } |
| 279 | } else { | 266 | } else { |
| 280 | retval = generic_permission(inode, submask, NULL); | 267 | retval = generic_permission(inode, mask, NULL); |
| 281 | } | 268 | } |
| 282 | if (retval) | 269 | if (retval) |
| 283 | return retval; | 270 | return retval; |
| @@ -286,7 +273,8 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 286 | if (retval) | 273 | if (retval) |
| 287 | return retval; | 274 | return retval; |
| 288 | 275 | ||
| 289 | return security_inode_permission(inode, mask, nd); | 276 | return security_inode_permission(inode, |
| 277 | mask & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND)); | ||
| 290 | } | 278 | } |
| 291 | 279 | ||
| 292 | /** | 280 | /** |
| @@ -301,7 +289,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 301 | */ | 289 | */ |
| 302 | int vfs_permission(struct nameidata *nd, int mask) | 290 | int vfs_permission(struct nameidata *nd, int mask) |
| 303 | { | 291 | { |
| 304 | return permission(nd->path.dentry->d_inode, mask, nd); | 292 | return inode_permission(nd->path.dentry->d_inode, mask); |
| 305 | } | 293 | } |
| 306 | 294 | ||
| 307 | /** | 295 | /** |
| @@ -318,7 +306,7 @@ int vfs_permission(struct nameidata *nd, int mask) | |||
| 318 | */ | 306 | */ |
| 319 | int file_permission(struct file *file, int mask) | 307 | int file_permission(struct file *file, int mask) |
| 320 | { | 308 | { |
| 321 | return permission(file->f_path.dentry->d_inode, mask, NULL); | 309 | return inode_permission(file->f_path.dentry->d_inode, mask); |
| 322 | } | 310 | } |
| 323 | 311 | ||
| 324 | /* | 312 | /* |
| @@ -459,8 +447,7 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, | |||
| 459 | * short-cut DAC fails, then call permission() to do more | 447 | * short-cut DAC fails, then call permission() to do more |
| 460 | * complete permission check. | 448 | * complete permission check. |
| 461 | */ | 449 | */ |
| 462 | static int exec_permission_lite(struct inode *inode, | 450 | static int exec_permission_lite(struct inode *inode) |
| 463 | struct nameidata *nd) | ||
| 464 | { | 451 | { |
| 465 | umode_t mode = inode->i_mode; | 452 | umode_t mode = inode->i_mode; |
| 466 | 453 | ||
| @@ -486,7 +473,7 @@ static int exec_permission_lite(struct inode *inode, | |||
| 486 | 473 | ||
| 487 | return -EACCES; | 474 | return -EACCES; |
| 488 | ok: | 475 | ok: |
| 489 | return security_inode_permission(inode, MAY_EXEC, nd); | 476 | return security_inode_permission(inode, MAY_EXEC); |
| 490 | } | 477 | } |
| 491 | 478 | ||
| 492 | /* | 479 | /* |
| @@ -519,7 +506,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 519 | */ | 506 | */ |
| 520 | result = d_lookup(parent, name); | 507 | result = d_lookup(parent, name); |
| 521 | if (!result) { | 508 | if (!result) { |
| 522 | struct dentry * dentry = d_alloc(parent, name); | 509 | struct dentry *dentry; |
| 510 | |||
| 511 | /* Don't create child dentry for a dead directory. */ | ||
| 512 | result = ERR_PTR(-ENOENT); | ||
| 513 | if (IS_DEADDIR(dir)) | ||
| 514 | goto out_unlock; | ||
| 515 | |||
| 516 | dentry = d_alloc(parent, name); | ||
| 523 | result = ERR_PTR(-ENOMEM); | 517 | result = ERR_PTR(-ENOMEM); |
| 524 | if (dentry) { | 518 | if (dentry) { |
| 525 | result = dir->i_op->lookup(dir, dentry, nd); | 519 | result = dir->i_op->lookup(dir, dentry, nd); |
| @@ -528,6 +522,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 528 | else | 522 | else |
| 529 | result = dentry; | 523 | result = dentry; |
| 530 | } | 524 | } |
| 525 | out_unlock: | ||
| 531 | mutex_unlock(&dir->i_mutex); | 526 | mutex_unlock(&dir->i_mutex); |
| 532 | return result; | 527 | return result; |
| 533 | } | 528 | } |
| @@ -545,27 +540,16 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s | |||
| 545 | return result; | 540 | return result; |
| 546 | } | 541 | } |
| 547 | 542 | ||
| 548 | static int __emul_lookup_dentry(const char *, struct nameidata *); | ||
| 549 | |||
| 550 | /* SMP-safe */ | 543 | /* SMP-safe */ |
| 551 | static __always_inline int | 544 | static __always_inline void |
| 552 | walk_init_root(const char *name, struct nameidata *nd) | 545 | walk_init_root(const char *name, struct nameidata *nd) |
| 553 | { | 546 | { |
| 554 | struct fs_struct *fs = current->fs; | 547 | struct fs_struct *fs = current->fs; |
| 555 | 548 | ||
| 556 | read_lock(&fs->lock); | 549 | read_lock(&fs->lock); |
| 557 | if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) { | ||
| 558 | nd->path = fs->altroot; | ||
| 559 | path_get(&fs->altroot); | ||
| 560 | read_unlock(&fs->lock); | ||
| 561 | if (__emul_lookup_dentry(name,nd)) | ||
| 562 | return 0; | ||
| 563 | read_lock(&fs->lock); | ||
| 564 | } | ||
| 565 | nd->path = fs->root; | 550 | nd->path = fs->root; |
| 566 | path_get(&fs->root); | 551 | path_get(&fs->root); |
| 567 | read_unlock(&fs->lock); | 552 | read_unlock(&fs->lock); |
| 568 | return 1; | ||
| 569 | } | 553 | } |
| 570 | 554 | ||
| 571 | /* | 555 | /* |
| @@ -606,12 +590,9 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l | |||
| 606 | 590 | ||
| 607 | if (*link == '/') { | 591 | if (*link == '/') { |
| 608 | path_put(&nd->path); | 592 | path_put(&nd->path); |
| 609 | if (!walk_init_root(link, nd)) | 593 | walk_init_root(link, nd); |
| 610 | /* weird __emul_prefix() stuff did it */ | ||
| 611 | goto out; | ||
| 612 | } | 594 | } |
| 613 | res = link_path_walk(link, nd); | 595 | res = link_path_walk(link, nd); |
| 614 | out: | ||
| 615 | if (nd->depth || res || nd->last_type!=LAST_NORM) | 596 | if (nd->depth || res || nd->last_type!=LAST_NORM) |
| 616 | return res; | 597 | return res; |
| 617 | /* | 598 | /* |
| @@ -889,7 +870,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd) | |||
| 889 | unsigned int c; | 870 | unsigned int c; |
| 890 | 871 | ||
| 891 | nd->flags |= LOOKUP_CONTINUE; | 872 | nd->flags |= LOOKUP_CONTINUE; |
| 892 | err = exec_permission_lite(inode, nd); | 873 | err = exec_permission_lite(inode); |
| 893 | if (err == -EAGAIN) | 874 | if (err == -EAGAIN) |
| 894 | err = vfs_permission(nd, MAY_EXEC); | 875 | err = vfs_permission(nd, MAY_EXEC); |
| 895 | if (err) | 876 | if (err) |
| @@ -1060,67 +1041,6 @@ static int path_walk(const char *name, struct nameidata *nd) | |||
| 1060 | return link_path_walk(name, nd); | 1041 | return link_path_walk(name, nd); |
| 1061 | } | 1042 | } |
| 1062 | 1043 | ||
| 1063 | /* | ||
| 1064 | * SMP-safe: Returns 1 and nd will have valid dentry and mnt, if | ||
| 1065 | * everything is done. Returns 0 and drops input nd, if lookup failed; | ||
| 1066 | */ | ||
| 1067 | static int __emul_lookup_dentry(const char *name, struct nameidata *nd) | ||
| 1068 | { | ||
| 1069 | if (path_walk(name, nd)) | ||
| 1070 | return 0; /* something went wrong... */ | ||
| 1071 | |||
| 1072 | if (!nd->path.dentry->d_inode || | ||
| 1073 | S_ISDIR(nd->path.dentry->d_inode->i_mode)) { | ||
| 1074 | struct path old_path = nd->path; | ||
| 1075 | struct qstr last = nd->last; | ||
| 1076 | int last_type = nd->last_type; | ||
| 1077 | struct fs_struct *fs = current->fs; | ||
| 1078 | |||
| 1079 | /* | ||
| 1080 | * NAME was not found in alternate root or it's a directory. | ||
| 1081 | * Try to find it in the normal root: | ||
| 1082 | */ | ||
| 1083 | nd->last_type = LAST_ROOT; | ||
| 1084 | read_lock(&fs->lock); | ||
| 1085 | nd->path = fs->root; | ||
| 1086 | path_get(&fs->root); | ||
| 1087 | read_unlock(&fs->lock); | ||
| 1088 | if (path_walk(name, nd) == 0) { | ||
| 1089 | if (nd->path.dentry->d_inode) { | ||
| 1090 | path_put(&old_path); | ||
| 1091 | return 1; | ||
| 1092 | } | ||
| 1093 | path_put(&nd->path); | ||
| 1094 | } | ||
| 1095 | nd->path = old_path; | ||
| 1096 | nd->last = last; | ||
| 1097 | nd->last_type = last_type; | ||
| 1098 | } | ||
| 1099 | return 1; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | void set_fs_altroot(void) | ||
| 1103 | { | ||
| 1104 | char *emul = __emul_prefix(); | ||
| 1105 | struct nameidata nd; | ||
| 1106 | struct path path = {}, old_path; | ||
| 1107 | int err; | ||
| 1108 | struct fs_struct *fs = current->fs; | ||
| 1109 | |||
| 1110 | if (!emul) | ||
| 1111 | goto set_it; | ||
| 1112 | err = path_lookup(emul, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd); | ||
| 1113 | if (!err) | ||
| 1114 | path = nd.path; | ||
| 1115 | set_it: | ||
| 1116 | write_lock(&fs->lock); | ||
| 1117 | old_path = fs->altroot; | ||
| 1118 | fs->altroot = path; | ||
| 1119 | write_unlock(&fs->lock); | ||
| 1120 | if (old_path.dentry) | ||
| 1121 | path_put(&old_path); | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1044 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ |
| 1125 | static int do_path_lookup(int dfd, const char *name, | 1045 | static int do_path_lookup(int dfd, const char *name, |
| 1126 | unsigned int flags, struct nameidata *nd) | 1046 | unsigned int flags, struct nameidata *nd) |
| @@ -1136,14 +1056,6 @@ static int do_path_lookup(int dfd, const char *name, | |||
| 1136 | 1056 | ||
| 1137 | if (*name=='/') { | 1057 | if (*name=='/') { |
| 1138 | read_lock(&fs->lock); | 1058 | read_lock(&fs->lock); |
| 1139 | if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) { | ||
| 1140 | nd->path = fs->altroot; | ||
| 1141 | path_get(&fs->altroot); | ||
| 1142 | read_unlock(&fs->lock); | ||
| 1143 | if (__emul_lookup_dentry(name,nd)) | ||
| 1144 | goto out; /* found in altroot */ | ||
| 1145 | read_lock(&fs->lock); | ||
| 1146 | } | ||
| 1147 | nd->path = fs->root; | 1059 | nd->path = fs->root; |
| 1148 | path_get(&fs->root); | 1060 | path_get(&fs->root); |
| 1149 | read_unlock(&fs->lock); | 1061 | read_unlock(&fs->lock); |
| @@ -1177,7 +1089,6 @@ static int do_path_lookup(int dfd, const char *name, | |||
| 1177 | } | 1089 | } |
| 1178 | 1090 | ||
| 1179 | retval = path_walk(name, nd); | 1091 | retval = path_walk(name, nd); |
| 1180 | out: | ||
| 1181 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1092 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && |
| 1182 | nd->path.dentry->d_inode)) | 1093 | nd->path.dentry->d_inode)) |
| 1183 | audit_inode(name, nd->path.dentry); | 1094 | audit_inode(name, nd->path.dentry); |
| @@ -1282,19 +1193,6 @@ static int path_lookup_create(int dfd, const char *name, | |||
| 1282 | nd, open_flags, create_mode); | 1193 | nd, open_flags, create_mode); |
| 1283 | } | 1194 | } |
| 1284 | 1195 | ||
| 1285 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | ||
| 1286 | struct nameidata *nd, int open_flags) | ||
| 1287 | { | ||
| 1288 | char *tmp = getname(name); | ||
| 1289 | int err = PTR_ERR(tmp); | ||
| 1290 | |||
| 1291 | if (!IS_ERR(tmp)) { | ||
| 1292 | err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0); | ||
| 1293 | putname(tmp); | ||
| 1294 | } | ||
| 1295 | return err; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | static struct dentry *__lookup_hash(struct qstr *name, | 1196 | static struct dentry *__lookup_hash(struct qstr *name, |
| 1299 | struct dentry *base, struct nameidata *nd) | 1197 | struct dentry *base, struct nameidata *nd) |
| 1300 | { | 1198 | { |
| @@ -1317,7 +1215,14 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
| 1317 | 1215 | ||
| 1318 | dentry = cached_lookup(base, name, nd); | 1216 | dentry = cached_lookup(base, name, nd); |
| 1319 | if (!dentry) { | 1217 | if (!dentry) { |
| 1320 | struct dentry *new = d_alloc(base, name); | 1218 | struct dentry *new; |
| 1219 | |||
| 1220 | /* Don't create child dentry for a dead directory. */ | ||
| 1221 | dentry = ERR_PTR(-ENOENT); | ||
| 1222 | if (IS_DEADDIR(inode)) | ||
| 1223 | goto out; | ||
| 1224 | |||
| 1225 | new = d_alloc(base, name); | ||
| 1321 | dentry = ERR_PTR(-ENOMEM); | 1226 | dentry = ERR_PTR(-ENOMEM); |
| 1322 | if (!new) | 1227 | if (!new) |
| 1323 | goto out; | 1228 | goto out; |
| @@ -1340,7 +1245,7 @@ static struct dentry *lookup_hash(struct nameidata *nd) | |||
| 1340 | { | 1245 | { |
| 1341 | int err; | 1246 | int err; |
| 1342 | 1247 | ||
| 1343 | err = permission(nd->path.dentry->d_inode, MAY_EXEC, nd); | 1248 | err = inode_permission(nd->path.dentry->d_inode, MAY_EXEC); |
| 1344 | if (err) | 1249 | if (err) |
| 1345 | return ERR_PTR(err); | 1250 | return ERR_PTR(err); |
| 1346 | return __lookup_hash(&nd->last, nd->path.dentry, nd); | 1251 | return __lookup_hash(&nd->last, nd->path.dentry, nd); |
| @@ -1388,7 +1293,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) | |||
| 1388 | if (err) | 1293 | if (err) |
| 1389 | return ERR_PTR(err); | 1294 | return ERR_PTR(err); |
| 1390 | 1295 | ||
| 1391 | err = permission(base->d_inode, MAY_EXEC, NULL); | 1296 | err = inode_permission(base->d_inode, MAY_EXEC); |
| 1392 | if (err) | 1297 | if (err) |
| 1393 | return ERR_PTR(err); | 1298 | return ERR_PTR(err); |
| 1394 | return __lookup_hash(&this, base, NULL); | 1299 | return __lookup_hash(&this, base, NULL); |
| @@ -1416,22 +1321,40 @@ struct dentry *lookup_one_noperm(const char *name, struct dentry *base) | |||
| 1416 | return __lookup_hash(&this, base, NULL); | 1321 | return __lookup_hash(&this, base, NULL); |
| 1417 | } | 1322 | } |
| 1418 | 1323 | ||
| 1419 | int __user_walk_fd(int dfd, const char __user *name, unsigned flags, | 1324 | int user_path_at(int dfd, const char __user *name, unsigned flags, |
| 1420 | struct nameidata *nd) | 1325 | struct path *path) |
| 1421 | { | 1326 | { |
| 1327 | struct nameidata nd; | ||
| 1422 | char *tmp = getname(name); | 1328 | char *tmp = getname(name); |
| 1423 | int err = PTR_ERR(tmp); | 1329 | int err = PTR_ERR(tmp); |
| 1424 | |||
| 1425 | if (!IS_ERR(tmp)) { | 1330 | if (!IS_ERR(tmp)) { |
| 1426 | err = do_path_lookup(dfd, tmp, flags, nd); | 1331 | |
| 1332 | BUG_ON(flags & LOOKUP_PARENT); | ||
| 1333 | |||
| 1334 | err = do_path_lookup(dfd, tmp, flags, &nd); | ||
| 1427 | putname(tmp); | 1335 | putname(tmp); |
| 1336 | if (!err) | ||
| 1337 | *path = nd.path; | ||
| 1428 | } | 1338 | } |
| 1429 | return err; | 1339 | return err; |
| 1430 | } | 1340 | } |
| 1431 | 1341 | ||
| 1432 | int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | 1342 | static int user_path_parent(int dfd, const char __user *path, |
| 1343 | struct nameidata *nd, char **name) | ||
| 1433 | { | 1344 | { |
| 1434 | return __user_walk_fd(AT_FDCWD, name, flags, nd); | 1345 | char *s = getname(path); |
| 1346 | int error; | ||
| 1347 | |||
| 1348 | if (IS_ERR(s)) | ||
| 1349 | return PTR_ERR(s); | ||
| 1350 | |||
| 1351 | error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd); | ||
| 1352 | if (error) | ||
| 1353 | putname(s); | ||
| 1354 | else | ||
| 1355 | *name = s; | ||
| 1356 | |||
| 1357 | return error; | ||
| 1435 | } | 1358 | } |
| 1436 | 1359 | ||
| 1437 | /* | 1360 | /* |
| @@ -1478,7 +1401,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
| 1478 | BUG_ON(victim->d_parent->d_inode != dir); | 1401 | BUG_ON(victim->d_parent->d_inode != dir); |
| 1479 | audit_inode_child(victim->d_name.name, victim, dir); | 1402 | audit_inode_child(victim->d_name.name, victim, dir); |
| 1480 | 1403 | ||
| 1481 | error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); | 1404 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); |
| 1482 | if (error) | 1405 | if (error) |
| 1483 | return error; | 1406 | return error; |
| 1484 | if (IS_APPEND(dir)) | 1407 | if (IS_APPEND(dir)) |
| @@ -1508,14 +1431,13 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) | |||
| 1508 | * 3. We should have write and exec permissions on dir | 1431 | * 3. We should have write and exec permissions on dir |
| 1509 | * 4. We can't do it if dir is immutable (done in permission()) | 1432 | * 4. We can't do it if dir is immutable (done in permission()) |
| 1510 | */ | 1433 | */ |
| 1511 | static inline int may_create(struct inode *dir, struct dentry *child, | 1434 | static inline int may_create(struct inode *dir, struct dentry *child) |
| 1512 | struct nameidata *nd) | ||
| 1513 | { | 1435 | { |
| 1514 | if (child->d_inode) | 1436 | if (child->d_inode) |
| 1515 | return -EEXIST; | 1437 | return -EEXIST; |
| 1516 | if (IS_DEADDIR(dir)) | 1438 | if (IS_DEADDIR(dir)) |
| 1517 | return -ENOENT; | 1439 | return -ENOENT; |
| 1518 | return permission(dir,MAY_WRITE | MAY_EXEC, nd); | 1440 | return inode_permission(dir, MAY_WRITE | MAY_EXEC); |
| 1519 | } | 1441 | } |
| 1520 | 1442 | ||
| 1521 | /* | 1443 | /* |
| @@ -1581,7 +1503,7 @@ void unlock_rename(struct dentry *p1, struct dentry *p2) | |||
| 1581 | int vfs_create(struct inode *dir, struct dentry *dentry, int mode, | 1503 | int vfs_create(struct inode *dir, struct dentry *dentry, int mode, |
| 1582 | struct nameidata *nd) | 1504 | struct nameidata *nd) |
| 1583 | { | 1505 | { |
| 1584 | int error = may_create(dir, dentry, nd); | 1506 | int error = may_create(dir, dentry); |
| 1585 | 1507 | ||
| 1586 | if (error) | 1508 | if (error) |
| 1587 | return error; | 1509 | return error; |
| @@ -1755,7 +1677,7 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
| 1755 | int will_write; | 1677 | int will_write; |
| 1756 | int flag = open_to_namei_flags(open_flag); | 1678 | int flag = open_to_namei_flags(open_flag); |
| 1757 | 1679 | ||
| 1758 | acc_mode = ACC_MODE(flag); | 1680 | acc_mode = MAY_OPEN | ACC_MODE(flag); |
| 1759 | 1681 | ||
| 1760 | /* O_TRUNC implies we need access checks for write permissions */ | 1682 | /* O_TRUNC implies we need access checks for write permissions */ |
| 1761 | if (flag & O_TRUNC) | 1683 | if (flag & O_TRUNC) |
| @@ -2025,7 +1947,7 @@ EXPORT_SYMBOL_GPL(lookup_create); | |||
| 2025 | 1947 | ||
| 2026 | int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | 1948 | int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) |
| 2027 | { | 1949 | { |
| 2028 | int error = may_create(dir, dentry, NULL); | 1950 | int error = may_create(dir, dentry); |
| 2029 | 1951 | ||
| 2030 | if (error) | 1952 | if (error) |
| 2031 | return error; | 1953 | return error; |
| @@ -2071,20 +1993,18 @@ static int may_mknod(mode_t mode) | |||
| 2071 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, | 1993 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
| 2072 | unsigned dev) | 1994 | unsigned dev) |
| 2073 | { | 1995 | { |
| 2074 | int error = 0; | 1996 | int error; |
| 2075 | char * tmp; | 1997 | char *tmp; |
| 2076 | struct dentry * dentry; | 1998 | struct dentry *dentry; |
| 2077 | struct nameidata nd; | 1999 | struct nameidata nd; |
| 2078 | 2000 | ||
| 2079 | if (S_ISDIR(mode)) | 2001 | if (S_ISDIR(mode)) |
| 2080 | return -EPERM; | 2002 | return -EPERM; |
| 2081 | tmp = getname(filename); | ||
| 2082 | if (IS_ERR(tmp)) | ||
| 2083 | return PTR_ERR(tmp); | ||
| 2084 | 2003 | ||
| 2085 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); | 2004 | error = user_path_parent(dfd, filename, &nd, &tmp); |
| 2086 | if (error) | 2005 | if (error) |
| 2087 | goto out; | 2006 | return error; |
| 2007 | |||
| 2088 | dentry = lookup_create(&nd, 0); | 2008 | dentry = lookup_create(&nd, 0); |
| 2089 | if (IS_ERR(dentry)) { | 2009 | if (IS_ERR(dentry)) { |
| 2090 | error = PTR_ERR(dentry); | 2010 | error = PTR_ERR(dentry); |
| @@ -2116,7 +2036,6 @@ out_dput: | |||
| 2116 | out_unlock: | 2036 | out_unlock: |
| 2117 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2037 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2118 | path_put(&nd.path); | 2038 | path_put(&nd.path); |
| 2119 | out: | ||
| 2120 | putname(tmp); | 2039 | putname(tmp); |
| 2121 | 2040 | ||
| 2122 | return error; | 2041 | return error; |
| @@ -2129,7 +2048,7 @@ asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) | |||
| 2129 | 2048 | ||
| 2130 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 2049 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
| 2131 | { | 2050 | { |
| 2132 | int error = may_create(dir, dentry, NULL); | 2051 | int error = may_create(dir, dentry); |
| 2133 | 2052 | ||
| 2134 | if (error) | 2053 | if (error) |
| 2135 | return error; | 2054 | return error; |
| @@ -2156,14 +2075,10 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) | |||
| 2156 | struct dentry *dentry; | 2075 | struct dentry *dentry; |
| 2157 | struct nameidata nd; | 2076 | struct nameidata nd; |
| 2158 | 2077 | ||
| 2159 | tmp = getname(pathname); | 2078 | error = user_path_parent(dfd, pathname, &nd, &tmp); |
| 2160 | error = PTR_ERR(tmp); | 2079 | if (error) |
| 2161 | if (IS_ERR(tmp)) | ||
| 2162 | goto out_err; | 2080 | goto out_err; |
| 2163 | 2081 | ||
| 2164 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); | ||
| 2165 | if (error) | ||
| 2166 | goto out; | ||
| 2167 | dentry = lookup_create(&nd, 1); | 2082 | dentry = lookup_create(&nd, 1); |
| 2168 | error = PTR_ERR(dentry); | 2083 | error = PTR_ERR(dentry); |
| 2169 | if (IS_ERR(dentry)) | 2084 | if (IS_ERR(dentry)) |
| @@ -2181,7 +2096,6 @@ out_dput: | |||
| 2181 | out_unlock: | 2096 | out_unlock: |
| 2182 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2097 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2183 | path_put(&nd.path); | 2098 | path_put(&nd.path); |
| 2184 | out: | ||
| 2185 | putname(tmp); | 2099 | putname(tmp); |
| 2186 | out_err: | 2100 | out_err: |
| 2187 | return error; | 2101 | return error; |
| @@ -2259,13 +2173,9 @@ static long do_rmdir(int dfd, const char __user *pathname) | |||
| 2259 | struct dentry *dentry; | 2173 | struct dentry *dentry; |
| 2260 | struct nameidata nd; | 2174 | struct nameidata nd; |
| 2261 | 2175 | ||
| 2262 | name = getname(pathname); | 2176 | error = user_path_parent(dfd, pathname, &nd, &name); |
| 2263 | if(IS_ERR(name)) | ||
| 2264 | return PTR_ERR(name); | ||
| 2265 | |||
| 2266 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); | ||
| 2267 | if (error) | 2177 | if (error) |
| 2268 | goto exit; | 2178 | return error; |
| 2269 | 2179 | ||
| 2270 | switch(nd.last_type) { | 2180 | switch(nd.last_type) { |
| 2271 | case LAST_DOTDOT: | 2181 | case LAST_DOTDOT: |
| @@ -2294,7 +2204,6 @@ exit2: | |||
| 2294 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2204 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2295 | exit1: | 2205 | exit1: |
| 2296 | path_put(&nd.path); | 2206 | path_put(&nd.path); |
| 2297 | exit: | ||
| 2298 | putname(name); | 2207 | putname(name); |
| 2299 | return error; | 2208 | return error; |
| 2300 | } | 2209 | } |
| @@ -2343,19 +2252,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 2343 | */ | 2252 | */ |
| 2344 | static long do_unlinkat(int dfd, const char __user *pathname) | 2253 | static long do_unlinkat(int dfd, const char __user *pathname) |
| 2345 | { | 2254 | { |
| 2346 | int error = 0; | 2255 | int error; |
| 2347 | char * name; | 2256 | char *name; |
| 2348 | struct dentry *dentry; | 2257 | struct dentry *dentry; |
| 2349 | struct nameidata nd; | 2258 | struct nameidata nd; |
| 2350 | struct inode *inode = NULL; | 2259 | struct inode *inode = NULL; |
| 2351 | 2260 | ||
| 2352 | name = getname(pathname); | 2261 | error = user_path_parent(dfd, pathname, &nd, &name); |
| 2353 | if(IS_ERR(name)) | ||
| 2354 | return PTR_ERR(name); | ||
| 2355 | |||
| 2356 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); | ||
| 2357 | if (error) | 2262 | if (error) |
| 2358 | goto exit; | 2263 | return error; |
| 2264 | |||
| 2359 | error = -EISDIR; | 2265 | error = -EISDIR; |
| 2360 | if (nd.last_type != LAST_NORM) | 2266 | if (nd.last_type != LAST_NORM) |
| 2361 | goto exit1; | 2267 | goto exit1; |
| @@ -2382,7 +2288,6 @@ static long do_unlinkat(int dfd, const char __user *pathname) | |||
| 2382 | iput(inode); /* truncate the inode here */ | 2288 | iput(inode); /* truncate the inode here */ |
| 2383 | exit1: | 2289 | exit1: |
| 2384 | path_put(&nd.path); | 2290 | path_put(&nd.path); |
| 2385 | exit: | ||
| 2386 | putname(name); | 2291 | putname(name); |
| 2387 | return error; | 2292 | return error; |
| 2388 | 2293 | ||
| @@ -2408,9 +2313,9 @@ asmlinkage long sys_unlink(const char __user *pathname) | |||
| 2408 | return do_unlinkat(AT_FDCWD, pathname); | 2313 | return do_unlinkat(AT_FDCWD, pathname); |
| 2409 | } | 2314 | } |
| 2410 | 2315 | ||
| 2411 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) | 2316 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) |
| 2412 | { | 2317 | { |
| 2413 | int error = may_create(dir, dentry, NULL); | 2318 | int error = may_create(dir, dentry); |
| 2414 | 2319 | ||
| 2415 | if (error) | 2320 | if (error) |
| 2416 | return error; | 2321 | return error; |
| @@ -2432,23 +2337,20 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i | |||
| 2432 | asmlinkage long sys_symlinkat(const char __user *oldname, | 2337 | asmlinkage long sys_symlinkat(const char __user *oldname, |
| 2433 | int newdfd, const char __user *newname) | 2338 | int newdfd, const char __user *newname) |
| 2434 | { | 2339 | { |
| 2435 | int error = 0; | 2340 | int error; |
| 2436 | char * from; | 2341 | char *from; |
| 2437 | char * to; | 2342 | char *to; |
| 2438 | struct dentry *dentry; | 2343 | struct dentry *dentry; |
| 2439 | struct nameidata nd; | 2344 | struct nameidata nd; |
| 2440 | 2345 | ||
| 2441 | from = getname(oldname); | 2346 | from = getname(oldname); |
| 2442 | if(IS_ERR(from)) | 2347 | if (IS_ERR(from)) |
| 2443 | return PTR_ERR(from); | 2348 | return PTR_ERR(from); |
| 2444 | to = getname(newname); | ||
| 2445 | error = PTR_ERR(to); | ||
| 2446 | if (IS_ERR(to)) | ||
| 2447 | goto out_putname; | ||
| 2448 | 2349 | ||
| 2449 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); | 2350 | error = user_path_parent(newdfd, newname, &nd, &to); |
| 2450 | if (error) | 2351 | if (error) |
| 2451 | goto out; | 2352 | goto out_putname; |
| 2353 | |||
| 2452 | dentry = lookup_create(&nd, 0); | 2354 | dentry = lookup_create(&nd, 0); |
| 2453 | error = PTR_ERR(dentry); | 2355 | error = PTR_ERR(dentry); |
| 2454 | if (IS_ERR(dentry)) | 2356 | if (IS_ERR(dentry)) |
| @@ -2457,14 +2359,13 @@ asmlinkage long sys_symlinkat(const char __user *oldname, | |||
| 2457 | error = mnt_want_write(nd.path.mnt); | 2359 | error = mnt_want_write(nd.path.mnt); |
| 2458 | if (error) | 2360 | if (error) |
| 2459 | goto out_dput; | 2361 | goto out_dput; |
| 2460 | error = vfs_symlink(nd.path.dentry->d_inode, dentry, from, S_IALLUGO); | 2362 | error = vfs_symlink(nd.path.dentry->d_inode, dentry, from); |
| 2461 | mnt_drop_write(nd.path.mnt); | 2363 | mnt_drop_write(nd.path.mnt); |
| 2462 | out_dput: | 2364 | out_dput: |
| 2463 | dput(dentry); | 2365 | dput(dentry); |
| 2464 | out_unlock: | 2366 | out_unlock: |
| 2465 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2367 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2466 | path_put(&nd.path); | 2368 | path_put(&nd.path); |
| 2467 | out: | ||
| 2468 | putname(to); | 2369 | putname(to); |
| 2469 | out_putname: | 2370 | out_putname: |
| 2470 | putname(from); | 2371 | putname(from); |
| @@ -2484,7 +2385,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
| 2484 | if (!inode) | 2385 | if (!inode) |
| 2485 | return -ENOENT; | 2386 | return -ENOENT; |
| 2486 | 2387 | ||
| 2487 | error = may_create(dir, new_dentry, NULL); | 2388 | error = may_create(dir, new_dentry); |
| 2488 | if (error) | 2389 | if (error) |
| 2489 | return error; | 2390 | return error; |
| 2490 | 2391 | ||
| @@ -2498,19 +2399,19 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
| 2498 | return -EPERM; | 2399 | return -EPERM; |
| 2499 | if (!dir->i_op || !dir->i_op->link) | 2400 | if (!dir->i_op || !dir->i_op->link) |
| 2500 | return -EPERM; | 2401 | return -EPERM; |
| 2501 | if (S_ISDIR(old_dentry->d_inode->i_mode)) | 2402 | if (S_ISDIR(inode->i_mode)) |
| 2502 | return -EPERM; | 2403 | return -EPERM; |
| 2503 | 2404 | ||
| 2504 | error = security_inode_link(old_dentry, dir, new_dentry); | 2405 | error = security_inode_link(old_dentry, dir, new_dentry); |
| 2505 | if (error) | 2406 | if (error) |
| 2506 | return error; | 2407 | return error; |
| 2507 | 2408 | ||
| 2508 | mutex_lock(&old_dentry->d_inode->i_mutex); | 2409 | mutex_lock(&inode->i_mutex); |
| 2509 | DQUOT_INIT(dir); | 2410 | DQUOT_INIT(dir); |
| 2510 | error = dir->i_op->link(old_dentry, dir, new_dentry); | 2411 | error = dir->i_op->link(old_dentry, dir, new_dentry); |
| 2511 | mutex_unlock(&old_dentry->d_inode->i_mutex); | 2412 | mutex_unlock(&inode->i_mutex); |
| 2512 | if (!error) | 2413 | if (!error) |
| 2513 | fsnotify_link(dir, old_dentry->d_inode, new_dentry); | 2414 | fsnotify_link(dir, inode, new_dentry); |
| 2514 | return error; | 2415 | return error; |
| 2515 | } | 2416 | } |
| 2516 | 2417 | ||
| @@ -2528,27 +2429,25 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, | |||
| 2528 | int flags) | 2429 | int flags) |
| 2529 | { | 2430 | { |
| 2530 | struct dentry *new_dentry; | 2431 | struct dentry *new_dentry; |
| 2531 | struct nameidata nd, old_nd; | 2432 | struct nameidata nd; |
| 2433 | struct path old_path; | ||
| 2532 | int error; | 2434 | int error; |
| 2533 | char * to; | 2435 | char *to; |
| 2534 | 2436 | ||
| 2535 | if ((flags & ~AT_SYMLINK_FOLLOW) != 0) | 2437 | if ((flags & ~AT_SYMLINK_FOLLOW) != 0) |
| 2536 | return -EINVAL; | 2438 | return -EINVAL; |
| 2537 | 2439 | ||
| 2538 | to = getname(newname); | 2440 | error = user_path_at(olddfd, oldname, |
| 2539 | if (IS_ERR(to)) | 2441 | flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, |
| 2540 | return PTR_ERR(to); | 2442 | &old_path); |
| 2541 | |||
| 2542 | error = __user_walk_fd(olddfd, oldname, | ||
| 2543 | flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, | ||
| 2544 | &old_nd); | ||
| 2545 | if (error) | 2443 | if (error) |
| 2546 | goto exit; | 2444 | return error; |
| 2547 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); | 2445 | |
| 2446 | error = user_path_parent(newdfd, newname, &nd, &to); | ||
| 2548 | if (error) | 2447 | if (error) |
| 2549 | goto out; | 2448 | goto out; |
| 2550 | error = -EXDEV; | 2449 | error = -EXDEV; |
| 2551 | if (old_nd.path.mnt != nd.path.mnt) | 2450 | if (old_path.mnt != nd.path.mnt) |
| 2552 | goto out_release; | 2451 | goto out_release; |
| 2553 | new_dentry = lookup_create(&nd, 0); | 2452 | new_dentry = lookup_create(&nd, 0); |
| 2554 | error = PTR_ERR(new_dentry); | 2453 | error = PTR_ERR(new_dentry); |
| @@ -2557,7 +2456,7 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, | |||
| 2557 | error = mnt_want_write(nd.path.mnt); | 2456 | error = mnt_want_write(nd.path.mnt); |
| 2558 | if (error) | 2457 | if (error) |
| 2559 | goto out_dput; | 2458 | goto out_dput; |
| 2560 | error = vfs_link(old_nd.path.dentry, nd.path.dentry->d_inode, new_dentry); | 2459 | error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); |
| 2561 | mnt_drop_write(nd.path.mnt); | 2460 | mnt_drop_write(nd.path.mnt); |
| 2562 | out_dput: | 2461 | out_dput: |
| 2563 | dput(new_dentry); | 2462 | dput(new_dentry); |
| @@ -2565,10 +2464,9 @@ out_unlock: | |||
| 2565 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2464 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2566 | out_release: | 2465 | out_release: |
| 2567 | path_put(&nd.path); | 2466 | path_put(&nd.path); |
| 2568 | out: | ||
| 2569 | path_put(&old_nd.path); | ||
| 2570 | exit: | ||
| 2571 | putname(to); | 2467 | putname(to); |
| 2468 | out: | ||
| 2469 | path_put(&old_path); | ||
| 2572 | 2470 | ||
| 2573 | return error; | 2471 | return error; |
| 2574 | } | 2472 | } |
| @@ -2621,7 +2519,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2621 | * we'll need to flip '..'. | 2519 | * we'll need to flip '..'. |
| 2622 | */ | 2520 | */ |
| 2623 | if (new_dir != old_dir) { | 2521 | if (new_dir != old_dir) { |
| 2624 | error = permission(old_dentry->d_inode, MAY_WRITE, NULL); | 2522 | error = inode_permission(old_dentry->d_inode, MAY_WRITE); |
| 2625 | if (error) | 2523 | if (error) |
| 2626 | return error; | 2524 | return error; |
| 2627 | } | 2525 | } |
| @@ -2696,7 +2594,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2696 | return error; | 2594 | return error; |
| 2697 | 2595 | ||
| 2698 | if (!new_dentry->d_inode) | 2596 | if (!new_dentry->d_inode) |
| 2699 | error = may_create(new_dir, new_dentry, NULL); | 2597 | error = may_create(new_dir, new_dentry); |
| 2700 | else | 2598 | else |
| 2701 | error = may_delete(new_dir, new_dentry, is_dir); | 2599 | error = may_delete(new_dir, new_dentry, is_dir); |
| 2702 | if (error) | 2600 | if (error) |
| @@ -2724,20 +2622,22 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2724 | return error; | 2622 | return error; |
| 2725 | } | 2623 | } |
| 2726 | 2624 | ||
| 2727 | static int do_rename(int olddfd, const char *oldname, | 2625 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, |
| 2728 | int newdfd, const char *newname) | 2626 | int newdfd, const char __user *newname) |
| 2729 | { | 2627 | { |
| 2730 | int error = 0; | 2628 | struct dentry *old_dir, *new_dir; |
| 2731 | struct dentry * old_dir, * new_dir; | 2629 | struct dentry *old_dentry, *new_dentry; |
| 2732 | struct dentry * old_dentry, *new_dentry; | 2630 | struct dentry *trap; |
| 2733 | struct dentry * trap; | ||
| 2734 | struct nameidata oldnd, newnd; | 2631 | struct nameidata oldnd, newnd; |
| 2632 | char *from; | ||
| 2633 | char *to; | ||
| 2634 | int error; | ||
| 2735 | 2635 | ||
| 2736 | error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); | 2636 | error = user_path_parent(olddfd, oldname, &oldnd, &from); |
| 2737 | if (error) | 2637 | if (error) |
| 2738 | goto exit; | 2638 | goto exit; |
| 2739 | 2639 | ||
| 2740 | error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); | 2640 | error = user_path_parent(newdfd, newname, &newnd, &to); |
| 2741 | if (error) | 2641 | if (error) |
| 2742 | goto exit1; | 2642 | goto exit1; |
| 2743 | 2643 | ||
| @@ -2799,29 +2699,11 @@ exit3: | |||
| 2799 | unlock_rename(new_dir, old_dir); | 2699 | unlock_rename(new_dir, old_dir); |
| 2800 | exit2: | 2700 | exit2: |
| 2801 | path_put(&newnd.path); | 2701 | path_put(&newnd.path); |
| 2702 | putname(to); | ||
| 2802 | exit1: | 2703 | exit1: |
| 2803 | path_put(&oldnd.path); | 2704 | path_put(&oldnd.path); |
| 2804 | exit: | ||
| 2805 | return error; | ||
| 2806 | } | ||
| 2807 | |||
| 2808 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, | ||
| 2809 | int newdfd, const char __user *newname) | ||
| 2810 | { | ||
| 2811 | int error; | ||
| 2812 | char * from; | ||
| 2813 | char * to; | ||
| 2814 | |||
| 2815 | from = getname(oldname); | ||
| 2816 | if(IS_ERR(from)) | ||
| 2817 | return PTR_ERR(from); | ||
| 2818 | to = getname(newname); | ||
| 2819 | error = PTR_ERR(to); | ||
| 2820 | if (!IS_ERR(to)) { | ||
| 2821 | error = do_rename(olddfd, from, newdfd, to); | ||
| 2822 | putname(to); | ||
| 2823 | } | ||
| 2824 | putname(from); | 2705 | putname(from); |
| 2706 | exit: | ||
| 2825 | return error; | 2707 | return error; |
| 2826 | } | 2708 | } |
| 2827 | 2709 | ||
| @@ -2959,8 +2841,7 @@ const struct inode_operations page_symlink_inode_operations = { | |||
| 2959 | .put_link = page_put_link, | 2841 | .put_link = page_put_link, |
| 2960 | }; | 2842 | }; |
| 2961 | 2843 | ||
| 2962 | EXPORT_SYMBOL(__user_walk); | 2844 | EXPORT_SYMBOL(user_path_at); |
| 2963 | EXPORT_SYMBOL(__user_walk_fd); | ||
| 2964 | EXPORT_SYMBOL(follow_down); | 2845 | EXPORT_SYMBOL(follow_down); |
| 2965 | EXPORT_SYMBOL(follow_up); | 2846 | EXPORT_SYMBOL(follow_up); |
| 2966 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ | 2847 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ |
| @@ -2975,7 +2856,7 @@ EXPORT_SYMBOL(page_symlink); | |||
| 2975 | EXPORT_SYMBOL(page_symlink_inode_operations); | 2856 | EXPORT_SYMBOL(page_symlink_inode_operations); |
| 2976 | EXPORT_SYMBOL(path_lookup); | 2857 | EXPORT_SYMBOL(path_lookup); |
| 2977 | EXPORT_SYMBOL(vfs_path_lookup); | 2858 | EXPORT_SYMBOL(vfs_path_lookup); |
| 2978 | EXPORT_SYMBOL(permission); | 2859 | EXPORT_SYMBOL(inode_permission); |
| 2979 | EXPORT_SYMBOL(vfs_permission); | 2860 | EXPORT_SYMBOL(vfs_permission); |
| 2980 | EXPORT_SYMBOL(file_permission); | 2861 | EXPORT_SYMBOL(file_permission); |
| 2981 | EXPORT_SYMBOL(unlock_rename); | 2862 | EXPORT_SYMBOL(unlock_rename); |
diff --git a/fs/namespace.c b/fs/namespace.c index 4f6f7635b59c..6e283c93b50d 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -112,9 +112,13 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
| 112 | int err; | 112 | int err; |
| 113 | 113 | ||
| 114 | err = mnt_alloc_id(mnt); | 114 | err = mnt_alloc_id(mnt); |
| 115 | if (err) { | 115 | if (err) |
| 116 | kmem_cache_free(mnt_cache, mnt); | 116 | goto out_free_cache; |
| 117 | return NULL; | 117 | |
| 118 | if (name) { | ||
| 119 | mnt->mnt_devname = kstrdup(name, GFP_KERNEL); | ||
| 120 | if (!mnt->mnt_devname) | ||
| 121 | goto out_free_id; | ||
| 118 | } | 122 | } |
| 119 | 123 | ||
| 120 | atomic_set(&mnt->mnt_count, 1); | 124 | atomic_set(&mnt->mnt_count, 1); |
| @@ -127,16 +131,14 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
| 127 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | 131 | INIT_LIST_HEAD(&mnt->mnt_slave_list); |
| 128 | INIT_LIST_HEAD(&mnt->mnt_slave); | 132 | INIT_LIST_HEAD(&mnt->mnt_slave); |
| 129 | atomic_set(&mnt->__mnt_writers, 0); | 133 | atomic_set(&mnt->__mnt_writers, 0); |
| 130 | if (name) { | ||
| 131 | int size = strlen(name) + 1; | ||
| 132 | char *newname = kmalloc(size, GFP_KERNEL); | ||
| 133 | if (newname) { | ||
| 134 | memcpy(newname, name, size); | ||
| 135 | mnt->mnt_devname = newname; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | 134 | } |
| 139 | return mnt; | 135 | return mnt; |
| 136 | |||
| 137 | out_free_id: | ||
| 138 | mnt_free_id(mnt); | ||
| 139 | out_free_cache: | ||
| 140 | kmem_cache_free(mnt_cache, mnt); | ||
| 141 | return NULL; | ||
| 140 | } | 142 | } |
| 141 | 143 | ||
| 142 | /* | 144 | /* |
| @@ -309,10 +311,9 @@ static void handle_write_count_underflow(struct vfsmount *mnt) | |||
| 309 | */ | 311 | */ |
| 310 | if ((atomic_read(&mnt->__mnt_writers) < 0) && | 312 | if ((atomic_read(&mnt->__mnt_writers) < 0) && |
| 311 | !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { | 313 | !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { |
| 312 | printk(KERN_DEBUG "leak detected on mount(%p) writers " | 314 | WARN(1, KERN_DEBUG "leak detected on mount(%p) writers " |
| 313 | "count: %d\n", | 315 | "count: %d\n", |
| 314 | mnt, atomic_read(&mnt->__mnt_writers)); | 316 | mnt, atomic_read(&mnt->__mnt_writers)); |
| 315 | WARN_ON(1); | ||
| 316 | /* use the flag to keep the dmesg spam down */ | 317 | /* use the flag to keep the dmesg spam down */ |
| 317 | mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; | 318 | mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; |
| 318 | } | 319 | } |
| @@ -1129,27 +1130,27 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
| 1129 | 1130 | ||
| 1130 | asmlinkage long sys_umount(char __user * name, int flags) | 1131 | asmlinkage long sys_umount(char __user * name, int flags) |
| 1131 | { | 1132 | { |
| 1132 | struct nameidata nd; | 1133 | struct path path; |
| 1133 | int retval; | 1134 | int retval; |
| 1134 | 1135 | ||
| 1135 | retval = __user_walk(name, LOOKUP_FOLLOW, &nd); | 1136 | retval = user_path(name, &path); |
| 1136 | if (retval) | 1137 | if (retval) |
| 1137 | goto out; | 1138 | goto out; |
| 1138 | retval = -EINVAL; | 1139 | retval = -EINVAL; |
| 1139 | if (nd.path.dentry != nd.path.mnt->mnt_root) | 1140 | if (path.dentry != path.mnt->mnt_root) |
| 1140 | goto dput_and_out; | 1141 | goto dput_and_out; |
| 1141 | if (!check_mnt(nd.path.mnt)) | 1142 | if (!check_mnt(path.mnt)) |
| 1142 | goto dput_and_out; | 1143 | goto dput_and_out; |
| 1143 | 1144 | ||
| 1144 | retval = -EPERM; | 1145 | retval = -EPERM; |
| 1145 | if (!capable(CAP_SYS_ADMIN)) | 1146 | if (!capable(CAP_SYS_ADMIN)) |
| 1146 | goto dput_and_out; | 1147 | goto dput_and_out; |
| 1147 | 1148 | ||
| 1148 | retval = do_umount(nd.path.mnt, flags); | 1149 | retval = do_umount(path.mnt, flags); |
| 1149 | dput_and_out: | 1150 | dput_and_out: |
| 1150 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ | 1151 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ |
| 1151 | dput(nd.path.dentry); | 1152 | dput(path.dentry); |
| 1152 | mntput_no_expire(nd.path.mnt); | 1153 | mntput_no_expire(path.mnt); |
| 1153 | out: | 1154 | out: |
| 1154 | return retval; | 1155 | return retval; |
| 1155 | } | 1156 | } |
| @@ -1666,31 +1667,31 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, | |||
| 1666 | if (IS_ERR(mnt)) | 1667 | if (IS_ERR(mnt)) |
| 1667 | return PTR_ERR(mnt); | 1668 | return PTR_ERR(mnt); |
| 1668 | 1669 | ||
| 1669 | return do_add_mount(mnt, nd, mnt_flags, NULL); | 1670 | return do_add_mount(mnt, &nd->path, mnt_flags, NULL); |
| 1670 | } | 1671 | } |
| 1671 | 1672 | ||
| 1672 | /* | 1673 | /* |
| 1673 | * add a mount into a namespace's mount tree | 1674 | * add a mount into a namespace's mount tree |
| 1674 | * - provide the option of adding the new mount to an expiration list | 1675 | * - provide the option of adding the new mount to an expiration list |
| 1675 | */ | 1676 | */ |
| 1676 | int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | 1677 | int do_add_mount(struct vfsmount *newmnt, struct path *path, |
| 1677 | int mnt_flags, struct list_head *fslist) | 1678 | int mnt_flags, struct list_head *fslist) |
| 1678 | { | 1679 | { |
| 1679 | int err; | 1680 | int err; |
| 1680 | 1681 | ||
| 1681 | down_write(&namespace_sem); | 1682 | down_write(&namespace_sem); |
| 1682 | /* Something was mounted here while we slept */ | 1683 | /* Something was mounted here while we slept */ |
| 1683 | while (d_mountpoint(nd->path.dentry) && | 1684 | while (d_mountpoint(path->dentry) && |
| 1684 | follow_down(&nd->path.mnt, &nd->path.dentry)) | 1685 | follow_down(&path->mnt, &path->dentry)) |
| 1685 | ; | 1686 | ; |
| 1686 | err = -EINVAL; | 1687 | err = -EINVAL; |
| 1687 | if (!check_mnt(nd->path.mnt)) | 1688 | if (!check_mnt(path->mnt)) |
| 1688 | goto unlock; | 1689 | goto unlock; |
| 1689 | 1690 | ||
| 1690 | /* Refuse the same filesystem on the same mount point */ | 1691 | /* Refuse the same filesystem on the same mount point */ |
| 1691 | err = -EBUSY; | 1692 | err = -EBUSY; |
| 1692 | if (nd->path.mnt->mnt_sb == newmnt->mnt_sb && | 1693 | if (path->mnt->mnt_sb == newmnt->mnt_sb && |
| 1693 | nd->path.mnt->mnt_root == nd->path.dentry) | 1694 | path->mnt->mnt_root == path->dentry) |
| 1694 | goto unlock; | 1695 | goto unlock; |
| 1695 | 1696 | ||
| 1696 | err = -EINVAL; | 1697 | err = -EINVAL; |
| @@ -1698,7 +1699,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 1698 | goto unlock; | 1699 | goto unlock; |
| 1699 | 1700 | ||
| 1700 | newmnt->mnt_flags = mnt_flags; | 1701 | newmnt->mnt_flags = mnt_flags; |
| 1701 | if ((err = graft_tree(newmnt, &nd->path))) | 1702 | if ((err = graft_tree(newmnt, path))) |
| 1702 | goto unlock; | 1703 | goto unlock; |
| 1703 | 1704 | ||
| 1704 | if (fslist) /* add to the specified expiration list */ | 1705 | if (fslist) /* add to the specified expiration list */ |
| @@ -1973,7 +1974,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
| 1973 | struct fs_struct *fs) | 1974 | struct fs_struct *fs) |
| 1974 | { | 1975 | { |
| 1975 | struct mnt_namespace *new_ns; | 1976 | struct mnt_namespace *new_ns; |
| 1976 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; | 1977 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
| 1977 | struct vfsmount *p, *q; | 1978 | struct vfsmount *p, *q; |
| 1978 | 1979 | ||
| 1979 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1980 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); |
| @@ -2016,10 +2017,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
| 2016 | pwdmnt = p; | 2017 | pwdmnt = p; |
| 2017 | fs->pwd.mnt = mntget(q); | 2018 | fs->pwd.mnt = mntget(q); |
| 2018 | } | 2019 | } |
| 2019 | if (p == fs->altroot.mnt) { | ||
| 2020 | altrootmnt = p; | ||
| 2021 | fs->altroot.mnt = mntget(q); | ||
| 2022 | } | ||
| 2023 | } | 2020 | } |
| 2024 | p = next_mnt(p, mnt_ns->root); | 2021 | p = next_mnt(p, mnt_ns->root); |
| 2025 | q = next_mnt(q, new_ns->root); | 2022 | q = next_mnt(q, new_ns->root); |
| @@ -2030,8 +2027,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
| 2030 | mntput(rootmnt); | 2027 | mntput(rootmnt); |
| 2031 | if (pwdmnt) | 2028 | if (pwdmnt) |
| 2032 | mntput(pwdmnt); | 2029 | mntput(pwdmnt); |
| 2033 | if (altrootmnt) | ||
| 2034 | mntput(altrootmnt); | ||
| 2035 | 2030 | ||
| 2036 | return new_ns; | 2031 | return new_ns; |
| 2037 | } | 2032 | } |
| @@ -2184,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
| 2184 | const char __user * put_old) | 2179 | const char __user * put_old) |
| 2185 | { | 2180 | { |
| 2186 | struct vfsmount *tmp; | 2181 | struct vfsmount *tmp; |
| 2187 | struct nameidata new_nd, old_nd; | 2182 | struct path new, old, parent_path, root_parent, root; |
| 2188 | struct path parent_path, root_parent, root; | ||
| 2189 | int error; | 2183 | int error; |
| 2190 | 2184 | ||
| 2191 | if (!capable(CAP_SYS_ADMIN)) | 2185 | if (!capable(CAP_SYS_ADMIN)) |
| 2192 | return -EPERM; | 2186 | return -EPERM; |
| 2193 | 2187 | ||
| 2194 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 2188 | error = user_path_dir(new_root, &new); |
| 2195 | &new_nd); | ||
| 2196 | if (error) | 2189 | if (error) |
| 2197 | goto out0; | 2190 | goto out0; |
| 2198 | error = -EINVAL; | 2191 | error = -EINVAL; |
| 2199 | if (!check_mnt(new_nd.path.mnt)) | 2192 | if (!check_mnt(new.mnt)) |
| 2200 | goto out1; | 2193 | goto out1; |
| 2201 | 2194 | ||
| 2202 | error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); | 2195 | error = user_path_dir(put_old, &old); |
| 2203 | if (error) | 2196 | if (error) |
| 2204 | goto out1; | 2197 | goto out1; |
| 2205 | 2198 | ||
| 2206 | error = security_sb_pivotroot(&old_nd.path, &new_nd.path); | 2199 | error = security_sb_pivotroot(&old, &new); |
| 2207 | if (error) { | 2200 | if (error) { |
| 2208 | path_put(&old_nd.path); | 2201 | path_put(&old); |
| 2209 | goto out1; | 2202 | goto out1; |
| 2210 | } | 2203 | } |
| 2211 | 2204 | ||
| @@ -2214,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
| 2214 | path_get(¤t->fs->root); | 2207 | path_get(¤t->fs->root); |
| 2215 | read_unlock(¤t->fs->lock); | 2208 | read_unlock(¤t->fs->lock); |
| 2216 | down_write(&namespace_sem); | 2209 | down_write(&namespace_sem); |
| 2217 | mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); | 2210 | mutex_lock(&old.dentry->d_inode->i_mutex); |
| 2218 | error = -EINVAL; | 2211 | error = -EINVAL; |
| 2219 | if (IS_MNT_SHARED(old_nd.path.mnt) || | 2212 | if (IS_MNT_SHARED(old.mnt) || |
| 2220 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || | 2213 | IS_MNT_SHARED(new.mnt->mnt_parent) || |
| 2221 | IS_MNT_SHARED(root.mnt->mnt_parent)) | 2214 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
| 2222 | goto out2; | 2215 | goto out2; |
| 2223 | if (!check_mnt(root.mnt)) | 2216 | if (!check_mnt(root.mnt)) |
| 2224 | goto out2; | 2217 | goto out2; |
| 2225 | error = -ENOENT; | 2218 | error = -ENOENT; |
| 2226 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) | 2219 | if (IS_DEADDIR(new.dentry->d_inode)) |
| 2227 | goto out2; | 2220 | goto out2; |
| 2228 | if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) | 2221 | if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry)) |
| 2229 | goto out2; | 2222 | goto out2; |
| 2230 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) | 2223 | if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry)) |
| 2231 | goto out2; | 2224 | goto out2; |
| 2232 | error = -EBUSY; | 2225 | error = -EBUSY; |
| 2233 | if (new_nd.path.mnt == root.mnt || | 2226 | if (new.mnt == root.mnt || |
| 2234 | old_nd.path.mnt == root.mnt) | 2227 | old.mnt == root.mnt) |
| 2235 | goto out2; /* loop, on the same file system */ | 2228 | goto out2; /* loop, on the same file system */ |
| 2236 | error = -EINVAL; | 2229 | error = -EINVAL; |
| 2237 | if (root.mnt->mnt_root != root.dentry) | 2230 | if (root.mnt->mnt_root != root.dentry) |
| 2238 | goto out2; /* not a mountpoint */ | 2231 | goto out2; /* not a mountpoint */ |
| 2239 | if (root.mnt->mnt_parent == root.mnt) | 2232 | if (root.mnt->mnt_parent == root.mnt) |
| 2240 | goto out2; /* not attached */ | 2233 | goto out2; /* not attached */ |
| 2241 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) | 2234 | if (new.mnt->mnt_root != new.dentry) |
| 2242 | goto out2; /* not a mountpoint */ | 2235 | goto out2; /* not a mountpoint */ |
| 2243 | if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) | 2236 | if (new.mnt->mnt_parent == new.mnt) |
| 2244 | goto out2; /* not attached */ | 2237 | goto out2; /* not attached */ |
| 2245 | /* make sure we can reach put_old from new_root */ | 2238 | /* make sure we can reach put_old from new_root */ |
| 2246 | tmp = old_nd.path.mnt; | 2239 | tmp = old.mnt; |
| 2247 | spin_lock(&vfsmount_lock); | 2240 | spin_lock(&vfsmount_lock); |
| 2248 | if (tmp != new_nd.path.mnt) { | 2241 | if (tmp != new.mnt) { |
| 2249 | for (;;) { | 2242 | for (;;) { |
| 2250 | if (tmp->mnt_parent == tmp) | 2243 | if (tmp->mnt_parent == tmp) |
| 2251 | goto out3; /* already mounted on put_old */ | 2244 | goto out3; /* already mounted on put_old */ |
| 2252 | if (tmp->mnt_parent == new_nd.path.mnt) | 2245 | if (tmp->mnt_parent == new.mnt) |
| 2253 | break; | 2246 | break; |
| 2254 | tmp = tmp->mnt_parent; | 2247 | tmp = tmp->mnt_parent; |
| 2255 | } | 2248 | } |
| 2256 | if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) | 2249 | if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) |
| 2257 | goto out3; | 2250 | goto out3; |
| 2258 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 2251 | } else if (!is_subdir(old.dentry, new.dentry)) |
| 2259 | goto out3; | 2252 | goto out3; |
| 2260 | detach_mnt(new_nd.path.mnt, &parent_path); | 2253 | detach_mnt(new.mnt, &parent_path); |
| 2261 | detach_mnt(root.mnt, &root_parent); | 2254 | detach_mnt(root.mnt, &root_parent); |
| 2262 | /* mount old root on put_old */ | 2255 | /* mount old root on put_old */ |
| 2263 | attach_mnt(root.mnt, &old_nd.path); | 2256 | attach_mnt(root.mnt, &old); |
| 2264 | /* mount new_root on / */ | 2257 | /* mount new_root on / */ |
| 2265 | attach_mnt(new_nd.path.mnt, &root_parent); | 2258 | attach_mnt(new.mnt, &root_parent); |
| 2266 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2259 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
| 2267 | spin_unlock(&vfsmount_lock); | 2260 | spin_unlock(&vfsmount_lock); |
| 2268 | chroot_fs_refs(&root, &new_nd.path); | 2261 | chroot_fs_refs(&root, &new); |
| 2269 | security_sb_post_pivotroot(&root, &new_nd.path); | 2262 | security_sb_post_pivotroot(&root, &new); |
| 2270 | error = 0; | 2263 | error = 0; |
| 2271 | path_put(&root_parent); | 2264 | path_put(&root_parent); |
| 2272 | path_put(&parent_path); | 2265 | path_put(&parent_path); |
| 2273 | out2: | 2266 | out2: |
| 2274 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 2267 | mutex_unlock(&old.dentry->d_inode->i_mutex); |
| 2275 | up_write(&namespace_sem); | 2268 | up_write(&namespace_sem); |
| 2276 | path_put(&root); | 2269 | path_put(&root); |
| 2277 | path_put(&old_nd.path); | 2270 | path_put(&old); |
| 2278 | out1: | 2271 | out1: |
| 2279 | path_put(&new_nd.path); | 2272 | path_put(&new); |
| 2280 | out0: | 2273 | out0: |
| 2281 | return error; | 2274 | return error; |
| 2282 | out3: | 2275 | out3: |
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 011ef0b6d2d4..07e9715b8658 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
| @@ -266,7 +266,7 @@ leave_me:; | |||
| 266 | 266 | ||
| 267 | 267 | ||
| 268 | static int | 268 | static int |
| 269 | __ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) | 269 | __ncp_lookup_validate(struct dentry *dentry) |
| 270 | { | 270 | { |
| 271 | struct ncp_server *server; | 271 | struct ncp_server *server; |
| 272 | struct dentry *parent; | 272 | struct dentry *parent; |
| @@ -340,7 +340,7 @@ ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) | |||
| 340 | { | 340 | { |
| 341 | int res; | 341 | int res; |
| 342 | lock_kernel(); | 342 | lock_kernel(); |
| 343 | res = __ncp_lookup_validate(dentry, nd); | 343 | res = __ncp_lookup_validate(dentry); |
| 344 | unlock_kernel(); | 344 | unlock_kernel(); |
| 345 | return res; | 345 | return res; |
| 346 | } | 346 | } |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 2e5ab1204dec..d642f0e5b365 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
| @@ -64,7 +64,7 @@ static void ncp_destroy_inode(struct inode *inode) | |||
| 64 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); | 64 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static void init_once(struct kmem_cache *cachep, void *foo) | 67 | static void init_once(void *foo) |
| 68 | { | 68 | { |
| 69 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; | 69 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; |
| 70 | 70 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 28a238dab23a..74f92b717f78 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -1884,7 +1884,7 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) | |||
| 1884 | return status; | 1884 | return status; |
| 1885 | nfs_access_add_cache(inode, &cache); | 1885 | nfs_access_add_cache(inode, &cache); |
| 1886 | out: | 1886 | out: |
| 1887 | if ((cache.mask & mask) == mask) | 1887 | if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
| 1888 | return 0; | 1888 | return 0; |
| 1889 | return -EACCES; | 1889 | return -EACCES; |
| 1890 | } | 1890 | } |
| @@ -1907,17 +1907,17 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) | |||
| 1907 | return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); | 1907 | return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); |
| 1908 | } | 1908 | } |
| 1909 | 1909 | ||
| 1910 | int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) | 1910 | int nfs_permission(struct inode *inode, int mask) |
| 1911 | { | 1911 | { |
| 1912 | struct rpc_cred *cred; | 1912 | struct rpc_cred *cred; |
| 1913 | int res = 0; | 1913 | int res = 0; |
| 1914 | 1914 | ||
| 1915 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); | 1915 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); |
| 1916 | 1916 | ||
| 1917 | if (mask == 0) | 1917 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
| 1918 | goto out; | 1918 | goto out; |
| 1919 | /* Is this sys_access() ? */ | 1919 | /* Is this sys_access() ? */ |
| 1920 | if (nd != NULL && (nd->flags & LOOKUP_ACCESS)) | 1920 | if (mask & MAY_ACCESS) |
| 1921 | goto force_lookup; | 1921 | goto force_lookup; |
| 1922 | 1922 | ||
| 1923 | switch (inode->i_mode & S_IFMT) { | 1923 | switch (inode->i_mode & S_IFMT) { |
| @@ -1926,8 +1926,7 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 1926 | case S_IFREG: | 1926 | case S_IFREG: |
| 1927 | /* NFSv4 has atomic_open... */ | 1927 | /* NFSv4 has atomic_open... */ |
| 1928 | if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN) | 1928 | if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN) |
| 1929 | && nd != NULL | 1929 | && (mask & MAY_OPEN)) |
| 1930 | && (nd->flags & LOOKUP_OPEN)) | ||
| 1931 | goto out; | 1930 | goto out; |
| 1932 | break; | 1931 | break; |
| 1933 | case S_IFDIR: | 1932 | case S_IFDIR: |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index df23f987da6b..52daefa2f521 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -1242,7 +1242,7 @@ static inline void nfs4_init_once(struct nfs_inode *nfsi) | |||
| 1242 | #endif | 1242 | #endif |
| 1243 | } | 1243 | } |
| 1244 | 1244 | ||
| 1245 | static void init_once(struct kmem_cache * cachep, void *foo) | 1245 | static void init_once(void *foo) |
| 1246 | { | 1246 | { |
| 1247 | struct nfs_inode *nfsi = (struct nfs_inode *) foo; | 1247 | struct nfs_inode *nfsi = (struct nfs_inode *) foo; |
| 1248 | 1248 | ||
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 2f285ef76399..66df08dd1caf 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -129,7 +129,7 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) | |||
| 129 | goto out_err; | 129 | goto out_err; |
| 130 | 130 | ||
| 131 | mntget(mnt); | 131 | mntget(mnt); |
| 132 | err = do_add_mount(mnt, nd, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, | 132 | err = do_add_mount(mnt, &nd->path, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, |
| 133 | &nfs_automount_list); | 133 | &nfs_automount_list); |
| 134 | if (err < 0) { | 134 | if (err < 0) { |
| 135 | mntput(mnt); | 135 | mntput(mnt); |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8478fc25daee..46763d1cd397 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
| @@ -127,7 +127,7 @@ enum { | |||
| 127 | Opt_err | 127 | Opt_err |
| 128 | }; | 128 | }; |
| 129 | 129 | ||
| 130 | static match_table_t __initconst tokens = { | 130 | static match_table_t __initdata tokens = { |
| 131 | {Opt_port, "port=%u"}, | 131 | {Opt_port, "port=%u"}, |
| 132 | {Opt_rsize, "rsize=%u"}, | 132 | {Opt_rsize, "rsize=%u"}, |
| 133 | {Opt_wsize, "wsize=%u"}, | 133 | {Opt_wsize, "wsize=%u"}, |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1b94e3650f5c..e9b20173fef3 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -1279,6 +1279,12 @@ static int nfs_parse_mount_options(char *raw, | |||
| 1279 | } | 1279 | } |
| 1280 | } | 1280 | } |
| 1281 | 1281 | ||
| 1282 | if (errors > 0) { | ||
| 1283 | dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", | ||
| 1284 | errors, (errors == 1 ? "" : "s")); | ||
| 1285 | if (!sloppy) | ||
| 1286 | return 0; | ||
| 1287 | } | ||
| 1282 | return 1; | 1288 | return 1; |
| 1283 | 1289 | ||
| 1284 | out_nomem: | 1290 | out_nomem: |
| @@ -1718,9 +1724,9 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
| 1718 | * ones were explicitly specified. Fall back to legacy behavior and | 1724 | * ones were explicitly specified. Fall back to legacy behavior and |
| 1719 | * just return success. | 1725 | * just return success. |
| 1720 | */ | 1726 | */ |
| 1721 | if ((nfsvers == 4 && options4->version == 1) || | 1727 | if ((nfsvers == 4 && (!options4 || options4->version == 1)) || |
| 1722 | (nfsvers <= 3 && options->version >= 1 && | 1728 | (nfsvers <= 3 && (!options || (options->version >= 1 && |
| 1723 | options->version <= 6)) | 1729 | options->version <= 6)))) |
| 1724 | return 0; | 1730 | return 0; |
| 1725 | 1731 | ||
| 1726 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 1732 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 3adf8b266461..f089e5839d7d 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -95,10 +95,11 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
| 95 | static void nfs_async_unlink_release(void *calldata) | 95 | static void nfs_async_unlink_release(void *calldata) |
| 96 | { | 96 | { |
| 97 | struct nfs_unlinkdata *data = calldata; | 97 | struct nfs_unlinkdata *data = calldata; |
| 98 | struct super_block *sb = data->dir->i_sb; | ||
| 98 | 99 | ||
| 99 | nfs_dec_sillycount(data->dir); | 100 | nfs_dec_sillycount(data->dir); |
| 100 | nfs_sb_deactive(NFS_SERVER(data->dir)); | ||
| 101 | nfs_free_unlinkdata(data); | 101 | nfs_free_unlinkdata(data); |
| 102 | nfs_sb_deactive(NFS_SB(sb)); | ||
| 102 | } | 103 | } |
| 103 | 104 | ||
| 104 | static const struct rpc_call_ops nfs_unlink_ops = { | 105 | static const struct rpc_call_ops nfs_unlink_ops = { |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 33bfcf09db46..9dc036f18356 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
| @@ -1023,7 +1023,7 @@ exp_export(struct nfsctl_export *nxp) | |||
| 1023 | /* Look up the dentry */ | 1023 | /* Look up the dentry */ |
| 1024 | err = path_lookup(nxp->ex_path, 0, &nd); | 1024 | err = path_lookup(nxp->ex_path, 0, &nd); |
| 1025 | if (err) | 1025 | if (err) |
| 1026 | goto out_unlock; | 1026 | goto out_put_clp; |
| 1027 | err = -EINVAL; | 1027 | err = -EINVAL; |
| 1028 | 1028 | ||
| 1029 | exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL); | 1029 | exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL); |
| @@ -1090,9 +1090,9 @@ finish: | |||
| 1090 | exp_put(exp); | 1090 | exp_put(exp); |
| 1091 | if (fsid_key && !IS_ERR(fsid_key)) | 1091 | if (fsid_key && !IS_ERR(fsid_key)) |
| 1092 | cache_put(&fsid_key->h, &svc_expkey_cache); | 1092 | cache_put(&fsid_key->h, &svc_expkey_cache); |
| 1093 | if (clp) | ||
| 1094 | auth_domain_put(clp); | ||
| 1095 | path_put(&nd.path); | 1093 | path_put(&nd.path); |
| 1094 | out_put_clp: | ||
| 1095 | auth_domain_put(clp); | ||
| 1096 | out_unlock: | 1096 | out_unlock: |
| 1097 | exp_writeunlock(); | 1097 | exp_writeunlock(); |
| 1098 | out: | 1098 | out: |
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 6b6225ac4926..15c6faeec77c 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c | |||
| @@ -19,6 +19,13 @@ | |||
| 19 | 19 | ||
| 20 | #define NFSDDBG_FACILITY NFSDDBG_LOCKD | 20 | #define NFSDDBG_FACILITY NFSDDBG_LOCKD |
| 21 | 21 | ||
| 22 | #ifdef CONFIG_LOCKD_V4 | ||
| 23 | #define nlm_stale_fh nlm4_stale_fh | ||
| 24 | #define nlm_failed nlm4_failed | ||
| 25 | #else | ||
| 26 | #define nlm_stale_fh nlm_lck_denied_nolocks | ||
| 27 | #define nlm_failed nlm_lck_denied_nolocks | ||
| 28 | #endif | ||
| 22 | /* | 29 | /* |
| 23 | * Note: we hold the dentry use count while the file is open. | 30 | * Note: we hold the dentry use count while the file is open. |
| 24 | */ | 31 | */ |
| @@ -47,12 +54,10 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) | |||
| 47 | return 0; | 54 | return 0; |
| 48 | case nfserr_dropit: | 55 | case nfserr_dropit: |
| 49 | return nlm_drop_reply; | 56 | return nlm_drop_reply; |
| 50 | #ifdef CONFIG_LOCKD_V4 | ||
| 51 | case nfserr_stale: | 57 | case nfserr_stale: |
| 52 | return nlm4_stale_fh; | 58 | return nlm_stale_fh; |
| 53 | #endif | ||
| 54 | default: | 59 | default: |
| 55 | return nlm_lck_denied; | 60 | return nlm_failed; |
| 56 | } | 61 | } |
| 57 | } | 62 | } |
| 58 | 63 | ||
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index b6ed38380ab8..54b8b4140c8f 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
| @@ -443,7 +443,7 @@ init_state(struct posix_acl_state *state, int cnt) | |||
| 443 | * enough space for either: | 443 | * enough space for either: |
| 444 | */ | 444 | */ |
| 445 | alloc = sizeof(struct posix_ace_state_array) | 445 | alloc = sizeof(struct posix_ace_state_array) |
| 446 | + cnt*sizeof(struct posix_ace_state); | 446 | + cnt*sizeof(struct posix_user_ace_state); |
| 447 | state->users = kzalloc(alloc, GFP_KERNEL); | 447 | state->users = kzalloc(alloc, GFP_KERNEL); |
| 448 | if (!state->users) | 448 | if (!state->users) |
| 449 | return -ENOMEM; | 449 | return -ENOMEM; |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index eef1629806f5..e5b51ffafc6c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
| @@ -851,7 +851,7 @@ struct nfsd4_operation { | |||
| 851 | 851 | ||
| 852 | static struct nfsd4_operation nfsd4_ops[]; | 852 | static struct nfsd4_operation nfsd4_ops[]; |
| 853 | 853 | ||
| 854 | static inline char *nfsd4_op_name(unsigned opnum); | 854 | static const char *nfsd4_op_name(unsigned opnum); |
| 855 | 855 | ||
| 856 | /* | 856 | /* |
| 857 | * COMPOUND call. | 857 | * COMPOUND call. |
| @@ -867,11 +867,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
| 867 | int slack_bytes; | 867 | int slack_bytes; |
| 868 | __be32 status; | 868 | __be32 status; |
| 869 | 869 | ||
| 870 | status = nfserr_resource; | ||
| 871 | cstate = cstate_alloc(); | ||
| 872 | if (cstate == NULL) | ||
| 873 | goto out; | ||
| 874 | |||
| 875 | resp->xbuf = &rqstp->rq_res; | 870 | resp->xbuf = &rqstp->rq_res; |
| 876 | resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; | 871 | resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; |
| 877 | resp->tagp = resp->p; | 872 | resp->tagp = resp->p; |
| @@ -890,6 +885,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
| 890 | if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) | 885 | if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) |
| 891 | goto out; | 886 | goto out; |
| 892 | 887 | ||
| 888 | status = nfserr_resource; | ||
| 889 | cstate = cstate_alloc(); | ||
| 890 | if (cstate == NULL) | ||
| 891 | goto out; | ||
| 892 | |||
| 893 | status = nfs_ok; | 893 | status = nfs_ok; |
| 894 | while (!status && resp->opcnt < args->opcnt) { | 894 | while (!status && resp->opcnt < args->opcnt) { |
| 895 | op = &args->ops[resp->opcnt++]; | 895 | op = &args->ops[resp->opcnt++]; |
| @@ -957,9 +957,9 @@ encode_op: | |||
| 957 | nfsd4_increment_op_stats(op->opnum); | 957 | nfsd4_increment_op_stats(op->opnum); |
| 958 | } | 958 | } |
| 959 | 959 | ||
| 960 | cstate_free(cstate); | ||
| 960 | out: | 961 | out: |
| 961 | nfsd4_release_compoundargs(args); | 962 | nfsd4_release_compoundargs(args); |
| 962 | cstate_free(cstate); | ||
| 963 | dprintk("nfsv4 compound returned %d\n", ntohl(status)); | 963 | dprintk("nfsv4 compound returned %d\n", ntohl(status)); |
| 964 | return status; | 964 | return status; |
| 965 | } | 965 | } |
| @@ -1116,8 +1116,7 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { | |||
| 1116 | }, | 1116 | }, |
| 1117 | }; | 1117 | }; |
| 1118 | 1118 | ||
| 1119 | static inline char * | 1119 | static const char *nfsd4_op_name(unsigned opnum) |
| 1120 | nfsd4_op_name(unsigned opnum) | ||
| 1121 | { | 1120 | { |
| 1122 | if (opnum < ARRAY_SIZE(nfsd4_ops)) | 1121 | if (opnum < ARRAY_SIZE(nfsd4_ops)) |
| 1123 | return nfsd4_ops[opnum].op_name; | 1122 | return nfsd4_ops[opnum].op_name; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 1955a2702e60..c53e65f8f3a2 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| 13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
| 14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
| 15 | #include <linux/namei.h> | ||
| 15 | #include <linux/fcntl.h> | 16 | #include <linux/fcntl.h> |
| 16 | #include <linux/net.h> | 17 | #include <linux/net.h> |
| 17 | #include <linux/in.h> | 18 | #include <linux/in.h> |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index f45451eb1e38..ea37c96f0445 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
| @@ -51,7 +51,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) | |||
| 51 | /* make sure parents give x permission to user */ | 51 | /* make sure parents give x permission to user */ |
| 52 | int err; | 52 | int err; |
| 53 | parent = dget_parent(tdentry); | 53 | parent = dget_parent(tdentry); |
| 54 | err = permission(parent->d_inode, MAY_EXEC, NULL); | 54 | err = inode_permission(parent->d_inode, MAY_EXEC); |
| 55 | if (err < 0) { | 55 | if (err < 0) { |
| 56 | dput(parent); | 56 | dput(parent); |
| 57 | break; | 57 | break; |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 0f4481e0502d..18060bed5267 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -1516,7 +1516,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1516 | struct dentry *dentry, *dnew; | 1516 | struct dentry *dentry, *dnew; |
| 1517 | __be32 err, cerr; | 1517 | __be32 err, cerr; |
| 1518 | int host_err; | 1518 | int host_err; |
| 1519 | umode_t mode; | ||
| 1520 | 1519 | ||
| 1521 | err = nfserr_noent; | 1520 | err = nfserr_noent; |
| 1522 | if (!flen || !plen) | 1521 | if (!flen || !plen) |
| @@ -1535,11 +1534,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1535 | if (IS_ERR(dnew)) | 1534 | if (IS_ERR(dnew)) |
| 1536 | goto out_nfserr; | 1535 | goto out_nfserr; |
| 1537 | 1536 | ||
| 1538 | mode = S_IALLUGO; | ||
| 1539 | /* Only the MODE ATTRibute is even vaguely meaningful */ | ||
| 1540 | if (iap && (iap->ia_valid & ATTR_MODE)) | ||
| 1541 | mode = iap->ia_mode & S_IALLUGO; | ||
| 1542 | |||
| 1543 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | 1537 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); |
| 1544 | if (host_err) | 1538 | if (host_err) |
| 1545 | goto out_nfserr; | 1539 | goto out_nfserr; |
| @@ -1551,11 +1545,11 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1551 | else { | 1545 | else { |
| 1552 | strncpy(path_alloced, path, plen); | 1546 | strncpy(path_alloced, path, plen); |
| 1553 | path_alloced[plen] = 0; | 1547 | path_alloced[plen] = 0; |
| 1554 | host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); | 1548 | host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced); |
| 1555 | kfree(path_alloced); | 1549 | kfree(path_alloced); |
| 1556 | } | 1550 | } |
| 1557 | } else | 1551 | } else |
| 1558 | host_err = vfs_symlink(dentry->d_inode, dnew, path, mode); | 1552 | host_err = vfs_symlink(dentry->d_inode, dnew, path); |
| 1559 | 1553 | ||
| 1560 | if (!host_err) { | 1554 | if (!host_err) { |
| 1561 | if (EX_ISSYNC(fhp->fh_export)) | 1555 | if (EX_ISSYNC(fhp->fh_export)) |
| @@ -1959,12 +1953,12 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
| 1959 | return 0; | 1953 | return 0; |
| 1960 | 1954 | ||
| 1961 | /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ | 1955 | /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ |
| 1962 | err = permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC), NULL); | 1956 | err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); |
| 1963 | 1957 | ||
| 1964 | /* Allow read access to binaries even when mode 111 */ | 1958 | /* Allow read access to binaries even when mode 111 */ |
| 1965 | if (err == -EACCES && S_ISREG(inode->i_mode) && | 1959 | if (err == -EACCES && S_ISREG(inode->i_mode) && |
| 1966 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) | 1960 | acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) |
| 1967 | err = permission(inode, MAY_EXEC, NULL); | 1961 | err = inode_permission(inode, MAY_EXEC); |
| 1968 | 1962 | ||
| 1969 | return err? nfserrno(err) : 0; | 1963 | return err? nfserrno(err) : 0; |
| 1970 | } | 1964 | } |
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 00e9ccde8e42..b38f944f0667 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c | |||
| @@ -1194,7 +1194,7 @@ lock_retry_remap: | |||
| 1194 | tbh = bhs[i]; | 1194 | tbh = bhs[i]; |
| 1195 | if (!tbh) | 1195 | if (!tbh) |
| 1196 | continue; | 1196 | continue; |
| 1197 | if (unlikely(test_set_buffer_locked(tbh))) | 1197 | if (!trylock_buffer(tbh)) |
| 1198 | BUG(); | 1198 | BUG(); |
| 1199 | /* The buffer dirty state is now irrelevant, just clean it. */ | 1199 | /* The buffer dirty state is now irrelevant, just clean it. */ |
| 1200 | clear_buffer_dirty(tbh); | 1200 | clear_buffer_dirty(tbh); |
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index 33ff314cc507..9669541d0119 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c | |||
| @@ -665,7 +665,7 @@ lock_retry_remap: | |||
| 665 | for (i = 0; i < nr_bhs; i++) { | 665 | for (i = 0; i < nr_bhs; i++) { |
| 666 | struct buffer_head *tbh = bhs[i]; | 666 | struct buffer_head *tbh = bhs[i]; |
| 667 | 667 | ||
| 668 | if (unlikely(test_set_buffer_locked(tbh))) | 668 | if (!trylock_buffer(tbh)) |
| 669 | continue; | 669 | continue; |
| 670 | if (unlikely(buffer_uptodate(tbh))) { | 670 | if (unlikely(buffer_uptodate(tbh))) { |
| 671 | unlock_buffer(tbh); | 671 | unlock_buffer(tbh); |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 3c5550cd11d6..d020866d4232 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
| @@ -2118,7 +2118,7 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, | |||
| 2118 | goto out; | 2118 | goto out; |
| 2119 | if (!count) | 2119 | if (!count) |
| 2120 | goto out; | 2120 | goto out; |
| 2121 | err = remove_suid(file->f_path.dentry); | 2121 | err = file_remove_suid(file); |
| 2122 | if (err) | 2122 | if (err) |
| 2123 | goto out; | 2123 | goto out; |
| 2124 | file_update_time(file); | 2124 | file_update_time(file); |
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 790defb847e7..17d32ca6bc35 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c | |||
| @@ -586,7 +586,7 @@ int ntfs_sync_mft_mirror(ntfs_volume *vol, const unsigned long mft_no, | |||
| 586 | for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { | 586 | for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { |
| 587 | struct buffer_head *tbh = bhs[i_bhs]; | 587 | struct buffer_head *tbh = bhs[i_bhs]; |
| 588 | 588 | ||
| 589 | if (unlikely(test_set_buffer_locked(tbh))) | 589 | if (!trylock_buffer(tbh)) |
| 590 | BUG(); | 590 | BUG(); |
| 591 | BUG_ON(!buffer_uptodate(tbh)); | 591 | BUG_ON(!buffer_uptodate(tbh)); |
| 592 | clear_buffer_dirty(tbh); | 592 | clear_buffer_dirty(tbh); |
| @@ -779,7 +779,7 @@ int write_mft_record_nolock(ntfs_inode *ni, MFT_RECORD *m, int sync) | |||
| 779 | for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { | 779 | for (i_bhs = 0; i_bhs < nr_bhs; i_bhs++) { |
| 780 | struct buffer_head *tbh = bhs[i_bhs]; | 780 | struct buffer_head *tbh = bhs[i_bhs]; |
| 781 | 781 | ||
| 782 | if (unlikely(test_set_buffer_locked(tbh))) | 782 | if (!trylock_buffer(tbh)) |
| 783 | BUG(); | 783 | BUG(); |
| 784 | BUG_ON(!buffer_uptodate(tbh)); | 784 | BUG_ON(!buffer_uptodate(tbh)); |
| 785 | clear_buffer_dirty(tbh); | 785 | clear_buffer_dirty(tbh); |
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index e1781c8b1650..9e8a95be7a1e 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c | |||
| @@ -174,7 +174,6 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent, | |||
| 174 | // TODO: Consider moving this lot to a separate function! (AIA) | 174 | // TODO: Consider moving this lot to a separate function! (AIA) |
| 175 | handle_name: | 175 | handle_name: |
| 176 | { | 176 | { |
| 177 | struct dentry *real_dent, *new_dent; | ||
| 178 | MFT_RECORD *m; | 177 | MFT_RECORD *m; |
| 179 | ntfs_attr_search_ctx *ctx; | 178 | ntfs_attr_search_ctx *ctx; |
| 180 | ntfs_inode *ni = NTFS_I(dent_inode); | 179 | ntfs_inode *ni = NTFS_I(dent_inode); |
| @@ -255,93 +254,9 @@ handle_name: | |||
| 255 | } | 254 | } |
| 256 | nls_name.hash = full_name_hash(nls_name.name, nls_name.len); | 255 | nls_name.hash = full_name_hash(nls_name.name, nls_name.len); |
| 257 | 256 | ||
| 258 | /* | 257 | dent = d_add_ci(dent, dent_inode, &nls_name); |
| 259 | * Note: No need for dent->d_lock lock as i_mutex is held on the | ||
| 260 | * parent inode. | ||
| 261 | */ | ||
| 262 | |||
| 263 | /* Does a dentry matching the nls_name exist already? */ | ||
| 264 | real_dent = d_lookup(dent->d_parent, &nls_name); | ||
| 265 | /* If not, create it now. */ | ||
| 266 | if (!real_dent) { | ||
| 267 | real_dent = d_alloc(dent->d_parent, &nls_name); | ||
| 268 | kfree(nls_name.name); | ||
| 269 | if (!real_dent) { | ||
| 270 | err = -ENOMEM; | ||
| 271 | goto err_out; | ||
| 272 | } | ||
| 273 | new_dent = d_splice_alias(dent_inode, real_dent); | ||
| 274 | if (new_dent) | ||
| 275 | dput(real_dent); | ||
| 276 | else | ||
| 277 | new_dent = real_dent; | ||
| 278 | ntfs_debug("Done. (Created new dentry.)"); | ||
| 279 | return new_dent; | ||
| 280 | } | ||
| 281 | kfree(nls_name.name); | 258 | kfree(nls_name.name); |
| 282 | /* Matching dentry exists, check if it is negative. */ | 259 | return dent; |
| 283 | if (real_dent->d_inode) { | ||
| 284 | if (unlikely(real_dent->d_inode != dent_inode)) { | ||
| 285 | /* This can happen because bad inodes are unhashed. */ | ||
| 286 | BUG_ON(!is_bad_inode(dent_inode)); | ||
| 287 | BUG_ON(!is_bad_inode(real_dent->d_inode)); | ||
| 288 | } | ||
| 289 | /* | ||
| 290 | * Already have the inode and the dentry attached, decrement | ||
| 291 | * the reference count to balance the ntfs_iget() we did | ||
| 292 | * earlier on. We found the dentry using d_lookup() so it | ||
| 293 | * cannot be disconnected and thus we do not need to worry | ||
| 294 | * about any NFS/disconnectedness issues here. | ||
| 295 | */ | ||
| 296 | iput(dent_inode); | ||
| 297 | ntfs_debug("Done. (Already had inode and dentry.)"); | ||
| 298 | return real_dent; | ||
| 299 | } | ||
| 300 | /* | ||
| 301 | * Negative dentry: instantiate it unless the inode is a directory and | ||
| 302 | * has a 'disconnected' dentry (i.e. IS_ROOT and DCACHE_DISCONNECTED), | ||
| 303 | * in which case d_move() that in place of the found dentry. | ||
| 304 | */ | ||
| 305 | if (!S_ISDIR(dent_inode->i_mode)) { | ||
| 306 | /* Not a directory; everything is easy. */ | ||
| 307 | d_instantiate(real_dent, dent_inode); | ||
| 308 | ntfs_debug("Done. (Already had negative file dentry.)"); | ||
| 309 | return real_dent; | ||
| 310 | } | ||
| 311 | spin_lock(&dcache_lock); | ||
| 312 | if (list_empty(&dent_inode->i_dentry)) { | ||
| 313 | /* | ||
| 314 | * Directory without a 'disconnected' dentry; we need to do | ||
| 315 | * d_instantiate() by hand because it takes dcache_lock which | ||
| 316 | * we already hold. | ||
| 317 | */ | ||
| 318 | list_add(&real_dent->d_alias, &dent_inode->i_dentry); | ||
| 319 | real_dent->d_inode = dent_inode; | ||
| 320 | spin_unlock(&dcache_lock); | ||
| 321 | security_d_instantiate(real_dent, dent_inode); | ||
| 322 | ntfs_debug("Done. (Already had negative directory dentry.)"); | ||
| 323 | return real_dent; | ||
| 324 | } | ||
| 325 | /* | ||
| 326 | * Directory with a 'disconnected' dentry; get a reference to the | ||
| 327 | * 'disconnected' dentry. | ||
| 328 | */ | ||
| 329 | new_dent = list_entry(dent_inode->i_dentry.next, struct dentry, | ||
| 330 | d_alias); | ||
| 331 | dget_locked(new_dent); | ||
| 332 | spin_unlock(&dcache_lock); | ||
| 333 | /* Do security vodoo. */ | ||
| 334 | security_d_instantiate(real_dent, dent_inode); | ||
| 335 | /* Move new_dent in place of real_dent. */ | ||
| 336 | d_move(new_dent, real_dent); | ||
| 337 | /* Balance the ntfs_iget() we did above. */ | ||
| 338 | iput(dent_inode); | ||
| 339 | /* Throw away real_dent. */ | ||
| 340 | dput(real_dent); | ||
| 341 | /* Use new_dent as the actual dentry. */ | ||
| 342 | ntfs_debug("Done. (Already had negative, disconnected directory " | ||
| 343 | "dentry.)"); | ||
| 344 | return new_dent; | ||
| 345 | 260 | ||
| 346 | eio_err_out: | 261 | eio_err_out: |
| 347 | ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk."); | 262 | ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk."); |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 3e76f3b216bc..4a46743b5077 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
| @@ -3080,7 +3080,7 @@ struct kmem_cache *ntfs_inode_cache; | |||
| 3080 | struct kmem_cache *ntfs_big_inode_cache; | 3080 | struct kmem_cache *ntfs_big_inode_cache; |
| 3081 | 3081 | ||
| 3082 | /* Init once constructor for the inode slab cache. */ | 3082 | /* Init once constructor for the inode slab cache. */ |
| 3083 | static void ntfs_big_inode_init_once(struct kmem_cache *cachep, void *foo) | 3083 | static void ntfs_big_inode_init_once(void *foo) |
| 3084 | { | 3084 | { |
| 3085 | ntfs_inode *ni = (ntfs_inode *)foo; | 3085 | ntfs_inode *ni = (ntfs_inode *)foo; |
| 3086 | 3086 | ||
diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h index 3a8af75351e8..4087fbdac327 100644 --- a/fs/ntfs/usnjrnl.h +++ b/fs/ntfs/usnjrnl.h | |||
| @@ -113,7 +113,7 @@ typedef struct { | |||
| 113 | * Reason flags (32-bit). Cumulative flags describing the change(s) to the | 113 | * Reason flags (32-bit). Cumulative flags describing the change(s) to the |
| 114 | * file since it was last opened. I think the names speak for themselves but | 114 | * file since it was last opened. I think the names speak for themselves but |
| 115 | * if you disagree check out the descriptions in the Linux NTFS project NTFS | 115 | * if you disagree check out the descriptions in the Linux NTFS project NTFS |
| 116 | * documentation: http://linux-ntfs.sourceforge.net/ntfs/files/usnjrnl.html | 116 | * documentation: http://www.linux-ntfs.org/ |
| 117 | */ | 117 | */ |
| 118 | enum { | 118 | enum { |
| 119 | USN_REASON_DATA_OVERWRITE = const_cpu_to_le32(0x00000001), | 119 | USN_REASON_DATA_OVERWRITE = const_cpu_to_le32(0x00000001), |
| @@ -145,7 +145,7 @@ typedef le32 USN_REASON_FLAGS; | |||
| 145 | * Source info flags (32-bit). Information about the source of the change(s) | 145 | * Source info flags (32-bit). Information about the source of the change(s) |
| 146 | * to the file. For detailed descriptions of what these mean, see the Linux | 146 | * to the file. For detailed descriptions of what these mean, see the Linux |
| 147 | * NTFS project NTFS documentation: | 147 | * NTFS project NTFS documentation: |
| 148 | * http://linux-ntfs.sourceforge.net/ntfs/files/usnjrnl.html | 148 | * http://www.linux-ntfs.org/ |
| 149 | */ | 149 | */ |
| 150 | enum { | 150 | enum { |
| 151 | USN_SOURCE_DATA_MANAGEMENT = const_cpu_to_le32(0x00000001), | 151 | USN_SOURCE_DATA_MANAGEMENT = const_cpu_to_le32(0x00000001), |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 1db080135c6d..a53da1466277 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
| @@ -594,7 +594,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, | |||
| 594 | goto bail; | 594 | goto bail; |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno) { | 597 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)) && !p_blkno && create) { |
| 598 | ocfs2_error(inode->i_sb, | 598 | ocfs2_error(inode->i_sb, |
| 599 | "Inode %llu has a hole at block %llu\n", | 599 | "Inode %llu has a hole at block %llu\n", |
| 600 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | 600 | (unsigned long long)OCFS2_I(inode)->ip_blkno, |
| @@ -1073,12 +1073,15 @@ static void ocfs2_write_failure(struct inode *inode, | |||
| 1073 | for(i = 0; i < wc->w_num_pages; i++) { | 1073 | for(i = 0; i < wc->w_num_pages; i++) { |
| 1074 | tmppage = wc->w_pages[i]; | 1074 | tmppage = wc->w_pages[i]; |
| 1075 | 1075 | ||
| 1076 | if (ocfs2_should_order_data(inode)) | 1076 | if (page_has_buffers(tmppage)) { |
| 1077 | walk_page_buffers(wc->w_handle, page_buffers(tmppage), | 1077 | if (ocfs2_should_order_data(inode)) |
| 1078 | from, to, NULL, | 1078 | walk_page_buffers(wc->w_handle, |
| 1079 | ocfs2_journal_dirty_data); | 1079 | page_buffers(tmppage), |
| 1080 | from, to, NULL, | ||
| 1081 | ocfs2_journal_dirty_data); | ||
| 1080 | 1082 | ||
| 1081 | block_commit_write(tmppage, from, to); | 1083 | block_commit_write(tmppage, from, to); |
| 1084 | } | ||
| 1082 | } | 1085 | } |
| 1083 | } | 1086 | } |
| 1084 | 1087 | ||
| @@ -1901,12 +1904,14 @@ int ocfs2_write_end_nolock(struct address_space *mapping, | |||
| 1901 | to = PAGE_CACHE_SIZE; | 1904 | to = PAGE_CACHE_SIZE; |
| 1902 | } | 1905 | } |
| 1903 | 1906 | ||
| 1904 | if (ocfs2_should_order_data(inode)) | 1907 | if (page_has_buffers(tmppage)) { |
| 1905 | walk_page_buffers(wc->w_handle, page_buffers(tmppage), | 1908 | if (ocfs2_should_order_data(inode)) |
| 1906 | from, to, NULL, | 1909 | walk_page_buffers(wc->w_handle, |
| 1907 | ocfs2_journal_dirty_data); | 1910 | page_buffers(tmppage), |
| 1908 | 1911 | from, to, NULL, | |
| 1909 | block_commit_write(tmppage, from, to); | 1912 | ocfs2_journal_dirty_data); |
| 1913 | block_commit_write(tmppage, from, to); | ||
| 1914 | } | ||
| 1910 | } | 1915 | } |
| 1911 | 1916 | ||
| 1912 | out_write_size: | 1917 | out_write_size: |
diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index d8bfa0eb41b2..52276c02f710 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c | |||
| @@ -138,20 +138,20 @@ static int nst_seq_show(struct seq_file *seq, void *v) | |||
| 138 | " message id: %d\n" | 138 | " message id: %d\n" |
| 139 | " message type: %u\n" | 139 | " message type: %u\n" |
| 140 | " message key: 0x%08x\n" | 140 | " message key: 0x%08x\n" |
| 141 | " sock acquiry: %lu.%lu\n" | 141 | " sock acquiry: %lu.%ld\n" |
| 142 | " send start: %lu.%lu\n" | 142 | " send start: %lu.%ld\n" |
| 143 | " wait start: %lu.%lu\n", | 143 | " wait start: %lu.%ld\n", |
| 144 | nst, (unsigned long)nst->st_task->pid, | 144 | nst, (unsigned long)nst->st_task->pid, |
| 145 | (unsigned long)nst->st_task->tgid, | 145 | (unsigned long)nst->st_task->tgid, |
| 146 | nst->st_task->comm, nst->st_node, | 146 | nst->st_task->comm, nst->st_node, |
| 147 | nst->st_sc, nst->st_id, nst->st_msg_type, | 147 | nst->st_sc, nst->st_id, nst->st_msg_type, |
| 148 | nst->st_msg_key, | 148 | nst->st_msg_key, |
| 149 | nst->st_sock_time.tv_sec, | 149 | nst->st_sock_time.tv_sec, |
| 150 | (unsigned long)nst->st_sock_time.tv_usec, | 150 | (long)nst->st_sock_time.tv_usec, |
| 151 | nst->st_send_time.tv_sec, | 151 | nst->st_send_time.tv_sec, |
| 152 | (unsigned long)nst->st_send_time.tv_usec, | 152 | (long)nst->st_send_time.tv_usec, |
| 153 | nst->st_status_time.tv_sec, | 153 | nst->st_status_time.tv_sec, |
| 154 | nst->st_status_time.tv_usec); | 154 | (long)nst->st_status_time.tv_usec); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | spin_unlock(&o2net_debug_lock); | 157 | spin_unlock(&o2net_debug_lock); |
| @@ -276,7 +276,7 @@ static void *sc_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 276 | return sc; /* unused, just needs to be null when done */ | 276 | return sc; /* unused, just needs to be null when done */ |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | #define TV_SEC_USEC(TV) TV.tv_sec, (unsigned long)TV.tv_usec | 279 | #define TV_SEC_USEC(TV) TV.tv_sec, (long)TV.tv_usec |
| 280 | 280 | ||
| 281 | static int sc_seq_show(struct seq_file *seq, void *v) | 281 | static int sc_seq_show(struct seq_file *seq, void *v) |
| 282 | { | 282 | { |
| @@ -309,12 +309,12 @@ static int sc_seq_show(struct seq_file *seq, void *v) | |||
| 309 | " remote node: %s\n" | 309 | " remote node: %s\n" |
| 310 | " page off: %zu\n" | 310 | " page off: %zu\n" |
| 311 | " handshake ok: %u\n" | 311 | " handshake ok: %u\n" |
| 312 | " timer: %lu.%lu\n" | 312 | " timer: %lu.%ld\n" |
| 313 | " data ready: %lu.%lu\n" | 313 | " data ready: %lu.%ld\n" |
| 314 | " advance start: %lu.%lu\n" | 314 | " advance start: %lu.%ld\n" |
| 315 | " advance stop: %lu.%lu\n" | 315 | " advance stop: %lu.%ld\n" |
| 316 | " func start: %lu.%lu\n" | 316 | " func start: %lu.%ld\n" |
| 317 | " func stop: %lu.%lu\n" | 317 | " func stop: %lu.%ld\n" |
| 318 | " func key: %u\n" | 318 | " func key: %u\n" |
| 319 | " func type: %u\n", | 319 | " func type: %u\n", |
| 320 | sc, | 320 | sc, |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index a27d61581bd6..2bcf706d9dd3 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
| @@ -143,8 +143,8 @@ static void o2net_sc_postpone_idle(struct o2net_sock_container *sc); | |||
| 143 | static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc); | 143 | static void o2net_sc_reset_idle_timer(struct o2net_sock_container *sc); |
| 144 | 144 | ||
| 145 | #ifdef CONFIG_DEBUG_FS | 145 | #ifdef CONFIG_DEBUG_FS |
| 146 | void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, | 146 | static void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, |
| 147 | u32 msgkey, struct task_struct *task, u8 node) | 147 | u32 msgkey, struct task_struct *task, u8 node) |
| 148 | { | 148 | { |
| 149 | INIT_LIST_HEAD(&nst->st_net_debug_item); | 149 | INIT_LIST_HEAD(&nst->st_net_debug_item); |
| 150 | nst->st_task = task; | 150 | nst->st_task = task; |
| @@ -153,31 +153,61 @@ void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, | |||
| 153 | nst->st_node = node; | 153 | nst->st_node = node; |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) | 156 | static void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) |
| 157 | { | 157 | { |
| 158 | do_gettimeofday(&nst->st_sock_time); | 158 | do_gettimeofday(&nst->st_sock_time); |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | void o2net_set_nst_send_time(struct o2net_send_tracking *nst) | 161 | static void o2net_set_nst_send_time(struct o2net_send_tracking *nst) |
| 162 | { | 162 | { |
| 163 | do_gettimeofday(&nst->st_send_time); | 163 | do_gettimeofday(&nst->st_send_time); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | void o2net_set_nst_status_time(struct o2net_send_tracking *nst) | 166 | static void o2net_set_nst_status_time(struct o2net_send_tracking *nst) |
| 167 | { | 167 | { |
| 168 | do_gettimeofday(&nst->st_status_time); | 168 | do_gettimeofday(&nst->st_status_time); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, | 171 | static void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, |
| 172 | struct o2net_sock_container *sc) | 172 | struct o2net_sock_container *sc) |
| 173 | { | 173 | { |
| 174 | nst->st_sc = sc; | 174 | nst->st_sc = sc; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id) | 177 | static void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id) |
| 178 | { | 178 | { |
| 179 | nst->st_id = msg_id; | 179 | nst->st_id = msg_id; |
| 180 | } | 180 | } |
| 181 | |||
| 182 | #else /* CONFIG_DEBUG_FS */ | ||
| 183 | |||
| 184 | static inline void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, | ||
| 185 | u32 msgkey, struct task_struct *task, u8 node) | ||
| 186 | { | ||
| 187 | } | ||
| 188 | |||
| 189 | static inline void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) | ||
| 190 | { | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline void o2net_set_nst_send_time(struct o2net_send_tracking *nst) | ||
| 194 | { | ||
| 195 | } | ||
| 196 | |||
| 197 | static inline void o2net_set_nst_status_time(struct o2net_send_tracking *nst) | ||
| 198 | { | ||
| 199 | } | ||
| 200 | |||
| 201 | static inline void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, | ||
| 202 | struct o2net_sock_container *sc) | ||
| 203 | { | ||
| 204 | } | ||
| 205 | |||
| 206 | static inline void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, | ||
| 207 | u32 msg_id) | ||
| 208 | { | ||
| 209 | } | ||
| 210 | |||
| 181 | #endif /* CONFIG_DEBUG_FS */ | 211 | #endif /* CONFIG_DEBUG_FS */ |
| 182 | 212 | ||
| 183 | static inline int o2net_reconnect_delay(void) | 213 | static inline int o2net_reconnect_delay(void) |
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h index 18307ff81b77..8d58cfe410b1 100644 --- a/fs/ocfs2/cluster/tcp_internal.h +++ b/fs/ocfs2/cluster/tcp_internal.h | |||
| @@ -224,42 +224,10 @@ struct o2net_send_tracking { | |||
| 224 | struct timeval st_send_time; | 224 | struct timeval st_send_time; |
| 225 | struct timeval st_status_time; | 225 | struct timeval st_status_time; |
| 226 | }; | 226 | }; |
| 227 | |||
| 228 | void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, | ||
| 229 | u32 msgkey, struct task_struct *task, u8 node); | ||
| 230 | void o2net_set_nst_sock_time(struct o2net_send_tracking *nst); | ||
| 231 | void o2net_set_nst_send_time(struct o2net_send_tracking *nst); | ||
| 232 | void o2net_set_nst_status_time(struct o2net_send_tracking *nst); | ||
| 233 | void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, | ||
| 234 | struct o2net_sock_container *sc); | ||
| 235 | void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, u32 msg_id); | ||
| 236 | |||
| 237 | #else | 227 | #else |
| 238 | struct o2net_send_tracking { | 228 | struct o2net_send_tracking { |
| 239 | u32 dummy; | 229 | u32 dummy; |
| 240 | }; | 230 | }; |
| 241 | |||
| 242 | static inline void o2net_init_nst(struct o2net_send_tracking *nst, u32 msgtype, | ||
| 243 | u32 msgkey, struct task_struct *task, u8 node) | ||
| 244 | { | ||
| 245 | } | ||
| 246 | static inline void o2net_set_nst_sock_time(struct o2net_send_tracking *nst) | ||
| 247 | { | ||
| 248 | } | ||
| 249 | static inline void o2net_set_nst_send_time(struct o2net_send_tracking *nst) | ||
| 250 | { | ||
| 251 | } | ||
| 252 | static inline void o2net_set_nst_status_time(struct o2net_send_tracking *nst) | ||
| 253 | { | ||
| 254 | } | ||
| 255 | static inline void o2net_set_nst_sock_container(struct o2net_send_tracking *nst, | ||
| 256 | struct o2net_sock_container *sc) | ||
| 257 | { | ||
| 258 | } | ||
| 259 | static inline void o2net_set_nst_msg_id(struct o2net_send_tracking *nst, | ||
| 260 | u32 msg_id) | ||
| 261 | { | ||
| 262 | } | ||
| 263 | #endif /* CONFIG_DEBUG_FS */ | 231 | #endif /* CONFIG_DEBUG_FS */ |
| 264 | 232 | ||
| 265 | #endif /* O2CLUSTER_TCP_INTERNAL_H */ | 233 | #endif /* O2CLUSTER_TCP_INTERNAL_H */ |
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 8a1875848080..9cce563fd627 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
| @@ -1300,7 +1300,6 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
| 1300 | di->i_size = cpu_to_le64(sb->s_blocksize); | 1300 | di->i_size = cpu_to_le64(sb->s_blocksize); |
| 1301 | di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec); | 1301 | di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec); |
| 1302 | di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec); | 1302 | di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec); |
| 1303 | dir->i_blocks = ocfs2_inode_sector_count(dir); | ||
| 1304 | 1303 | ||
| 1305 | /* | 1304 | /* |
| 1306 | * This should never fail as our extent list is empty and all | 1305 | * This should never fail as our extent list is empty and all |
| @@ -1310,9 +1309,15 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
| 1310 | NULL); | 1309 | NULL); |
| 1311 | if (ret) { | 1310 | if (ret) { |
| 1312 | mlog_errno(ret); | 1311 | mlog_errno(ret); |
| 1313 | goto out; | 1312 | goto out_commit; |
| 1314 | } | 1313 | } |
| 1315 | 1314 | ||
| 1315 | /* | ||
| 1316 | * Set i_blocks after the extent insert for the most up to | ||
| 1317 | * date ip_clusters value. | ||
| 1318 | */ | ||
| 1319 | dir->i_blocks = ocfs2_inode_sector_count(dir); | ||
| 1320 | |||
| 1316 | ret = ocfs2_journal_dirty(handle, di_bh); | 1321 | ret = ocfs2_journal_dirty(handle, di_bh); |
| 1317 | if (ret) { | 1322 | if (ret) { |
| 1318 | mlog_errno(ret); | 1323 | mlog_errno(ret); |
| @@ -1336,7 +1341,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
| 1336 | len, 0, NULL); | 1341 | len, 0, NULL); |
| 1337 | if (ret) { | 1342 | if (ret) { |
| 1338 | mlog_errno(ret); | 1343 | mlog_errno(ret); |
| 1339 | goto out; | 1344 | goto out_commit; |
| 1340 | } | 1345 | } |
| 1341 | } | 1346 | } |
| 1342 | 1347 | ||
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index e48aba698b77..533a789c3ef8 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c | |||
| @@ -267,8 +267,7 @@ static ssize_t dlmfs_file_write(struct file *filp, | |||
| 267 | return writelen; | 267 | return writelen; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | static void dlmfs_init_once(struct kmem_cache *cachep, | 270 | static void dlmfs_init_once(void *foo) |
| 271 | void *foo) | ||
| 272 | { | 271 | { |
| 273 | struct dlmfs_inode_private *ip = | 272 | struct dlmfs_inode_private *ip = |
| 274 | (struct dlmfs_inode_private *) foo; | 273 | (struct dlmfs_inode_private *) foo; |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index e8514e8b6ce8..ec2ed15c3daa 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -1176,7 +1176,7 @@ bail: | |||
| 1176 | return err; | 1176 | return err; |
| 1177 | } | 1177 | } |
| 1178 | 1178 | ||
| 1179 | int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd) | 1179 | int ocfs2_permission(struct inode *inode, int mask) |
| 1180 | { | 1180 | { |
| 1181 | int ret; | 1181 | int ret; |
| 1182 | 1182 | ||
| @@ -1766,8 +1766,8 @@ out_inode_unlock: | |||
| 1766 | out_rw_unlock: | 1766 | out_rw_unlock: |
| 1767 | ocfs2_rw_unlock(inode, 1); | 1767 | ocfs2_rw_unlock(inode, 1); |
| 1768 | 1768 | ||
| 1769 | mutex_unlock(&inode->i_mutex); | ||
| 1770 | out: | 1769 | out: |
| 1770 | mutex_unlock(&inode->i_mutex); | ||
| 1771 | return ret; | 1771 | return ret; |
| 1772 | } | 1772 | } |
| 1773 | 1773 | ||
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 048ddcaf5c80..1e27b4d017ea 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h | |||
| @@ -62,8 +62,7 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di, | |||
| 62 | int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); | 62 | int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); |
| 63 | int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, | 63 | int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 64 | struct kstat *stat); | 64 | struct kstat *stat); |
| 65 | int ocfs2_permission(struct inode *inode, int mask, | 65 | int ocfs2_permission(struct inode *inode, int mask); |
| 66 | struct nameidata *nd); | ||
| 67 | 66 | ||
| 68 | int ocfs2_should_update_atime(struct inode *inode, | 67 | int ocfs2_should_update_atime(struct inode *inode, |
| 69 | struct vfsmount *vfsmnt); | 68 | struct vfsmount *vfsmnt); |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index a8c19cb3cfdd..c47bc2a809c2 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
| @@ -57,7 +57,7 @@ static int __ocfs2_recovery_thread(void *arg); | |||
| 57 | static int ocfs2_commit_cache(struct ocfs2_super *osb); | 57 | static int ocfs2_commit_cache(struct ocfs2_super *osb); |
| 58 | static int ocfs2_wait_on_mount(struct ocfs2_super *osb); | 58 | static int ocfs2_wait_on_mount(struct ocfs2_super *osb); |
| 59 | static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, | 59 | static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, |
| 60 | int dirty); | 60 | int dirty, int replayed); |
| 61 | static int ocfs2_trylock_journal(struct ocfs2_super *osb, | 61 | static int ocfs2_trylock_journal(struct ocfs2_super *osb, |
| 62 | int slot_num); | 62 | int slot_num); |
| 63 | static int ocfs2_recover_orphans(struct ocfs2_super *osb, | 63 | static int ocfs2_recover_orphans(struct ocfs2_super *osb, |
| @@ -562,8 +562,18 @@ done: | |||
| 562 | return status; | 562 | return status; |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | static void ocfs2_bump_recovery_generation(struct ocfs2_dinode *di) | ||
| 566 | { | ||
| 567 | le32_add_cpu(&(di->id1.journal1.ij_recovery_generation), 1); | ||
| 568 | } | ||
| 569 | |||
| 570 | static u32 ocfs2_get_recovery_generation(struct ocfs2_dinode *di) | ||
| 571 | { | ||
| 572 | return le32_to_cpu(di->id1.journal1.ij_recovery_generation); | ||
| 573 | } | ||
| 574 | |||
| 565 | static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, | 575 | static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, |
| 566 | int dirty) | 576 | int dirty, int replayed) |
| 567 | { | 577 | { |
| 568 | int status; | 578 | int status; |
| 569 | unsigned int flags; | 579 | unsigned int flags; |
| @@ -593,6 +603,9 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, | |||
| 593 | flags &= ~OCFS2_JOURNAL_DIRTY_FL; | 603 | flags &= ~OCFS2_JOURNAL_DIRTY_FL; |
| 594 | fe->id1.journal1.ij_flags = cpu_to_le32(flags); | 604 | fe->id1.journal1.ij_flags = cpu_to_le32(flags); |
| 595 | 605 | ||
| 606 | if (replayed) | ||
| 607 | ocfs2_bump_recovery_generation(fe); | ||
| 608 | |||
| 596 | status = ocfs2_write_block(osb, bh, journal->j_inode); | 609 | status = ocfs2_write_block(osb, bh, journal->j_inode); |
| 597 | if (status < 0) | 610 | if (status < 0) |
| 598 | mlog_errno(status); | 611 | mlog_errno(status); |
| @@ -667,7 +680,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb) | |||
| 667 | * Do not toggle if flush was unsuccessful otherwise | 680 | * Do not toggle if flush was unsuccessful otherwise |
| 668 | * will leave dirty metadata in a "clean" journal | 681 | * will leave dirty metadata in a "clean" journal |
| 669 | */ | 682 | */ |
| 670 | status = ocfs2_journal_toggle_dirty(osb, 0); | 683 | status = ocfs2_journal_toggle_dirty(osb, 0, 0); |
| 671 | if (status < 0) | 684 | if (status < 0) |
| 672 | mlog_errno(status); | 685 | mlog_errno(status); |
| 673 | } | 686 | } |
| @@ -710,7 +723,7 @@ static void ocfs2_clear_journal_error(struct super_block *sb, | |||
| 710 | } | 723 | } |
| 711 | } | 724 | } |
| 712 | 725 | ||
| 713 | int ocfs2_journal_load(struct ocfs2_journal *journal, int local) | 726 | int ocfs2_journal_load(struct ocfs2_journal *journal, int local, int replayed) |
| 714 | { | 727 | { |
| 715 | int status = 0; | 728 | int status = 0; |
| 716 | struct ocfs2_super *osb; | 729 | struct ocfs2_super *osb; |
| @@ -729,7 +742,7 @@ int ocfs2_journal_load(struct ocfs2_journal *journal, int local) | |||
| 729 | 742 | ||
| 730 | ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num); | 743 | ocfs2_clear_journal_error(osb->sb, journal->j_journal, osb->slot_num); |
| 731 | 744 | ||
| 732 | status = ocfs2_journal_toggle_dirty(osb, 1); | 745 | status = ocfs2_journal_toggle_dirty(osb, 1, replayed); |
| 733 | if (status < 0) { | 746 | if (status < 0) { |
| 734 | mlog_errno(status); | 747 | mlog_errno(status); |
| 735 | goto done; | 748 | goto done; |
| @@ -771,7 +784,7 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full) | |||
| 771 | goto bail; | 784 | goto bail; |
| 772 | } | 785 | } |
| 773 | 786 | ||
| 774 | status = ocfs2_journal_toggle_dirty(journal->j_osb, 0); | 787 | status = ocfs2_journal_toggle_dirty(journal->j_osb, 0, 0); |
| 775 | if (status < 0) | 788 | if (status < 0) |
| 776 | mlog_errno(status); | 789 | mlog_errno(status); |
| 777 | 790 | ||
| @@ -1034,6 +1047,12 @@ restart: | |||
| 1034 | spin_unlock(&osb->osb_lock); | 1047 | spin_unlock(&osb->osb_lock); |
| 1035 | mlog(0, "All nodes recovered\n"); | 1048 | mlog(0, "All nodes recovered\n"); |
| 1036 | 1049 | ||
| 1050 | /* Refresh all journal recovery generations from disk */ | ||
| 1051 | status = ocfs2_check_journals_nolocks(osb); | ||
| 1052 | status = (status == -EROFS) ? 0 : status; | ||
| 1053 | if (status < 0) | ||
| 1054 | mlog_errno(status); | ||
| 1055 | |||
| 1037 | ocfs2_super_unlock(osb, 1); | 1056 | ocfs2_super_unlock(osb, 1); |
| 1038 | 1057 | ||
| 1039 | /* We always run recovery on our own orphan dir - the dead | 1058 | /* We always run recovery on our own orphan dir - the dead |
| @@ -1096,6 +1115,42 @@ out: | |||
| 1096 | mlog_exit_void(); | 1115 | mlog_exit_void(); |
| 1097 | } | 1116 | } |
| 1098 | 1117 | ||
| 1118 | static int ocfs2_read_journal_inode(struct ocfs2_super *osb, | ||
| 1119 | int slot_num, | ||
| 1120 | struct buffer_head **bh, | ||
| 1121 | struct inode **ret_inode) | ||
| 1122 | { | ||
| 1123 | int status = -EACCES; | ||
| 1124 | struct inode *inode = NULL; | ||
| 1125 | |||
| 1126 | BUG_ON(slot_num >= osb->max_slots); | ||
| 1127 | |||
| 1128 | inode = ocfs2_get_system_file_inode(osb, JOURNAL_SYSTEM_INODE, | ||
| 1129 | slot_num); | ||
| 1130 | if (!inode || is_bad_inode(inode)) { | ||
| 1131 | mlog_errno(status); | ||
| 1132 | goto bail; | ||
| 1133 | } | ||
| 1134 | SET_INODE_JOURNAL(inode); | ||
| 1135 | |||
| 1136 | status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, bh, 0, inode); | ||
| 1137 | if (status < 0) { | ||
| 1138 | mlog_errno(status); | ||
| 1139 | goto bail; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | status = 0; | ||
| 1143 | |||
| 1144 | bail: | ||
| 1145 | if (inode) { | ||
| 1146 | if (status || !ret_inode) | ||
| 1147 | iput(inode); | ||
| 1148 | else | ||
| 1149 | *ret_inode = inode; | ||
| 1150 | } | ||
| 1151 | return status; | ||
| 1152 | } | ||
| 1153 | |||
| 1099 | /* Does the actual journal replay and marks the journal inode as | 1154 | /* Does the actual journal replay and marks the journal inode as |
| 1100 | * clean. Will only replay if the journal inode is marked dirty. */ | 1155 | * clean. Will only replay if the journal inode is marked dirty. */ |
| 1101 | static int ocfs2_replay_journal(struct ocfs2_super *osb, | 1156 | static int ocfs2_replay_journal(struct ocfs2_super *osb, |
| @@ -1109,22 +1164,36 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, | |||
| 1109 | struct ocfs2_dinode *fe; | 1164 | struct ocfs2_dinode *fe; |
| 1110 | journal_t *journal = NULL; | 1165 | journal_t *journal = NULL; |
| 1111 | struct buffer_head *bh = NULL; | 1166 | struct buffer_head *bh = NULL; |
| 1167 | u32 slot_reco_gen; | ||
| 1112 | 1168 | ||
| 1113 | inode = ocfs2_get_system_file_inode(osb, JOURNAL_SYSTEM_INODE, | 1169 | status = ocfs2_read_journal_inode(osb, slot_num, &bh, &inode); |
| 1114 | slot_num); | 1170 | if (status) { |
| 1115 | if (inode == NULL) { | ||
| 1116 | status = -EACCES; | ||
| 1117 | mlog_errno(status); | 1171 | mlog_errno(status); |
| 1118 | goto done; | 1172 | goto done; |
| 1119 | } | 1173 | } |
| 1120 | if (is_bad_inode(inode)) { | 1174 | |
| 1121 | status = -EACCES; | 1175 | fe = (struct ocfs2_dinode *)bh->b_data; |
| 1122 | iput(inode); | 1176 | slot_reco_gen = ocfs2_get_recovery_generation(fe); |
| 1123 | inode = NULL; | 1177 | brelse(bh); |
| 1124 | mlog_errno(status); | 1178 | bh = NULL; |
| 1179 | |||
| 1180 | /* | ||
| 1181 | * As the fs recovery is asynchronous, there is a small chance that | ||
| 1182 | * another node mounted (and recovered) the slot before the recovery | ||
| 1183 | * thread could get the lock. To handle that, we dirty read the journal | ||
| 1184 | * inode for that slot to get the recovery generation. If it is | ||
| 1185 | * different than what we expected, the slot has been recovered. | ||
| 1186 | * If not, it needs recovery. | ||
| 1187 | */ | ||
| 1188 | if (osb->slot_recovery_generations[slot_num] != slot_reco_gen) { | ||
| 1189 | mlog(0, "Slot %u already recovered (old/new=%u/%u)\n", slot_num, | ||
| 1190 | osb->slot_recovery_generations[slot_num], slot_reco_gen); | ||
| 1191 | osb->slot_recovery_generations[slot_num] = slot_reco_gen; | ||
| 1192 | status = -EBUSY; | ||
| 1125 | goto done; | 1193 | goto done; |
| 1126 | } | 1194 | } |
| 1127 | SET_INODE_JOURNAL(inode); | 1195 | |
| 1196 | /* Continue with recovery as the journal has not yet been recovered */ | ||
| 1128 | 1197 | ||
| 1129 | status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); | 1198 | status = ocfs2_inode_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); |
| 1130 | if (status < 0) { | 1199 | if (status < 0) { |
| @@ -1138,9 +1207,12 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, | |||
| 1138 | fe = (struct ocfs2_dinode *) bh->b_data; | 1207 | fe = (struct ocfs2_dinode *) bh->b_data; |
| 1139 | 1208 | ||
| 1140 | flags = le32_to_cpu(fe->id1.journal1.ij_flags); | 1209 | flags = le32_to_cpu(fe->id1.journal1.ij_flags); |
| 1210 | slot_reco_gen = ocfs2_get_recovery_generation(fe); | ||
| 1141 | 1211 | ||
| 1142 | if (!(flags & OCFS2_JOURNAL_DIRTY_FL)) { | 1212 | if (!(flags & OCFS2_JOURNAL_DIRTY_FL)) { |
| 1143 | mlog(0, "No recovery required for node %d\n", node_num); | 1213 | mlog(0, "No recovery required for node %d\n", node_num); |
| 1214 | /* Refresh recovery generation for the slot */ | ||
| 1215 | osb->slot_recovery_generations[slot_num] = slot_reco_gen; | ||
| 1144 | goto done; | 1216 | goto done; |
| 1145 | } | 1217 | } |
| 1146 | 1218 | ||
| @@ -1188,6 +1260,11 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb, | |||
| 1188 | flags &= ~OCFS2_JOURNAL_DIRTY_FL; | 1260 | flags &= ~OCFS2_JOURNAL_DIRTY_FL; |
| 1189 | fe->id1.journal1.ij_flags = cpu_to_le32(flags); | 1261 | fe->id1.journal1.ij_flags = cpu_to_le32(flags); |
| 1190 | 1262 | ||
| 1263 | /* Increment recovery generation to indicate successful recovery */ | ||
| 1264 | ocfs2_bump_recovery_generation(fe); | ||
| 1265 | osb->slot_recovery_generations[slot_num] = | ||
| 1266 | ocfs2_get_recovery_generation(fe); | ||
| 1267 | |||
| 1191 | status = ocfs2_write_block(osb, bh, inode); | 1268 | status = ocfs2_write_block(osb, bh, inode); |
| 1192 | if (status < 0) | 1269 | if (status < 0) |
| 1193 | mlog_errno(status); | 1270 | mlog_errno(status); |
| @@ -1252,6 +1329,13 @@ static int ocfs2_recover_node(struct ocfs2_super *osb, | |||
| 1252 | 1329 | ||
| 1253 | status = ocfs2_replay_journal(osb, node_num, slot_num); | 1330 | status = ocfs2_replay_journal(osb, node_num, slot_num); |
| 1254 | if (status < 0) { | 1331 | if (status < 0) { |
| 1332 | if (status == -EBUSY) { | ||
| 1333 | mlog(0, "Skipping recovery for slot %u (node %u) " | ||
| 1334 | "as another node has recovered it\n", slot_num, | ||
| 1335 | node_num); | ||
| 1336 | status = 0; | ||
| 1337 | goto done; | ||
| 1338 | } | ||
| 1255 | mlog_errno(status); | 1339 | mlog_errno(status); |
| 1256 | goto done; | 1340 | goto done; |
| 1257 | } | 1341 | } |
| @@ -1334,21 +1418,46 @@ int ocfs2_mark_dead_nodes(struct ocfs2_super *osb) | |||
| 1334 | { | 1418 | { |
| 1335 | unsigned int node_num; | 1419 | unsigned int node_num; |
| 1336 | int status, i; | 1420 | int status, i; |
| 1421 | u32 gen; | ||
| 1422 | struct buffer_head *bh = NULL; | ||
| 1423 | struct ocfs2_dinode *di; | ||
| 1337 | 1424 | ||
| 1338 | /* This is called with the super block cluster lock, so we | 1425 | /* This is called with the super block cluster lock, so we |
| 1339 | * know that the slot map can't change underneath us. */ | 1426 | * know that the slot map can't change underneath us. */ |
| 1340 | 1427 | ||
| 1341 | spin_lock(&osb->osb_lock); | ||
| 1342 | for (i = 0; i < osb->max_slots; i++) { | 1428 | for (i = 0; i < osb->max_slots; i++) { |
| 1343 | if (i == osb->slot_num) | 1429 | /* Read journal inode to get the recovery generation */ |
| 1430 | status = ocfs2_read_journal_inode(osb, i, &bh, NULL); | ||
| 1431 | if (status) { | ||
| 1432 | mlog_errno(status); | ||
| 1433 | goto bail; | ||
| 1434 | } | ||
| 1435 | di = (struct ocfs2_dinode *)bh->b_data; | ||
| 1436 | gen = ocfs2_get_recovery_generation(di); | ||
| 1437 | brelse(bh); | ||
| 1438 | bh = NULL; | ||
| 1439 | |||
| 1440 | spin_lock(&osb->osb_lock); | ||
| 1441 | osb->slot_recovery_generations[i] = gen; | ||
| 1442 | |||
| 1443 | mlog(0, "Slot %u recovery generation is %u\n", i, | ||
| 1444 | osb->slot_recovery_generations[i]); | ||
| 1445 | |||
| 1446 | if (i == osb->slot_num) { | ||
| 1447 | spin_unlock(&osb->osb_lock); | ||
| 1344 | continue; | 1448 | continue; |
| 1449 | } | ||
| 1345 | 1450 | ||
| 1346 | status = ocfs2_slot_to_node_num_locked(osb, i, &node_num); | 1451 | status = ocfs2_slot_to_node_num_locked(osb, i, &node_num); |
| 1347 | if (status == -ENOENT) | 1452 | if (status == -ENOENT) { |
| 1453 | spin_unlock(&osb->osb_lock); | ||
| 1348 | continue; | 1454 | continue; |
| 1455 | } | ||
| 1349 | 1456 | ||
| 1350 | if (__ocfs2_recovery_map_test(osb, node_num)) | 1457 | if (__ocfs2_recovery_map_test(osb, node_num)) { |
| 1458 | spin_unlock(&osb->osb_lock); | ||
| 1351 | continue; | 1459 | continue; |
| 1460 | } | ||
| 1352 | spin_unlock(&osb->osb_lock); | 1461 | spin_unlock(&osb->osb_lock); |
| 1353 | 1462 | ||
| 1354 | /* Ok, we have a slot occupied by another node which | 1463 | /* Ok, we have a slot occupied by another node which |
| @@ -1364,10 +1473,7 @@ int ocfs2_mark_dead_nodes(struct ocfs2_super *osb) | |||
| 1364 | mlog_errno(status); | 1473 | mlog_errno(status); |
| 1365 | goto bail; | 1474 | goto bail; |
| 1366 | } | 1475 | } |
| 1367 | |||
| 1368 | spin_lock(&osb->osb_lock); | ||
| 1369 | } | 1476 | } |
| 1370 | spin_unlock(&osb->osb_lock); | ||
| 1371 | 1477 | ||
| 1372 | status = 0; | 1478 | status = 0; |
| 1373 | bail: | 1479 | bail: |
| @@ -1603,49 +1709,41 @@ static int ocfs2_commit_thread(void *arg) | |||
| 1603 | return 0; | 1709 | return 0; |
| 1604 | } | 1710 | } |
| 1605 | 1711 | ||
| 1606 | /* Look for a dirty journal without taking any cluster locks. Used for | 1712 | /* Reads all the journal inodes without taking any cluster locks. Used |
| 1607 | * hard readonly access to determine whether the file system journals | 1713 | * for hard readonly access to determine whether any journal requires |
| 1608 | * require recovery. */ | 1714 | * recovery. Also used to refresh the recovery generation numbers after |
| 1715 | * a journal has been recovered by another node. | ||
| 1716 | */ | ||
| 1609 | int ocfs2_check_journals_nolocks(struct ocfs2_super *osb) | 1717 | int ocfs2_check_journals_nolocks(struct ocfs2_super *osb) |
| 1610 | { | 1718 | { |
| 1611 | int ret = 0; | 1719 | int ret = 0; |
| 1612 | unsigned int slot; | 1720 | unsigned int slot; |
| 1613 | struct buffer_head *di_bh; | 1721 | struct buffer_head *di_bh = NULL; |
| 1614 | struct ocfs2_dinode *di; | 1722 | struct ocfs2_dinode *di; |
| 1615 | struct inode *journal = NULL; | 1723 | int journal_dirty = 0; |
| 1616 | 1724 | ||
| 1617 | for(slot = 0; slot < osb->max_slots; slot++) { | 1725 | for(slot = 0; slot < osb->max_slots; slot++) { |
| 1618 | journal = ocfs2_get_system_file_inode(osb, | 1726 | ret = ocfs2_read_journal_inode(osb, slot, &di_bh, NULL); |
| 1619 | JOURNAL_SYSTEM_INODE, | 1727 | if (ret) { |
| 1620 | slot); | ||
| 1621 | if (!journal || is_bad_inode(journal)) { | ||
| 1622 | ret = -EACCES; | ||
| 1623 | mlog_errno(ret); | ||
| 1624 | goto out; | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | di_bh = NULL; | ||
| 1628 | ret = ocfs2_read_block(osb, OCFS2_I(journal)->ip_blkno, &di_bh, | ||
| 1629 | 0, journal); | ||
| 1630 | if (ret < 0) { | ||
| 1631 | mlog_errno(ret); | 1728 | mlog_errno(ret); |
| 1632 | goto out; | 1729 | goto out; |
| 1633 | } | 1730 | } |
| 1634 | 1731 | ||
| 1635 | di = (struct ocfs2_dinode *) di_bh->b_data; | 1732 | di = (struct ocfs2_dinode *) di_bh->b_data; |
| 1636 | 1733 | ||
| 1734 | osb->slot_recovery_generations[slot] = | ||
| 1735 | ocfs2_get_recovery_generation(di); | ||
| 1736 | |||
| 1637 | if (le32_to_cpu(di->id1.journal1.ij_flags) & | 1737 | if (le32_to_cpu(di->id1.journal1.ij_flags) & |
| 1638 | OCFS2_JOURNAL_DIRTY_FL) | 1738 | OCFS2_JOURNAL_DIRTY_FL) |
| 1639 | ret = -EROFS; | 1739 | journal_dirty = 1; |
| 1640 | 1740 | ||
| 1641 | brelse(di_bh); | 1741 | brelse(di_bh); |
| 1642 | if (ret) | 1742 | di_bh = NULL; |
| 1643 | break; | ||
| 1644 | } | 1743 | } |
| 1645 | 1744 | ||
| 1646 | out: | 1745 | out: |
| 1647 | if (journal) | 1746 | if (journal_dirty) |
| 1648 | iput(journal); | 1747 | ret = -EROFS; |
| 1649 | |||
| 1650 | return ret; | 1748 | return ret; |
| 1651 | } | 1749 | } |
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index db82be2532ed..2178ebffa05f 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h | |||
| @@ -161,7 +161,8 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, | |||
| 161 | void ocfs2_journal_shutdown(struct ocfs2_super *osb); | 161 | void ocfs2_journal_shutdown(struct ocfs2_super *osb); |
| 162 | int ocfs2_journal_wipe(struct ocfs2_journal *journal, | 162 | int ocfs2_journal_wipe(struct ocfs2_journal *journal, |
| 163 | int full); | 163 | int full); |
| 164 | int ocfs2_journal_load(struct ocfs2_journal *journal, int local); | 164 | int ocfs2_journal_load(struct ocfs2_journal *journal, int local, |
| 165 | int replayed); | ||
| 165 | int ocfs2_check_journals_nolocks(struct ocfs2_super *osb); | 166 | int ocfs2_check_journals_nolocks(struct ocfs2_super *osb); |
| 166 | void ocfs2_recovery_thread(struct ocfs2_super *osb, | 167 | void ocfs2_recovery_thread(struct ocfs2_super *osb, |
| 167 | int node_num); | 168 | int node_num); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1cb814be8ef1..7f625f2b1117 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
| @@ -204,6 +204,8 @@ struct ocfs2_super | |||
| 204 | 204 | ||
| 205 | struct ocfs2_slot_info *slot_info; | 205 | struct ocfs2_slot_info *slot_info; |
| 206 | 206 | ||
| 207 | u32 *slot_recovery_generations; | ||
| 208 | |||
| 207 | spinlock_t node_map_lock; | 209 | spinlock_t node_map_lock; |
| 208 | 210 | ||
| 209 | u64 root_blkno; | 211 | u64 root_blkno; |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index 3f1945177629..4f619850ccf7 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
| @@ -660,7 +660,10 @@ struct ocfs2_dinode { | |||
| 660 | struct { /* Info for journal system | 660 | struct { /* Info for journal system |
| 661 | inodes */ | 661 | inodes */ |
| 662 | __le32 ij_flags; /* Mounted, version, etc. */ | 662 | __le32 ij_flags; /* Mounted, version, etc. */ |
| 663 | __le32 ij_pad; | 663 | __le32 ij_recovery_generation; /* Incremented when the |
| 664 | journal is recovered | ||
| 665 | after an unclean | ||
| 666 | shutdown */ | ||
| 664 | } journal1; | 667 | } journal1; |
| 665 | } id1; /* Inode type dependant 1 */ | 668 | } id1; /* Inode type dependant 1 */ |
| 666 | /*C0*/ union { | 669 | /*C0*/ union { |
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 10e149ae5e3a..07f348b8d721 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
| @@ -97,13 +97,14 @@ static int ocfs2_stack_driver_request(const char *stack_name, | |||
| 97 | goto out; | 97 | goto out; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /* Ok, the stack is pinned */ | ||
| 101 | p->sp_count++; | ||
| 102 | active_stack = p; | 100 | active_stack = p; |
| 103 | |||
| 104 | rc = 0; | 101 | rc = 0; |
| 105 | 102 | ||
| 106 | out: | 103 | out: |
| 104 | /* If we found it, pin it */ | ||
| 105 | if (!rc) | ||
| 106 | active_stack->sp_count++; | ||
| 107 | |||
| 107 | spin_unlock(&ocfs2_stack_lock); | 108 | spin_unlock(&ocfs2_stack_lock); |
| 108 | return rc; | 109 | return rc; |
| 109 | } | 110 | } |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index ccecfe5094fa..88255d3f52b4 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
| @@ -1118,7 +1118,7 @@ bail: | |||
| 1118 | return status; | 1118 | return status; |
| 1119 | } | 1119 | } |
| 1120 | 1120 | ||
| 1121 | static void ocfs2_inode_init_once(struct kmem_cache *cachep, void *data) | 1121 | static void ocfs2_inode_init_once(void *data) |
| 1122 | { | 1122 | { |
| 1123 | struct ocfs2_inode_info *oi = data; | 1123 | struct ocfs2_inode_info *oi = data; |
| 1124 | 1124 | ||
| @@ -1442,6 +1442,15 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
| 1442 | } | 1442 | } |
| 1443 | mlog(0, "max_slots for this device: %u\n", osb->max_slots); | 1443 | mlog(0, "max_slots for this device: %u\n", osb->max_slots); |
| 1444 | 1444 | ||
| 1445 | osb->slot_recovery_generations = | ||
| 1446 | kcalloc(osb->max_slots, sizeof(*osb->slot_recovery_generations), | ||
| 1447 | GFP_KERNEL); | ||
| 1448 | if (!osb->slot_recovery_generations) { | ||
| 1449 | status = -ENOMEM; | ||
| 1450 | mlog_errno(status); | ||
| 1451 | goto bail; | ||
| 1452 | } | ||
| 1453 | |||
| 1445 | init_waitqueue_head(&osb->osb_wipe_event); | 1454 | init_waitqueue_head(&osb->osb_wipe_event); |
| 1446 | osb->osb_orphan_wipes = kcalloc(osb->max_slots, | 1455 | osb->osb_orphan_wipes = kcalloc(osb->max_slots, |
| 1447 | sizeof(*osb->osb_orphan_wipes), | 1456 | sizeof(*osb->osb_orphan_wipes), |
| @@ -1703,7 +1712,7 @@ static int ocfs2_check_volume(struct ocfs2_super *osb) | |||
| 1703 | local = ocfs2_mount_local(osb); | 1712 | local = ocfs2_mount_local(osb); |
| 1704 | 1713 | ||
| 1705 | /* will play back anything left in the journal. */ | 1714 | /* will play back anything left in the journal. */ |
| 1706 | status = ocfs2_journal_load(osb->journal, local); | 1715 | status = ocfs2_journal_load(osb->journal, local, dirty); |
| 1707 | if (status < 0) { | 1716 | if (status < 0) { |
| 1708 | mlog(ML_ERROR, "ocfs2 journal load failed! %d\n", status); | 1717 | mlog(ML_ERROR, "ocfs2 journal load failed! %d\n", status); |
| 1709 | goto finally; | 1718 | goto finally; |
| @@ -1768,6 +1777,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) | |||
| 1768 | ocfs2_free_slot_info(osb); | 1777 | ocfs2_free_slot_info(osb); |
| 1769 | 1778 | ||
| 1770 | kfree(osb->osb_orphan_wipes); | 1779 | kfree(osb->osb_orphan_wipes); |
| 1780 | kfree(osb->slot_recovery_generations); | ||
| 1771 | /* FIXME | 1781 | /* FIXME |
| 1772 | * This belongs in journal shutdown, but because we have to | 1782 | * This belongs in journal shutdown, but because we have to |
| 1773 | * allocate osb->journal at the start of ocfs2_initalize_osb(), | 1783 | * allocate osb->journal at the start of ocfs2_initalize_osb(), |
diff --git a/fs/omfs/Makefile b/fs/omfs/Makefile new file mode 100644 index 000000000000..8b82b63f1129 --- /dev/null +++ b/fs/omfs/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | |||
| 2 | obj-$(CONFIG_OMFS_FS) += omfs.o | ||
| 3 | |||
| 4 | omfs-y := bitmap.o dir.o file.o inode.o | ||
diff --git a/fs/omfs/bitmap.c b/fs/omfs/bitmap.c new file mode 100644 index 000000000000..e1c0ec0ae989 --- /dev/null +++ b/fs/omfs/bitmap.c | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/fs.h> | ||
| 3 | #include <linux/buffer_head.h> | ||
| 4 | #include <asm/div64.h> | ||
| 5 | #include "omfs.h" | ||
| 6 | |||
| 7 | unsigned long omfs_count_free(struct super_block *sb) | ||
| 8 | { | ||
| 9 | unsigned int i; | ||
| 10 | unsigned long sum = 0; | ||
| 11 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 12 | int nbits = sb->s_blocksize * 8; | ||
| 13 | |||
| 14 | for (i = 0; i < sbi->s_imap_size; i++) | ||
| 15 | sum += nbits - bitmap_weight(sbi->s_imap[i], nbits); | ||
| 16 | |||
| 17 | return sum; | ||
| 18 | } | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Counts the run of zero bits starting at bit up to max. | ||
| 22 | * It handles the case where a run might spill over a buffer. | ||
| 23 | * Called with bitmap lock. | ||
| 24 | */ | ||
| 25 | static int count_run(unsigned long **addr, int nbits, | ||
| 26 | int addrlen, int bit, int max) | ||
| 27 | { | ||
| 28 | int count = 0; | ||
| 29 | int x; | ||
| 30 | |||
| 31 | for (; addrlen > 0; addrlen--, addr++) { | ||
| 32 | x = find_next_bit(*addr, nbits, bit); | ||
| 33 | count += x - bit; | ||
| 34 | |||
| 35 | if (x < nbits || count > max) | ||
| 36 | return min(count, max); | ||
| 37 | |||
| 38 | bit = 0; | ||
| 39 | } | ||
| 40 | return min(count, max); | ||
| 41 | } | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Sets or clears the run of count bits starting with bit. | ||
| 45 | * Called with bitmap lock. | ||
| 46 | */ | ||
| 47 | static int set_run(struct super_block *sb, int map, | ||
| 48 | int nbits, int bit, int count, int set) | ||
| 49 | { | ||
| 50 | int i; | ||
| 51 | int err; | ||
| 52 | struct buffer_head *bh; | ||
| 53 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 54 | |||
| 55 | err = -ENOMEM; | ||
| 56 | bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); | ||
| 57 | if (!bh) | ||
| 58 | goto out; | ||
| 59 | |||
| 60 | for (i = 0; i < count; i++, bit++) { | ||
| 61 | if (bit >= nbits) { | ||
| 62 | bit = 0; | ||
| 63 | map++; | ||
| 64 | |||
| 65 | mark_buffer_dirty(bh); | ||
| 66 | brelse(bh); | ||
| 67 | bh = sb_bread(sb, | ||
| 68 | clus_to_blk(sbi, sbi->s_bitmap_ino) + map); | ||
| 69 | if (!bh) | ||
| 70 | goto out; | ||
| 71 | } | ||
| 72 | if (set) { | ||
| 73 | set_bit(bit, sbi->s_imap[map]); | ||
| 74 | set_bit(bit, (unsigned long *)bh->b_data); | ||
| 75 | } else { | ||
| 76 | clear_bit(bit, sbi->s_imap[map]); | ||
| 77 | clear_bit(bit, (unsigned long *)bh->b_data); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | mark_buffer_dirty(bh); | ||
| 81 | brelse(bh); | ||
| 82 | err = 0; | ||
| 83 | out: | ||
| 84 | return err; | ||
| 85 | } | ||
| 86 | |||
| 87 | /* | ||
| 88 | * Tries to allocate exactly one block. Returns true if sucessful. | ||
| 89 | */ | ||
| 90 | int omfs_allocate_block(struct super_block *sb, u64 block) | ||
| 91 | { | ||
| 92 | struct buffer_head *bh; | ||
| 93 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 94 | int bits_per_entry = 8 * sb->s_blocksize; | ||
| 95 | unsigned int map, bit; | ||
| 96 | int ret = 0; | ||
| 97 | u64 tmp; | ||
| 98 | |||
| 99 | tmp = block; | ||
| 100 | bit = do_div(tmp, bits_per_entry); | ||
| 101 | map = tmp; | ||
| 102 | |||
| 103 | mutex_lock(&sbi->s_bitmap_lock); | ||
| 104 | if (map >= sbi->s_imap_size || test_and_set_bit(bit, sbi->s_imap[map])) | ||
| 105 | goto out; | ||
| 106 | |||
| 107 | if (sbi->s_bitmap_ino > 0) { | ||
| 108 | bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); | ||
| 109 | if (!bh) | ||
| 110 | goto out; | ||
| 111 | |||
| 112 | set_bit(bit, (unsigned long *)bh->b_data); | ||
| 113 | mark_buffer_dirty(bh); | ||
| 114 | brelse(bh); | ||
| 115 | } | ||
| 116 | ret = 1; | ||
| 117 | out: | ||
| 118 | mutex_unlock(&sbi->s_bitmap_lock); | ||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | |||
| 122 | |||
| 123 | /* | ||
| 124 | * Tries to allocate a set of blocks. The request size depends on the | ||
| 125 | * type: for inodes, we must allocate sbi->s_mirrors blocks, and for file | ||
| 126 | * blocks, we try to allocate sbi->s_clustersize, but can always get away | ||
| 127 | * with just one block. | ||
| 128 | */ | ||
| 129 | int omfs_allocate_range(struct super_block *sb, | ||
| 130 | int min_request, | ||
| 131 | int max_request, | ||
| 132 | u64 *return_block, | ||
| 133 | int *return_size) | ||
| 134 | { | ||
| 135 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 136 | int bits_per_entry = 8 * sb->s_blocksize; | ||
| 137 | int ret = 0; | ||
| 138 | int i, run, bit; | ||
| 139 | |||
| 140 | mutex_lock(&sbi->s_bitmap_lock); | ||
| 141 | for (i = 0; i < sbi->s_imap_size; i++) { | ||
| 142 | bit = 0; | ||
| 143 | while (bit < bits_per_entry) { | ||
| 144 | bit = find_next_zero_bit(sbi->s_imap[i], bits_per_entry, | ||
| 145 | bit); | ||
| 146 | |||
| 147 | if (bit == bits_per_entry) | ||
| 148 | break; | ||
| 149 | |||
| 150 | run = count_run(&sbi->s_imap[i], bits_per_entry, | ||
| 151 | sbi->s_imap_size-i, bit, max_request); | ||
| 152 | |||
| 153 | if (run >= min_request) | ||
| 154 | goto found; | ||
| 155 | bit += run; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | ret = -ENOSPC; | ||
| 159 | goto out; | ||
| 160 | |||
| 161 | found: | ||
| 162 | *return_block = i * bits_per_entry + bit; | ||
| 163 | *return_size = run; | ||
| 164 | ret = set_run(sb, i, bits_per_entry, bit, run, 1); | ||
| 165 | |||
| 166 | out: | ||
| 167 | mutex_unlock(&sbi->s_bitmap_lock); | ||
| 168 | return ret; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Clears count bits starting at a given block. | ||
| 173 | */ | ||
| 174 | int omfs_clear_range(struct super_block *sb, u64 block, int count) | ||
| 175 | { | ||
| 176 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 177 | int bits_per_entry = 8 * sb->s_blocksize; | ||
| 178 | u64 tmp; | ||
| 179 | unsigned int map, bit; | ||
| 180 | int ret; | ||
| 181 | |||
| 182 | tmp = block; | ||
| 183 | bit = do_div(tmp, bits_per_entry); | ||
| 184 | map = tmp; | ||
| 185 | |||
| 186 | if (map >= sbi->s_imap_size) | ||
| 187 | return 0; | ||
| 188 | |||
| 189 | mutex_lock(&sbi->s_bitmap_lock); | ||
| 190 | ret = set_run(sb, map, bits_per_entry, bit, count, 0); | ||
| 191 | mutex_unlock(&sbi->s_bitmap_lock); | ||
| 192 | return ret; | ||
| 193 | } | ||
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c new file mode 100644 index 000000000000..c0757e998876 --- /dev/null +++ b/fs/omfs/dir.c | |||
| @@ -0,0 +1,504 @@ | |||
| 1 | /* | ||
| 2 | * OMFS (as used by RIO Karma) directory operations. | ||
| 3 | * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com> | ||
| 4 | * Released under GPL v2. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/fs.h> | ||
| 8 | #include <linux/ctype.h> | ||
| 9 | #include <linux/buffer_head.h> | ||
| 10 | #include "omfs.h" | ||
| 11 | |||
| 12 | static int omfs_hash(const char *name, int namelen, int mod) | ||
| 13 | { | ||
| 14 | int i, hash = 0; | ||
| 15 | for (i = 0; i < namelen; i++) | ||
| 16 | hash ^= tolower(name[i]) << (i % 24); | ||
| 17 | return hash % mod; | ||
| 18 | } | ||
| 19 | |||
| 20 | /* | ||
| 21 | * Finds the bucket for a given name and reads the containing block; | ||
| 22 | * *ofs is set to the offset of the first list entry. | ||
| 23 | */ | ||
| 24 | static struct buffer_head *omfs_get_bucket(struct inode *dir, | ||
| 25 | const char *name, int namelen, int *ofs) | ||
| 26 | { | ||
| 27 | int nbuckets = (dir->i_size - OMFS_DIR_START)/8; | ||
| 28 | int block = clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino); | ||
| 29 | int bucket = omfs_hash(name, namelen, nbuckets); | ||
| 30 | |||
| 31 | *ofs = OMFS_DIR_START + bucket * 8; | ||
| 32 | return sb_bread(dir->i_sb, block); | ||
| 33 | } | ||
| 34 | |||
| 35 | static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, | ||
| 36 | const char *name, int namelen, | ||
| 37 | u64 *prev_block) | ||
| 38 | { | ||
| 39 | struct buffer_head *bh; | ||
| 40 | struct omfs_inode *oi; | ||
| 41 | int err = -ENOENT; | ||
| 42 | *prev_block = ~0; | ||
| 43 | |||
| 44 | while (block != ~0) { | ||
| 45 | bh = sb_bread(dir->i_sb, | ||
| 46 | clus_to_blk(OMFS_SB(dir->i_sb), block)); | ||
| 47 | if (!bh) { | ||
| 48 | err = -EIO; | ||
| 49 | goto err; | ||
| 50 | } | ||
| 51 | |||
| 52 | oi = (struct omfs_inode *) bh->b_data; | ||
| 53 | if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, block)) { | ||
| 54 | brelse(bh); | ||
| 55 | goto err; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (strncmp(oi->i_name, name, namelen) == 0) | ||
| 59 | return bh; | ||
| 60 | |||
| 61 | *prev_block = block; | ||
| 62 | block = be64_to_cpu(oi->i_sibling); | ||
| 63 | brelse(bh); | ||
| 64 | } | ||
| 65 | err: | ||
| 66 | return ERR_PTR(err); | ||
| 67 | } | ||
| 68 | |||
| 69 | static struct buffer_head *omfs_find_entry(struct inode *dir, | ||
| 70 | const char *name, int namelen) | ||
| 71 | { | ||
| 72 | struct buffer_head *bh; | ||
| 73 | int ofs; | ||
| 74 | u64 block, dummy; | ||
| 75 | |||
| 76 | bh = omfs_get_bucket(dir, name, namelen, &ofs); | ||
| 77 | if (!bh) | ||
| 78 | return ERR_PTR(-EIO); | ||
| 79 | |||
| 80 | block = be64_to_cpu(*((__be64 *) &bh->b_data[ofs])); | ||
| 81 | brelse(bh); | ||
| 82 | |||
| 83 | return omfs_scan_list(dir, block, name, namelen, &dummy); | ||
| 84 | } | ||
| 85 | |||
| 86 | int omfs_make_empty(struct inode *inode, struct super_block *sb) | ||
| 87 | { | ||
| 88 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 89 | int block = clus_to_blk(sbi, inode->i_ino); | ||
| 90 | struct buffer_head *bh; | ||
| 91 | struct omfs_inode *oi; | ||
| 92 | |||
| 93 | bh = sb_bread(sb, block); | ||
| 94 | if (!bh) | ||
| 95 | return -ENOMEM; | ||
| 96 | |||
| 97 | memset(bh->b_data, 0, sizeof(struct omfs_inode)); | ||
| 98 | |||
| 99 | if (inode->i_mode & S_IFDIR) { | ||
| 100 | memset(&bh->b_data[OMFS_DIR_START], 0xff, | ||
| 101 | sbi->s_sys_blocksize - OMFS_DIR_START); | ||
| 102 | } else | ||
| 103 | omfs_make_empty_table(bh, OMFS_EXTENT_START); | ||
| 104 | |||
| 105 | oi = (struct omfs_inode *) bh->b_data; | ||
| 106 | oi->i_head.h_self = cpu_to_be64(inode->i_ino); | ||
| 107 | oi->i_sibling = ~cpu_to_be64(0ULL); | ||
| 108 | |||
| 109 | mark_buffer_dirty(bh); | ||
| 110 | brelse(bh); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int omfs_add_link(struct dentry *dentry, struct inode *inode) | ||
| 115 | { | ||
| 116 | struct inode *dir = dentry->d_parent->d_inode; | ||
| 117 | const char *name = dentry->d_name.name; | ||
| 118 | int namelen = dentry->d_name.len; | ||
| 119 | struct omfs_inode *oi; | ||
| 120 | struct buffer_head *bh; | ||
| 121 | u64 block; | ||
| 122 | __be64 *entry; | ||
| 123 | int ofs; | ||
| 124 | |||
| 125 | /* just prepend to head of queue in proper bucket */ | ||
| 126 | bh = omfs_get_bucket(dir, name, namelen, &ofs); | ||
| 127 | if (!bh) | ||
| 128 | goto out; | ||
| 129 | |||
| 130 | entry = (__be64 *) &bh->b_data[ofs]; | ||
| 131 | block = be64_to_cpu(*entry); | ||
| 132 | *entry = cpu_to_be64(inode->i_ino); | ||
| 133 | mark_buffer_dirty(bh); | ||
| 134 | brelse(bh); | ||
| 135 | |||
| 136 | /* now set the sibling and parent pointers on the new inode */ | ||
| 137 | bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), inode->i_ino)); | ||
| 138 | if (!bh) | ||
| 139 | goto out; | ||
| 140 | |||
| 141 | oi = (struct omfs_inode *) bh->b_data; | ||
| 142 | memcpy(oi->i_name, name, namelen); | ||
| 143 | memset(oi->i_name + namelen, 0, OMFS_NAMELEN - namelen); | ||
| 144 | oi->i_sibling = cpu_to_be64(block); | ||
| 145 | oi->i_parent = cpu_to_be64(dir->i_ino); | ||
| 146 | mark_buffer_dirty(bh); | ||
| 147 | brelse(bh); | ||
| 148 | |||
| 149 | dir->i_ctime = CURRENT_TIME_SEC; | ||
| 150 | |||
| 151 | /* mark affected inodes dirty to rebuild checksums */ | ||
| 152 | mark_inode_dirty(dir); | ||
| 153 | mark_inode_dirty(inode); | ||
| 154 | return 0; | ||
| 155 | out: | ||
| 156 | return -ENOMEM; | ||
| 157 | } | ||
| 158 | |||
| 159 | static int omfs_delete_entry(struct dentry *dentry) | ||
| 160 | { | ||
| 161 | struct inode *dir = dentry->d_parent->d_inode; | ||
| 162 | struct inode *dirty; | ||
| 163 | const char *name = dentry->d_name.name; | ||
| 164 | int namelen = dentry->d_name.len; | ||
| 165 | struct omfs_inode *oi; | ||
| 166 | struct buffer_head *bh, *bh2; | ||
| 167 | __be64 *entry, next; | ||
| 168 | u64 block, prev; | ||
| 169 | int ofs; | ||
| 170 | int err = -ENOMEM; | ||
| 171 | |||
| 172 | /* delete the proper node in the bucket's linked list */ | ||
| 173 | bh = omfs_get_bucket(dir, name, namelen, &ofs); | ||
| 174 | if (!bh) | ||
| 175 | goto out; | ||
| 176 | |||
| 177 | entry = (__be64 *) &bh->b_data[ofs]; | ||
| 178 | block = be64_to_cpu(*entry); | ||
| 179 | |||
| 180 | bh2 = omfs_scan_list(dir, block, name, namelen, &prev); | ||
| 181 | if (IS_ERR(bh2)) { | ||
| 182 | err = PTR_ERR(bh2); | ||
| 183 | goto out_free_bh; | ||
| 184 | } | ||
| 185 | |||
| 186 | oi = (struct omfs_inode *) bh2->b_data; | ||
| 187 | next = oi->i_sibling; | ||
| 188 | brelse(bh2); | ||
| 189 | |||
| 190 | if (prev != ~0) { | ||
| 191 | /* found in middle of list, get list ptr */ | ||
| 192 | brelse(bh); | ||
| 193 | bh = sb_bread(dir->i_sb, | ||
| 194 | clus_to_blk(OMFS_SB(dir->i_sb), prev)); | ||
| 195 | if (!bh) | ||
| 196 | goto out; | ||
| 197 | |||
| 198 | oi = (struct omfs_inode *) bh->b_data; | ||
| 199 | entry = &oi->i_sibling; | ||
| 200 | } | ||
| 201 | |||
| 202 | *entry = next; | ||
| 203 | mark_buffer_dirty(bh); | ||
| 204 | |||
| 205 | if (prev != ~0) { | ||
| 206 | dirty = omfs_iget(dir->i_sb, prev); | ||
| 207 | if (!IS_ERR(dirty)) { | ||
| 208 | mark_inode_dirty(dirty); | ||
| 209 | iput(dirty); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | err = 0; | ||
| 214 | out_free_bh: | ||
| 215 | brelse(bh); | ||
| 216 | out: | ||
| 217 | return err; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int omfs_dir_is_empty(struct inode *inode) | ||
| 221 | { | ||
| 222 | int nbuckets = (inode->i_size - OMFS_DIR_START) / 8; | ||
| 223 | struct buffer_head *bh; | ||
| 224 | u64 *ptr; | ||
| 225 | int i; | ||
| 226 | |||
| 227 | bh = sb_bread(inode->i_sb, clus_to_blk(OMFS_SB(inode->i_sb), | ||
| 228 | inode->i_ino)); | ||
| 229 | |||
| 230 | if (!bh) | ||
| 231 | return 0; | ||
| 232 | |||
| 233 | ptr = (u64 *) &bh->b_data[OMFS_DIR_START]; | ||
| 234 | |||
| 235 | for (i = 0; i < nbuckets; i++, ptr++) | ||
| 236 | if (*ptr != ~0) | ||
| 237 | break; | ||
| 238 | |||
| 239 | brelse(bh); | ||
| 240 | return *ptr != ~0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int omfs_unlink(struct inode *dir, struct dentry *dentry) | ||
| 244 | { | ||
| 245 | int ret; | ||
| 246 | struct inode *inode = dentry->d_inode; | ||
| 247 | |||
| 248 | ret = omfs_delete_entry(dentry); | ||
| 249 | if (ret) | ||
| 250 | goto end_unlink; | ||
| 251 | |||
| 252 | inode_dec_link_count(inode); | ||
| 253 | mark_inode_dirty(dir); | ||
| 254 | |||
| 255 | end_unlink: | ||
| 256 | return ret; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int omfs_rmdir(struct inode *dir, struct dentry *dentry) | ||
| 260 | { | ||
| 261 | int err = -ENOTEMPTY; | ||
| 262 | struct inode *inode = dentry->d_inode; | ||
| 263 | |||
| 264 | if (omfs_dir_is_empty(inode)) { | ||
| 265 | err = omfs_unlink(dir, dentry); | ||
| 266 | if (!err) | ||
| 267 | inode_dec_link_count(inode); | ||
| 268 | } | ||
| 269 | return err; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int omfs_add_node(struct inode *dir, struct dentry *dentry, int mode) | ||
| 273 | { | ||
| 274 | int err; | ||
| 275 | struct inode *inode = omfs_new_inode(dir, mode); | ||
| 276 | |||
| 277 | if (IS_ERR(inode)) | ||
| 278 | return PTR_ERR(inode); | ||
| 279 | |||
| 280 | err = omfs_make_empty(inode, dir->i_sb); | ||
| 281 | if (err) | ||
| 282 | goto out_free_inode; | ||
| 283 | |||
| 284 | err = omfs_add_link(dentry, inode); | ||
| 285 | if (err) | ||
| 286 | goto out_free_inode; | ||
| 287 | |||
| 288 | d_instantiate(dentry, inode); | ||
| 289 | return 0; | ||
| 290 | |||
| 291 | out_free_inode: | ||
| 292 | iput(inode); | ||
| 293 | return err; | ||
| 294 | } | ||
| 295 | |||
| 296 | static int omfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
| 297 | { | ||
| 298 | return omfs_add_node(dir, dentry, mode | S_IFDIR); | ||
| 299 | } | ||
| 300 | |||
| 301 | static int omfs_create(struct inode *dir, struct dentry *dentry, int mode, | ||
| 302 | struct nameidata *nd) | ||
| 303 | { | ||
| 304 | return omfs_add_node(dir, dentry, mode | S_IFREG); | ||
| 305 | } | ||
| 306 | |||
| 307 | static struct dentry *omfs_lookup(struct inode *dir, struct dentry *dentry, | ||
| 308 | struct nameidata *nd) | ||
| 309 | { | ||
| 310 | struct buffer_head *bh; | ||
| 311 | struct inode *inode = NULL; | ||
| 312 | |||
| 313 | if (dentry->d_name.len > OMFS_NAMELEN) | ||
| 314 | return ERR_PTR(-ENAMETOOLONG); | ||
| 315 | |||
| 316 | bh = omfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); | ||
| 317 | if (!IS_ERR(bh)) { | ||
| 318 | struct omfs_inode *oi = (struct omfs_inode *)bh->b_data; | ||
| 319 | ino_t ino = be64_to_cpu(oi->i_head.h_self); | ||
| 320 | brelse(bh); | ||
| 321 | inode = omfs_iget(dir->i_sb, ino); | ||
| 322 | if (IS_ERR(inode)) | ||
| 323 | return ERR_CAST(inode); | ||
| 324 | } | ||
| 325 | d_add(dentry, inode); | ||
| 326 | return NULL; | ||
| 327 | } | ||
| 328 | |||
| 329 | /* sanity check block's self pointer */ | ||
| 330 | int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, | ||
| 331 | u64 fsblock) | ||
| 332 | { | ||
| 333 | int is_bad; | ||
| 334 | u64 ino = be64_to_cpu(header->h_self); | ||
| 335 | is_bad = ((ino != fsblock) || (ino < sbi->s_root_ino) || | ||
| 336 | (ino > sbi->s_num_blocks)); | ||
| 337 | |||
| 338 | if (is_bad) | ||
| 339 | printk(KERN_WARNING "omfs: bad hash chain detected\n"); | ||
| 340 | |||
| 341 | return is_bad; | ||
| 342 | } | ||
| 343 | |||
| 344 | static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, | ||
| 345 | u64 fsblock, int hindex) | ||
| 346 | { | ||
| 347 | struct inode *dir = filp->f_dentry->d_inode; | ||
| 348 | struct buffer_head *bh; | ||
| 349 | struct omfs_inode *oi; | ||
| 350 | u64 self; | ||
| 351 | int res = 0; | ||
| 352 | unsigned char d_type; | ||
| 353 | |||
| 354 | /* follow chain in this bucket */ | ||
| 355 | while (fsblock != ~0) { | ||
| 356 | bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), | ||
| 357 | fsblock)); | ||
| 358 | if (!bh) | ||
| 359 | goto out; | ||
| 360 | |||
| 361 | oi = (struct omfs_inode *) bh->b_data; | ||
| 362 | if (omfs_is_bad(OMFS_SB(dir->i_sb), &oi->i_head, fsblock)) { | ||
| 363 | brelse(bh); | ||
| 364 | goto out; | ||
| 365 | } | ||
| 366 | |||
| 367 | self = fsblock; | ||
| 368 | fsblock = be64_to_cpu(oi->i_sibling); | ||
| 369 | |||
| 370 | /* skip visited nodes */ | ||
| 371 | if (hindex) { | ||
| 372 | hindex--; | ||
| 373 | brelse(bh); | ||
| 374 | continue; | ||
| 375 | } | ||
| 376 | |||
| 377 | d_type = (oi->i_type == OMFS_DIR) ? DT_DIR : DT_REG; | ||
| 378 | |||
| 379 | res = filldir(dirent, oi->i_name, strnlen(oi->i_name, | ||
| 380 | OMFS_NAMELEN), filp->f_pos, self, d_type); | ||
| 381 | if (res == 0) | ||
| 382 | filp->f_pos++; | ||
| 383 | brelse(bh); | ||
| 384 | } | ||
| 385 | out: | ||
| 386 | return res; | ||
| 387 | } | ||
| 388 | |||
| 389 | static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
| 390 | struct inode *new_dir, struct dentry *new_dentry) | ||
| 391 | { | ||
| 392 | struct inode *new_inode = new_dentry->d_inode; | ||
| 393 | struct inode *old_inode = old_dentry->d_inode; | ||
| 394 | struct buffer_head *bh; | ||
| 395 | int is_dir; | ||
| 396 | int err; | ||
| 397 | |||
| 398 | is_dir = S_ISDIR(old_inode->i_mode); | ||
| 399 | |||
| 400 | if (new_inode) { | ||
| 401 | /* overwriting existing file/dir */ | ||
| 402 | err = -ENOTEMPTY; | ||
| 403 | if (is_dir && !omfs_dir_is_empty(new_inode)) | ||
| 404 | goto out; | ||
| 405 | |||
| 406 | err = -ENOENT; | ||
| 407 | bh = omfs_find_entry(new_dir, new_dentry->d_name.name, | ||
| 408 | new_dentry->d_name.len); | ||
| 409 | if (IS_ERR(bh)) | ||
| 410 | goto out; | ||
| 411 | brelse(bh); | ||
| 412 | |||
| 413 | err = omfs_unlink(new_dir, new_dentry); | ||
| 414 | if (err) | ||
| 415 | goto out; | ||
| 416 | } | ||
| 417 | |||
| 418 | /* since omfs locates files by name, we need to unlink _before_ | ||
| 419 | * adding the new link or we won't find the old one */ | ||
| 420 | inode_inc_link_count(old_inode); | ||
| 421 | err = omfs_unlink(old_dir, old_dentry); | ||
| 422 | if (err) { | ||
| 423 | inode_dec_link_count(old_inode); | ||
| 424 | goto out; | ||
| 425 | } | ||
| 426 | |||
| 427 | err = omfs_add_link(new_dentry, old_inode); | ||
| 428 | if (err) | ||
| 429 | goto out; | ||
| 430 | |||
| 431 | old_inode->i_ctime = CURRENT_TIME_SEC; | ||
| 432 | out: | ||
| 433 | return err; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
| 437 | { | ||
| 438 | struct inode *dir = filp->f_dentry->d_inode; | ||
| 439 | struct buffer_head *bh; | ||
| 440 | loff_t offset, res; | ||
| 441 | unsigned int hchain, hindex; | ||
| 442 | int nbuckets; | ||
| 443 | u64 fsblock; | ||
| 444 | int ret = -EINVAL; | ||
| 445 | |||
| 446 | if (filp->f_pos >> 32) | ||
| 447 | goto success; | ||
| 448 | |||
| 449 | switch ((unsigned long) filp->f_pos) { | ||
| 450 | case 0: | ||
| 451 | if (filldir(dirent, ".", 1, 0, dir->i_ino, DT_DIR) < 0) | ||
| 452 | goto success; | ||
| 453 | filp->f_pos++; | ||
| 454 | /* fall through */ | ||
| 455 | case 1: | ||
| 456 | if (filldir(dirent, "..", 2, 1, | ||
| 457 | parent_ino(filp->f_dentry), DT_DIR) < 0) | ||
| 458 | goto success; | ||
| 459 | filp->f_pos = 1 << 20; | ||
| 460 | /* fall through */ | ||
| 461 | } | ||
| 462 | |||
| 463 | nbuckets = (dir->i_size - OMFS_DIR_START) / 8; | ||
| 464 | |||
| 465 | /* high 12 bits store bucket + 1 and low 20 bits store hash index */ | ||
| 466 | hchain = (filp->f_pos >> 20) - 1; | ||
| 467 | hindex = filp->f_pos & 0xfffff; | ||
| 468 | |||
| 469 | bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino)); | ||
| 470 | if (!bh) | ||
| 471 | goto out; | ||
| 472 | |||
| 473 | offset = OMFS_DIR_START + hchain * 8; | ||
| 474 | |||
| 475 | for (; hchain < nbuckets; hchain++, offset += 8) { | ||
| 476 | fsblock = be64_to_cpu(*((__be64 *) &bh->b_data[offset])); | ||
| 477 | |||
| 478 | res = omfs_fill_chain(filp, dirent, filldir, fsblock, hindex); | ||
| 479 | hindex = 0; | ||
| 480 | if (res < 0) | ||
| 481 | break; | ||
| 482 | |||
| 483 | filp->f_pos = (hchain+2) << 20; | ||
| 484 | } | ||
| 485 | brelse(bh); | ||
| 486 | success: | ||
| 487 | ret = 0; | ||
| 488 | out: | ||
| 489 | return ret; | ||
| 490 | } | ||
| 491 | |||
| 492 | struct inode_operations omfs_dir_inops = { | ||
| 493 | .lookup = omfs_lookup, | ||
| 494 | .mkdir = omfs_mkdir, | ||
| 495 | .rename = omfs_rename, | ||
| 496 | .create = omfs_create, | ||
| 497 | .unlink = omfs_unlink, | ||
| 498 | .rmdir = omfs_rmdir, | ||
| 499 | }; | ||
| 500 | |||
| 501 | struct file_operations omfs_dir_operations = { | ||
| 502 | .read = generic_read_dir, | ||
| 503 | .readdir = omfs_readdir, | ||
| 504 | }; | ||
diff --git a/fs/omfs/file.c b/fs/omfs/file.c new file mode 100644 index 000000000000..834b2331f6b3 --- /dev/null +++ b/fs/omfs/file.c | |||
| @@ -0,0 +1,365 @@ | |||
| 1 | /* | ||
| 2 | * OMFS (as used by RIO Karma) file operations. | ||
| 3 | * Copyright (C) 2005 Bob Copeland <me@bobcopeland.com> | ||
| 4 | * Released under GPL v2. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/version.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/fs.h> | ||
| 10 | #include <linux/buffer_head.h> | ||
| 11 | #include <linux/mpage.h> | ||
| 12 | #include "omfs.h" | ||
| 13 | |||
| 14 | static int omfs_sync_file(struct file *file, struct dentry *dentry, | ||
| 15 | int datasync) | ||
| 16 | { | ||
| 17 | struct inode *inode = dentry->d_inode; | ||
| 18 | int err; | ||
| 19 | |||
| 20 | err = sync_mapping_buffers(inode->i_mapping); | ||
| 21 | if (!(inode->i_state & I_DIRTY)) | ||
| 22 | return err; | ||
| 23 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 24 | return err; | ||
| 25 | err |= omfs_sync_inode(inode); | ||
| 26 | return err ? -EIO : 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset) | ||
| 30 | { | ||
| 31 | return (sbi->s_sys_blocksize - offset - | ||
| 32 | sizeof(struct omfs_extent)) / | ||
| 33 | sizeof(struct omfs_extent_entry) + 1; | ||
| 34 | } | ||
| 35 | |||
| 36 | void omfs_make_empty_table(struct buffer_head *bh, int offset) | ||
| 37 | { | ||
| 38 | struct omfs_extent *oe = (struct omfs_extent *) &bh->b_data[offset]; | ||
| 39 | |||
| 40 | oe->e_next = ~cpu_to_be64(0ULL); | ||
| 41 | oe->e_extent_count = cpu_to_be32(1), | ||
| 42 | oe->e_fill = cpu_to_be32(0x22), | ||
| 43 | oe->e_entry.e_cluster = ~cpu_to_be64(0ULL); | ||
| 44 | oe->e_entry.e_blocks = ~cpu_to_be64(0ULL); | ||
| 45 | } | ||
| 46 | |||
| 47 | int omfs_shrink_inode(struct inode *inode) | ||
| 48 | { | ||
| 49 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); | ||
| 50 | struct omfs_extent *oe; | ||
| 51 | struct omfs_extent_entry *entry; | ||
| 52 | struct buffer_head *bh; | ||
| 53 | u64 next, last; | ||
| 54 | u32 extent_count; | ||
| 55 | u32 max_extents; | ||
| 56 | int ret; | ||
| 57 | |||
| 58 | /* traverse extent table, freeing each entry that is greater | ||
| 59 | * than inode->i_size; | ||
| 60 | */ | ||
| 61 | next = inode->i_ino; | ||
| 62 | |||
| 63 | /* only support truncate -> 0 for now */ | ||
| 64 | ret = -EIO; | ||
| 65 | if (inode->i_size != 0) | ||
| 66 | goto out; | ||
| 67 | |||
| 68 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); | ||
| 69 | if (!bh) | ||
| 70 | goto out; | ||
| 71 | |||
| 72 | oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]); | ||
| 73 | max_extents = omfs_max_extents(sbi, OMFS_EXTENT_START); | ||
| 74 | |||
| 75 | for (;;) { | ||
| 76 | |||
| 77 | if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next)) | ||
| 78 | goto out_brelse; | ||
| 79 | |||
| 80 | extent_count = be32_to_cpu(oe->e_extent_count); | ||
| 81 | |||
| 82 | if (extent_count > max_extents) | ||
| 83 | goto out_brelse; | ||
| 84 | |||
| 85 | last = next; | ||
| 86 | next = be64_to_cpu(oe->e_next); | ||
| 87 | entry = &oe->e_entry; | ||
| 88 | |||
| 89 | /* ignore last entry as it is the terminator */ | ||
| 90 | for (; extent_count > 1; extent_count--) { | ||
| 91 | u64 start, count; | ||
| 92 | start = be64_to_cpu(entry->e_cluster); | ||
| 93 | count = be64_to_cpu(entry->e_blocks); | ||
| 94 | |||
| 95 | omfs_clear_range(inode->i_sb, start, (int) count); | ||
| 96 | entry++; | ||
| 97 | } | ||
| 98 | omfs_make_empty_table(bh, (char *) oe - bh->b_data); | ||
| 99 | mark_buffer_dirty(bh); | ||
| 100 | brelse(bh); | ||
| 101 | |||
| 102 | if (last != inode->i_ino) | ||
| 103 | omfs_clear_range(inode->i_sb, last, sbi->s_mirrors); | ||
| 104 | |||
| 105 | if (next == ~0) | ||
| 106 | break; | ||
| 107 | |||
| 108 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); | ||
| 109 | if (!bh) | ||
| 110 | goto out; | ||
| 111 | oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); | ||
| 112 | max_extents = omfs_max_extents(sbi, OMFS_EXTENT_CONT); | ||
| 113 | } | ||
| 114 | ret = 0; | ||
| 115 | out: | ||
| 116 | return ret; | ||
| 117 | out_brelse: | ||
| 118 | brelse(bh); | ||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | |||
| 122 | static void omfs_truncate(struct inode *inode) | ||
| 123 | { | ||
| 124 | omfs_shrink_inode(inode); | ||
| 125 | mark_inode_dirty(inode); | ||
| 126 | } | ||
| 127 | |||
| 128 | /* | ||
| 129 | * Add new blocks to the current extent, or create new entries/continuations | ||
| 130 | * as necessary. | ||
| 131 | */ | ||
| 132 | static int omfs_grow_extent(struct inode *inode, struct omfs_extent *oe, | ||
| 133 | u64 *ret_block) | ||
| 134 | { | ||
| 135 | struct omfs_extent_entry *terminator; | ||
| 136 | struct omfs_extent_entry *entry = &oe->e_entry; | ||
| 137 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); | ||
| 138 | u32 extent_count = be32_to_cpu(oe->e_extent_count); | ||
| 139 | u64 new_block = 0; | ||
| 140 | u32 max_count; | ||
| 141 | int new_count; | ||
| 142 | int ret = 0; | ||
| 143 | |||
| 144 | /* reached the end of the extent table with no blocks mapped. | ||
| 145 | * there are three possibilities for adding: grow last extent, | ||
| 146 | * add a new extent to the current extent table, and add a | ||
| 147 | * continuation inode. in last two cases need an allocator for | ||
| 148 | * sbi->s_cluster_size | ||
| 149 | */ | ||
| 150 | |||
| 151 | /* TODO: handle holes */ | ||
| 152 | |||
| 153 | /* should always have a terminator */ | ||
| 154 | if (extent_count < 1) | ||
| 155 | return -EIO; | ||
| 156 | |||
| 157 | /* trivially grow current extent, if next block is not taken */ | ||
| 158 | terminator = entry + extent_count - 1; | ||
| 159 | if (extent_count > 1) { | ||
| 160 | entry = terminator-1; | ||
| 161 | new_block = be64_to_cpu(entry->e_cluster) + | ||
| 162 | be64_to_cpu(entry->e_blocks); | ||
| 163 | |||
| 164 | if (omfs_allocate_block(inode->i_sb, new_block)) { | ||
| 165 | entry->e_blocks = | ||
| 166 | cpu_to_be64(be64_to_cpu(entry->e_blocks) + 1); | ||
| 167 | terminator->e_blocks = ~(cpu_to_be64( | ||
| 168 | be64_to_cpu(~terminator->e_blocks) + 1)); | ||
| 169 | goto out; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | max_count = omfs_max_extents(sbi, OMFS_EXTENT_START); | ||
| 173 | |||
| 174 | /* TODO: add a continuation block here */ | ||
| 175 | if (be32_to_cpu(oe->e_extent_count) > max_count-1) | ||
| 176 | return -EIO; | ||
| 177 | |||
| 178 | /* try to allocate a new cluster */ | ||
| 179 | ret = omfs_allocate_range(inode->i_sb, 1, sbi->s_clustersize, | ||
| 180 | &new_block, &new_count); | ||
| 181 | if (ret) | ||
| 182 | goto out_fail; | ||
| 183 | |||
| 184 | /* copy terminator down an entry */ | ||
| 185 | entry = terminator; | ||
| 186 | terminator++; | ||
| 187 | memcpy(terminator, entry, sizeof(struct omfs_extent_entry)); | ||
| 188 | |||
| 189 | entry->e_cluster = cpu_to_be64(new_block); | ||
| 190 | entry->e_blocks = cpu_to_be64((u64) new_count); | ||
| 191 | |||
| 192 | terminator->e_blocks = ~(cpu_to_be64( | ||
| 193 | be64_to_cpu(~terminator->e_blocks) + (u64) new_count)); | ||
| 194 | |||
| 195 | /* write in new entry */ | ||
| 196 | oe->e_extent_count = cpu_to_be32(1 + be32_to_cpu(oe->e_extent_count)); | ||
| 197 | |||
| 198 | out: | ||
| 199 | *ret_block = new_block; | ||
| 200 | out_fail: | ||
| 201 | return ret; | ||
| 202 | } | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Scans across the directory table for a given file block number. | ||
| 206 | * If block not found, return 0. | ||
| 207 | */ | ||
| 208 | static sector_t find_block(struct inode *inode, struct omfs_extent_entry *ent, | ||
| 209 | sector_t block, int count, int *left) | ||
| 210 | { | ||
| 211 | /* count > 1 because of terminator */ | ||
| 212 | sector_t searched = 0; | ||
| 213 | for (; count > 1; count--) { | ||
| 214 | int numblocks = clus_to_blk(OMFS_SB(inode->i_sb), | ||
| 215 | be64_to_cpu(ent->e_blocks)); | ||
| 216 | |||
| 217 | if (block >= searched && | ||
| 218 | block < searched + numblocks) { | ||
| 219 | /* | ||
| 220 | * found it at cluster + (block - searched) | ||
| 221 | * numblocks - (block - searched) is remainder | ||
| 222 | */ | ||
| 223 | *left = numblocks - (block - searched); | ||
| 224 | return clus_to_blk(OMFS_SB(inode->i_sb), | ||
| 225 | be64_to_cpu(ent->e_cluster)) + | ||
| 226 | block - searched; | ||
| 227 | } | ||
| 228 | searched += numblocks; | ||
| 229 | ent++; | ||
| 230 | } | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static int omfs_get_block(struct inode *inode, sector_t block, | ||
| 235 | struct buffer_head *bh_result, int create) | ||
| 236 | { | ||
| 237 | struct buffer_head *bh; | ||
| 238 | sector_t next, offset; | ||
| 239 | int ret; | ||
| 240 | u64 new_block; | ||
| 241 | u32 max_extents; | ||
| 242 | int extent_count; | ||
| 243 | struct omfs_extent *oe; | ||
| 244 | struct omfs_extent_entry *entry; | ||
| 245 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); | ||
| 246 | int max_blocks = bh_result->b_size >> inode->i_blkbits; | ||
| 247 | int remain; | ||
| 248 | |||
| 249 | ret = -EIO; | ||
| 250 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino)); | ||
| 251 | if (!bh) | ||
| 252 | goto out; | ||
| 253 | |||
| 254 | oe = (struct omfs_extent *)(&bh->b_data[OMFS_EXTENT_START]); | ||
| 255 | max_extents = omfs_max_extents(sbi, OMFS_EXTENT_START); | ||
| 256 | next = inode->i_ino; | ||
| 257 | |||
| 258 | for (;;) { | ||
| 259 | |||
| 260 | if (omfs_is_bad(sbi, (struct omfs_header *) bh->b_data, next)) | ||
| 261 | goto out_brelse; | ||
| 262 | |||
| 263 | extent_count = be32_to_cpu(oe->e_extent_count); | ||
| 264 | next = be64_to_cpu(oe->e_next); | ||
| 265 | entry = &oe->e_entry; | ||
| 266 | |||
| 267 | if (extent_count > max_extents) | ||
| 268 | goto out_brelse; | ||
| 269 | |||
| 270 | offset = find_block(inode, entry, block, extent_count, &remain); | ||
| 271 | if (offset > 0) { | ||
| 272 | ret = 0; | ||
| 273 | map_bh(bh_result, inode->i_sb, offset); | ||
| 274 | if (remain > max_blocks) | ||
| 275 | remain = max_blocks; | ||
| 276 | bh_result->b_size = (remain << inode->i_blkbits); | ||
| 277 | goto out_brelse; | ||
| 278 | } | ||
| 279 | if (next == ~0) | ||
| 280 | break; | ||
| 281 | |||
| 282 | brelse(bh); | ||
| 283 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); | ||
| 284 | if (!bh) | ||
| 285 | goto out; | ||
| 286 | oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); | ||
| 287 | max_extents = omfs_max_extents(sbi, OMFS_EXTENT_CONT); | ||
| 288 | } | ||
| 289 | if (create) { | ||
| 290 | ret = omfs_grow_extent(inode, oe, &new_block); | ||
| 291 | if (ret == 0) { | ||
| 292 | mark_buffer_dirty(bh); | ||
| 293 | mark_inode_dirty(inode); | ||
| 294 | map_bh(bh_result, inode->i_sb, | ||
| 295 | clus_to_blk(sbi, new_block)); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | out_brelse: | ||
| 299 | brelse(bh); | ||
| 300 | out: | ||
| 301 | return ret; | ||
| 302 | } | ||
| 303 | |||
| 304 | static int omfs_readpage(struct file *file, struct page *page) | ||
| 305 | { | ||
| 306 | return block_read_full_page(page, omfs_get_block); | ||
| 307 | } | ||
| 308 | |||
| 309 | static int omfs_readpages(struct file *file, struct address_space *mapping, | ||
| 310 | struct list_head *pages, unsigned nr_pages) | ||
| 311 | { | ||
| 312 | return mpage_readpages(mapping, pages, nr_pages, omfs_get_block); | ||
| 313 | } | ||
| 314 | |||
| 315 | static int omfs_writepage(struct page *page, struct writeback_control *wbc) | ||
| 316 | { | ||
| 317 | return block_write_full_page(page, omfs_get_block, wbc); | ||
| 318 | } | ||
| 319 | |||
| 320 | static int | ||
| 321 | omfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | ||
| 322 | { | ||
| 323 | return mpage_writepages(mapping, wbc, omfs_get_block); | ||
| 324 | } | ||
| 325 | |||
| 326 | static int omfs_write_begin(struct file *file, struct address_space *mapping, | ||
| 327 | loff_t pos, unsigned len, unsigned flags, | ||
| 328 | struct page **pagep, void **fsdata) | ||
| 329 | { | ||
| 330 | *pagep = NULL; | ||
| 331 | return block_write_begin(file, mapping, pos, len, flags, | ||
| 332 | pagep, fsdata, omfs_get_block); | ||
| 333 | } | ||
| 334 | |||
| 335 | static sector_t omfs_bmap(struct address_space *mapping, sector_t block) | ||
| 336 | { | ||
| 337 | return generic_block_bmap(mapping, block, omfs_get_block); | ||
| 338 | } | ||
| 339 | |||
| 340 | struct file_operations omfs_file_operations = { | ||
| 341 | .llseek = generic_file_llseek, | ||
| 342 | .read = do_sync_read, | ||
| 343 | .write = do_sync_write, | ||
| 344 | .aio_read = generic_file_aio_read, | ||
| 345 | .aio_write = generic_file_aio_write, | ||
| 346 | .mmap = generic_file_mmap, | ||
| 347 | .fsync = omfs_sync_file, | ||
| 348 | .splice_read = generic_file_splice_read, | ||
| 349 | }; | ||
| 350 | |||
| 351 | struct inode_operations omfs_file_inops = { | ||
| 352 | .truncate = omfs_truncate | ||
| 353 | }; | ||
| 354 | |||
| 355 | struct address_space_operations omfs_aops = { | ||
| 356 | .readpage = omfs_readpage, | ||
| 357 | .readpages = omfs_readpages, | ||
| 358 | .writepage = omfs_writepage, | ||
| 359 | .writepages = omfs_writepages, | ||
| 360 | .sync_page = block_sync_page, | ||
| 361 | .write_begin = omfs_write_begin, | ||
| 362 | .write_end = generic_write_end, | ||
| 363 | .bmap = omfs_bmap, | ||
| 364 | }; | ||
| 365 | |||
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c new file mode 100644 index 000000000000..d29047b1b9b0 --- /dev/null +++ b/fs/omfs/inode.c | |||
| @@ -0,0 +1,553 @@ | |||
| 1 | /* | ||
| 2 | * Optimized MPEG FS - inode and super operations. | ||
| 3 | * Copyright (C) 2006 Bob Copeland <me@bobcopeland.com> | ||
| 4 | * Released under GPL v2. | ||
| 5 | */ | ||
| 6 | #include <linux/version.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/sched.h> | ||
| 9 | #include <linux/fs.h> | ||
| 10 | #include <linux/vfs.h> | ||
| 11 | #include <linux/parser.h> | ||
| 12 | #include <linux/buffer_head.h> | ||
| 13 | #include <linux/vmalloc.h> | ||
| 14 | #include <linux/crc-itu-t.h> | ||
| 15 | #include "omfs.h" | ||
| 16 | |||
| 17 | MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>"); | ||
| 18 | MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); | ||
| 19 | MODULE_LICENSE("GPL"); | ||
| 20 | |||
| 21 | struct inode *omfs_new_inode(struct inode *dir, int mode) | ||
| 22 | { | ||
| 23 | struct inode *inode; | ||
| 24 | u64 new_block; | ||
| 25 | int err; | ||
| 26 | int len; | ||
| 27 | struct omfs_sb_info *sbi = OMFS_SB(dir->i_sb); | ||
| 28 | |||
| 29 | inode = new_inode(dir->i_sb); | ||
| 30 | if (!inode) | ||
| 31 | return ERR_PTR(-ENOMEM); | ||
| 32 | |||
| 33 | err = omfs_allocate_range(dir->i_sb, sbi->s_mirrors, sbi->s_mirrors, | ||
| 34 | &new_block, &len); | ||
| 35 | if (err) | ||
| 36 | goto fail; | ||
| 37 | |||
| 38 | inode->i_ino = new_block; | ||
| 39 | inode->i_mode = mode; | ||
| 40 | inode->i_uid = current->fsuid; | ||
| 41 | inode->i_gid = current->fsgid; | ||
| 42 | inode->i_blocks = 0; | ||
| 43 | inode->i_mapping->a_ops = &omfs_aops; | ||
| 44 | |||
| 45 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
| 46 | switch (mode & S_IFMT) { | ||
| 47 | case S_IFDIR: | ||
| 48 | inode->i_op = &omfs_dir_inops; | ||
| 49 | inode->i_fop = &omfs_dir_operations; | ||
| 50 | inode->i_size = sbi->s_sys_blocksize; | ||
| 51 | inc_nlink(inode); | ||
| 52 | break; | ||
| 53 | case S_IFREG: | ||
| 54 | inode->i_op = &omfs_file_inops; | ||
| 55 | inode->i_fop = &omfs_file_operations; | ||
| 56 | inode->i_size = 0; | ||
| 57 | break; | ||
| 58 | } | ||
| 59 | |||
| 60 | insert_inode_hash(inode); | ||
| 61 | mark_inode_dirty(inode); | ||
| 62 | return inode; | ||
| 63 | fail: | ||
| 64 | make_bad_inode(inode); | ||
| 65 | iput(inode); | ||
| 66 | return ERR_PTR(err); | ||
| 67 | } | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Update the header checksums for a dirty inode based on its contents. | ||
| 71 | * Caller is expected to hold the buffer head underlying oi and mark it | ||
| 72 | * dirty. | ||
| 73 | */ | ||
| 74 | static void omfs_update_checksums(struct omfs_inode *oi) | ||
| 75 | { | ||
| 76 | int xor, i, ofs = 0, count; | ||
| 77 | u16 crc = 0; | ||
| 78 | unsigned char *ptr = (unsigned char *) oi; | ||
| 79 | |||
| 80 | count = be32_to_cpu(oi->i_head.h_body_size); | ||
| 81 | ofs = sizeof(struct omfs_header); | ||
| 82 | |||
| 83 | crc = crc_itu_t(crc, ptr + ofs, count); | ||
| 84 | oi->i_head.h_crc = cpu_to_be16(crc); | ||
| 85 | |||
| 86 | xor = ptr[0]; | ||
| 87 | for (i = 1; i < OMFS_XOR_COUNT; i++) | ||
| 88 | xor ^= ptr[i]; | ||
| 89 | |||
| 90 | oi->i_head.h_check_xor = xor; | ||
| 91 | } | ||
| 92 | |||
| 93 | static int omfs_write_inode(struct inode *inode, int wait) | ||
| 94 | { | ||
| 95 | struct omfs_inode *oi; | ||
| 96 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); | ||
| 97 | struct buffer_head *bh, *bh2; | ||
| 98 | unsigned int block; | ||
| 99 | u64 ctime; | ||
| 100 | int i; | ||
| 101 | int ret = -EIO; | ||
| 102 | int sync_failed = 0; | ||
| 103 | |||
| 104 | /* get current inode since we may have written sibling ptrs etc. */ | ||
| 105 | block = clus_to_blk(sbi, inode->i_ino); | ||
| 106 | bh = sb_bread(inode->i_sb, block); | ||
| 107 | if (!bh) | ||
| 108 | goto out; | ||
| 109 | |||
| 110 | oi = (struct omfs_inode *) bh->b_data; | ||
| 111 | |||
| 112 | oi->i_head.h_self = cpu_to_be64(inode->i_ino); | ||
| 113 | if (S_ISDIR(inode->i_mode)) | ||
| 114 | oi->i_type = OMFS_DIR; | ||
| 115 | else if (S_ISREG(inode->i_mode)) | ||
| 116 | oi->i_type = OMFS_FILE; | ||
| 117 | else { | ||
| 118 | printk(KERN_WARNING "omfs: unknown file type: %d\n", | ||
| 119 | inode->i_mode); | ||
| 120 | goto out_brelse; | ||
| 121 | } | ||
| 122 | |||
| 123 | oi->i_head.h_body_size = cpu_to_be32(sbi->s_sys_blocksize - | ||
| 124 | sizeof(struct omfs_header)); | ||
| 125 | oi->i_head.h_version = 1; | ||
| 126 | oi->i_head.h_type = OMFS_INODE_NORMAL; | ||
| 127 | oi->i_head.h_magic = OMFS_IMAGIC; | ||
| 128 | oi->i_size = cpu_to_be64(inode->i_size); | ||
| 129 | |||
| 130 | ctime = inode->i_ctime.tv_sec * 1000LL + | ||
| 131 | ((inode->i_ctime.tv_nsec + 999)/1000); | ||
| 132 | oi->i_ctime = cpu_to_be64(ctime); | ||
| 133 | |||
| 134 | omfs_update_checksums(oi); | ||
| 135 | |||
| 136 | mark_buffer_dirty(bh); | ||
| 137 | if (wait) { | ||
| 138 | sync_dirty_buffer(bh); | ||
| 139 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
| 140 | sync_failed = 1; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* if mirroring writes, copy to next fsblock */ | ||
| 144 | for (i = 1; i < sbi->s_mirrors; i++) { | ||
| 145 | bh2 = sb_bread(inode->i_sb, block + i * | ||
| 146 | (sbi->s_blocksize / sbi->s_sys_blocksize)); | ||
| 147 | if (!bh2) | ||
| 148 | goto out_brelse; | ||
| 149 | |||
| 150 | memcpy(bh2->b_data, bh->b_data, bh->b_size); | ||
| 151 | mark_buffer_dirty(bh2); | ||
| 152 | if (wait) { | ||
| 153 | sync_dirty_buffer(bh2); | ||
| 154 | if (buffer_req(bh2) && !buffer_uptodate(bh2)) | ||
| 155 | sync_failed = 1; | ||
| 156 | } | ||
| 157 | brelse(bh2); | ||
| 158 | } | ||
| 159 | ret = (sync_failed) ? -EIO : 0; | ||
| 160 | out_brelse: | ||
| 161 | brelse(bh); | ||
| 162 | out: | ||
| 163 | return ret; | ||
| 164 | } | ||
| 165 | |||
| 166 | int omfs_sync_inode(struct inode *inode) | ||
| 167 | { | ||
| 168 | return omfs_write_inode(inode, 1); | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * called when an entry is deleted, need to clear the bits in the | ||
| 173 | * bitmaps. | ||
| 174 | */ | ||
| 175 | static void omfs_delete_inode(struct inode *inode) | ||
| 176 | { | ||
| 177 | truncate_inode_pages(&inode->i_data, 0); | ||
| 178 | |||
| 179 | if (S_ISREG(inode->i_mode)) { | ||
| 180 | inode->i_size = 0; | ||
| 181 | omfs_shrink_inode(inode); | ||
| 182 | } | ||
| 183 | |||
| 184 | omfs_clear_range(inode->i_sb, inode->i_ino, 2); | ||
| 185 | clear_inode(inode); | ||
| 186 | } | ||
| 187 | |||
| 188 | struct inode *omfs_iget(struct super_block *sb, ino_t ino) | ||
| 189 | { | ||
| 190 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 191 | struct omfs_inode *oi; | ||
| 192 | struct buffer_head *bh; | ||
| 193 | unsigned int block; | ||
| 194 | u64 ctime; | ||
| 195 | unsigned long nsecs; | ||
| 196 | struct inode *inode; | ||
| 197 | |||
| 198 | inode = iget_locked(sb, ino); | ||
| 199 | if (!inode) | ||
| 200 | return ERR_PTR(-ENOMEM); | ||
| 201 | if (!(inode->i_state & I_NEW)) | ||
| 202 | return inode; | ||
| 203 | |||
| 204 | block = clus_to_blk(sbi, ino); | ||
| 205 | bh = sb_bread(inode->i_sb, block); | ||
| 206 | if (!bh) | ||
| 207 | goto iget_failed; | ||
| 208 | |||
| 209 | oi = (struct omfs_inode *)bh->b_data; | ||
| 210 | |||
| 211 | /* check self */ | ||
| 212 | if (ino != be64_to_cpu(oi->i_head.h_self)) | ||
| 213 | goto fail_bh; | ||
| 214 | |||
| 215 | inode->i_uid = sbi->s_uid; | ||
| 216 | inode->i_gid = sbi->s_gid; | ||
| 217 | |||
| 218 | ctime = be64_to_cpu(oi->i_ctime); | ||
| 219 | nsecs = do_div(ctime, 1000) * 1000L; | ||
| 220 | |||
| 221 | inode->i_atime.tv_sec = ctime; | ||
| 222 | inode->i_mtime.tv_sec = ctime; | ||
| 223 | inode->i_ctime.tv_sec = ctime; | ||
| 224 | inode->i_atime.tv_nsec = nsecs; | ||
| 225 | inode->i_mtime.tv_nsec = nsecs; | ||
| 226 | inode->i_ctime.tv_nsec = nsecs; | ||
| 227 | |||
| 228 | inode->i_mapping->a_ops = &omfs_aops; | ||
| 229 | |||
| 230 | switch (oi->i_type) { | ||
| 231 | case OMFS_DIR: | ||
| 232 | inode->i_mode = S_IFDIR | (S_IRWXUGO & ~sbi->s_dmask); | ||
| 233 | inode->i_op = &omfs_dir_inops; | ||
| 234 | inode->i_fop = &omfs_dir_operations; | ||
| 235 | inode->i_size = sbi->s_sys_blocksize; | ||
| 236 | inc_nlink(inode); | ||
| 237 | break; | ||
| 238 | case OMFS_FILE: | ||
| 239 | inode->i_mode = S_IFREG | (S_IRWXUGO & ~sbi->s_fmask); | ||
| 240 | inode->i_fop = &omfs_file_operations; | ||
| 241 | inode->i_size = be64_to_cpu(oi->i_size); | ||
| 242 | break; | ||
| 243 | } | ||
| 244 | brelse(bh); | ||
| 245 | unlock_new_inode(inode); | ||
| 246 | return inode; | ||
| 247 | fail_bh: | ||
| 248 | brelse(bh); | ||
| 249 | iget_failed: | ||
| 250 | iget_failed(inode); | ||
| 251 | return ERR_PTR(-EIO); | ||
| 252 | } | ||
| 253 | |||
| 254 | static void omfs_put_super(struct super_block *sb) | ||
| 255 | { | ||
| 256 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 257 | kfree(sbi->s_imap); | ||
| 258 | kfree(sbi); | ||
| 259 | sb->s_fs_info = NULL; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
| 263 | { | ||
| 264 | struct super_block *s = dentry->d_sb; | ||
| 265 | struct omfs_sb_info *sbi = OMFS_SB(s); | ||
| 266 | buf->f_type = OMFS_MAGIC; | ||
| 267 | buf->f_bsize = sbi->s_blocksize; | ||
| 268 | buf->f_blocks = sbi->s_num_blocks; | ||
| 269 | buf->f_files = sbi->s_num_blocks; | ||
| 270 | buf->f_namelen = OMFS_NAMELEN; | ||
| 271 | |||
| 272 | buf->f_bfree = buf->f_bavail = buf->f_ffree = | ||
| 273 | omfs_count_free(s); | ||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | static struct super_operations omfs_sops = { | ||
| 278 | .write_inode = omfs_write_inode, | ||
| 279 | .delete_inode = omfs_delete_inode, | ||
| 280 | .put_super = omfs_put_super, | ||
| 281 | .statfs = omfs_statfs, | ||
| 282 | .show_options = generic_show_options, | ||
| 283 | }; | ||
| 284 | |||
| 285 | /* | ||
| 286 | * For Rio Karma, there is an on-disk free bitmap whose location is | ||
| 287 | * stored in the root block. For ReplayTV, there is no such free bitmap | ||
| 288 | * so we have to walk the tree. Both inodes and file data are allocated | ||
| 289 | * from the same map. This array can be big (300k) so we allocate | ||
| 290 | * in units of the blocksize. | ||
| 291 | */ | ||
| 292 | static int omfs_get_imap(struct super_block *sb) | ||
| 293 | { | ||
| 294 | int bitmap_size; | ||
| 295 | int array_size; | ||
| 296 | int count; | ||
| 297 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 298 | struct buffer_head *bh; | ||
| 299 | unsigned long **ptr; | ||
| 300 | sector_t block; | ||
| 301 | |||
| 302 | bitmap_size = DIV_ROUND_UP(sbi->s_num_blocks, 8); | ||
| 303 | array_size = DIV_ROUND_UP(bitmap_size, sb->s_blocksize); | ||
| 304 | |||
| 305 | if (sbi->s_bitmap_ino == ~0ULL) | ||
| 306 | goto out; | ||
| 307 | |||
| 308 | sbi->s_imap_size = array_size; | ||
| 309 | sbi->s_imap = kzalloc(array_size * sizeof(unsigned long *), GFP_KERNEL); | ||
| 310 | if (!sbi->s_imap) | ||
| 311 | goto nomem; | ||
| 312 | |||
| 313 | block = clus_to_blk(sbi, sbi->s_bitmap_ino); | ||
| 314 | ptr = sbi->s_imap; | ||
| 315 | for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { | ||
| 316 | bh = sb_bread(sb, block++); | ||
| 317 | if (!bh) | ||
| 318 | goto nomem_free; | ||
| 319 | *ptr = kmalloc(sb->s_blocksize, GFP_KERNEL); | ||
| 320 | if (!*ptr) { | ||
| 321 | brelse(bh); | ||
| 322 | goto nomem_free; | ||
| 323 | } | ||
| 324 | memcpy(*ptr, bh->b_data, sb->s_blocksize); | ||
| 325 | if (count < sb->s_blocksize) | ||
| 326 | memset((void *)*ptr + count, 0xff, | ||
| 327 | sb->s_blocksize - count); | ||
| 328 | brelse(bh); | ||
| 329 | ptr++; | ||
| 330 | } | ||
| 331 | out: | ||
| 332 | return 0; | ||
| 333 | |||
| 334 | nomem_free: | ||
| 335 | for (count = 0; count < array_size; count++) | ||
| 336 | kfree(sbi->s_imap[count]); | ||
| 337 | |||
| 338 | kfree(sbi->s_imap); | ||
| 339 | nomem: | ||
| 340 | sbi->s_imap = NULL; | ||
| 341 | sbi->s_imap_size = 0; | ||
| 342 | return -ENOMEM; | ||
| 343 | } | ||
| 344 | |||
| 345 | enum { | ||
| 346 | Opt_uid, Opt_gid, Opt_umask, Opt_dmask, Opt_fmask | ||
| 347 | }; | ||
| 348 | |||
| 349 | static match_table_t tokens = { | ||
| 350 | {Opt_uid, "uid=%u"}, | ||
| 351 | {Opt_gid, "gid=%u"}, | ||
| 352 | {Opt_umask, "umask=%o"}, | ||
| 353 | {Opt_dmask, "dmask=%o"}, | ||
| 354 | {Opt_fmask, "fmask=%o"}, | ||
| 355 | }; | ||
| 356 | |||
| 357 | static int parse_options(char *options, struct omfs_sb_info *sbi) | ||
| 358 | { | ||
| 359 | char *p; | ||
| 360 | substring_t args[MAX_OPT_ARGS]; | ||
| 361 | int option; | ||
| 362 | |||
| 363 | if (!options) | ||
| 364 | return 1; | ||
| 365 | |||
| 366 | while ((p = strsep(&options, ",")) != NULL) { | ||
| 367 | int token; | ||
| 368 | if (!*p) | ||
| 369 | continue; | ||
| 370 | |||
| 371 | token = match_token(p, tokens, args); | ||
| 372 | switch (token) { | ||
| 373 | case Opt_uid: | ||
| 374 | if (match_int(&args[0], &option)) | ||
| 375 | return 0; | ||
| 376 | sbi->s_uid = option; | ||
| 377 | break; | ||
| 378 | case Opt_gid: | ||
| 379 | if (match_int(&args[0], &option)) | ||
| 380 | return 0; | ||
| 381 | sbi->s_gid = option; | ||
| 382 | break; | ||
| 383 | case Opt_umask: | ||
| 384 | if (match_octal(&args[0], &option)) | ||
| 385 | return 0; | ||
| 386 | sbi->s_fmask = sbi->s_dmask = option; | ||
| 387 | break; | ||
| 388 | case Opt_dmask: | ||
| 389 | if (match_octal(&args[0], &option)) | ||
| 390 | return 0; | ||
| 391 | sbi->s_dmask = option; | ||
| 392 | break; | ||
| 393 | case Opt_fmask: | ||
| 394 | if (match_octal(&args[0], &option)) | ||
| 395 | return 0; | ||
| 396 | sbi->s_fmask = option; | ||
| 397 | break; | ||
| 398 | default: | ||
| 399 | return 0; | ||
| 400 | } | ||
| 401 | } | ||
| 402 | return 1; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int omfs_fill_super(struct super_block *sb, void *data, int silent) | ||
| 406 | { | ||
| 407 | struct buffer_head *bh, *bh2; | ||
| 408 | struct omfs_super_block *omfs_sb; | ||
| 409 | struct omfs_root_block *omfs_rb; | ||
| 410 | struct omfs_sb_info *sbi; | ||
| 411 | struct inode *root; | ||
| 412 | sector_t start; | ||
| 413 | int ret = -EINVAL; | ||
| 414 | |||
| 415 | save_mount_options(sb, (char *) data); | ||
| 416 | |||
| 417 | sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL); | ||
| 418 | if (!sbi) | ||
| 419 | return -ENOMEM; | ||
| 420 | |||
| 421 | sb->s_fs_info = sbi; | ||
| 422 | |||
| 423 | sbi->s_uid = current->uid; | ||
| 424 | sbi->s_gid = current->gid; | ||
| 425 | sbi->s_dmask = sbi->s_fmask = current->fs->umask; | ||
| 426 | |||
| 427 | if (!parse_options((char *) data, sbi)) | ||
| 428 | goto end; | ||
| 429 | |||
| 430 | sb->s_maxbytes = 0xffffffff; | ||
| 431 | |||
| 432 | sb_set_blocksize(sb, 0x200); | ||
| 433 | |||
| 434 | bh = sb_bread(sb, 0); | ||
| 435 | if (!bh) | ||
| 436 | goto end; | ||
| 437 | |||
| 438 | omfs_sb = (struct omfs_super_block *)bh->b_data; | ||
| 439 | |||
| 440 | if (omfs_sb->s_magic != cpu_to_be32(OMFS_MAGIC)) { | ||
| 441 | if (!silent) | ||
| 442 | printk(KERN_ERR "omfs: Invalid superblock (%x)\n", | ||
| 443 | omfs_sb->s_magic); | ||
| 444 | goto out_brelse_bh; | ||
| 445 | } | ||
| 446 | sb->s_magic = OMFS_MAGIC; | ||
| 447 | |||
| 448 | sbi->s_num_blocks = be64_to_cpu(omfs_sb->s_num_blocks); | ||
| 449 | sbi->s_blocksize = be32_to_cpu(omfs_sb->s_blocksize); | ||
| 450 | sbi->s_mirrors = be32_to_cpu(omfs_sb->s_mirrors); | ||
| 451 | sbi->s_root_ino = be64_to_cpu(omfs_sb->s_root_block); | ||
| 452 | sbi->s_sys_blocksize = be32_to_cpu(omfs_sb->s_sys_blocksize); | ||
| 453 | mutex_init(&sbi->s_bitmap_lock); | ||
| 454 | |||
| 455 | if (sbi->s_sys_blocksize > PAGE_SIZE) { | ||
| 456 | printk(KERN_ERR "omfs: sysblock size (%d) is out of range\n", | ||
| 457 | sbi->s_sys_blocksize); | ||
| 458 | goto out_brelse_bh; | ||
| 459 | } | ||
| 460 | |||
| 461 | if (sbi->s_blocksize < sbi->s_sys_blocksize || | ||
| 462 | sbi->s_blocksize > OMFS_MAX_BLOCK_SIZE) { | ||
| 463 | printk(KERN_ERR "omfs: block size (%d) is out of range\n", | ||
| 464 | sbi->s_blocksize); | ||
| 465 | goto out_brelse_bh; | ||
| 466 | } | ||
| 467 | |||
| 468 | /* | ||
| 469 | * Use sys_blocksize as the fs block since it is smaller than a | ||
| 470 | * page while the fs blocksize can be larger. | ||
| 471 | */ | ||
| 472 | sb_set_blocksize(sb, sbi->s_sys_blocksize); | ||
| 473 | |||
| 474 | /* | ||
| 475 | * ...and the difference goes into a shift. sys_blocksize is always | ||
| 476 | * a power of two factor of blocksize. | ||
| 477 | */ | ||
| 478 | sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - | ||
| 479 | get_bitmask_order(sbi->s_sys_blocksize); | ||
| 480 | |||
| 481 | start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block)); | ||
| 482 | bh2 = sb_bread(sb, start); | ||
| 483 | if (!bh2) | ||
| 484 | goto out_brelse_bh; | ||
| 485 | |||
| 486 | omfs_rb = (struct omfs_root_block *)bh2->b_data; | ||
| 487 | |||
| 488 | sbi->s_bitmap_ino = be64_to_cpu(omfs_rb->r_bitmap); | ||
| 489 | sbi->s_clustersize = be32_to_cpu(omfs_rb->r_clustersize); | ||
| 490 | |||
| 491 | if (sbi->s_num_blocks != be64_to_cpu(omfs_rb->r_num_blocks)) { | ||
| 492 | printk(KERN_ERR "omfs: block count discrepancy between " | ||
| 493 | "super and root blocks (%llx, %llx)\n", | ||
| 494 | (unsigned long long)sbi->s_num_blocks, | ||
| 495 | (unsigned long long)be64_to_cpu(omfs_rb->r_num_blocks)); | ||
| 496 | goto out_brelse_bh2; | ||
| 497 | } | ||
| 498 | |||
| 499 | ret = omfs_get_imap(sb); | ||
| 500 | if (ret) | ||
| 501 | goto out_brelse_bh2; | ||
| 502 | |||
| 503 | sb->s_op = &omfs_sops; | ||
| 504 | |||
| 505 | root = omfs_iget(sb, be64_to_cpu(omfs_rb->r_root_dir)); | ||
| 506 | if (IS_ERR(root)) { | ||
| 507 | ret = PTR_ERR(root); | ||
| 508 | goto out_brelse_bh2; | ||
| 509 | } | ||
| 510 | |||
| 511 | sb->s_root = d_alloc_root(root); | ||
| 512 | if (!sb->s_root) { | ||
| 513 | iput(root); | ||
| 514 | goto out_brelse_bh2; | ||
| 515 | } | ||
| 516 | printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name); | ||
| 517 | |||
| 518 | ret = 0; | ||
| 519 | out_brelse_bh2: | ||
| 520 | brelse(bh2); | ||
| 521 | out_brelse_bh: | ||
| 522 | brelse(bh); | ||
| 523 | end: | ||
| 524 | return ret; | ||
| 525 | } | ||
| 526 | |||
| 527 | static int omfs_get_sb(struct file_system_type *fs_type, | ||
| 528 | int flags, const char *dev_name, | ||
| 529 | void *data, struct vfsmount *m) | ||
| 530 | { | ||
| 531 | return get_sb_bdev(fs_type, flags, dev_name, data, omfs_fill_super, m); | ||
| 532 | } | ||
| 533 | |||
| 534 | static struct file_system_type omfs_fs_type = { | ||
| 535 | .owner = THIS_MODULE, | ||
| 536 | .name = "omfs", | ||
| 537 | .get_sb = omfs_get_sb, | ||
| 538 | .kill_sb = kill_block_super, | ||
| 539 | .fs_flags = FS_REQUIRES_DEV, | ||
| 540 | }; | ||
| 541 | |||
| 542 | static int __init init_omfs_fs(void) | ||
| 543 | { | ||
| 544 | return register_filesystem(&omfs_fs_type); | ||
| 545 | } | ||
| 546 | |||
| 547 | static void __exit exit_omfs_fs(void) | ||
| 548 | { | ||
| 549 | unregister_filesystem(&omfs_fs_type); | ||
| 550 | } | ||
| 551 | |||
| 552 | module_init(init_omfs_fs); | ||
| 553 | module_exit(exit_omfs_fs); | ||
diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h new file mode 100644 index 000000000000..2bc0f0670406 --- /dev/null +++ b/fs/omfs/omfs.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | #ifndef _OMFS_H | ||
| 2 | #define _OMFS_H | ||
| 3 | |||
| 4 | #include <linux/module.h> | ||
| 5 | #include <linux/fs.h> | ||
| 6 | |||
| 7 | #include "omfs_fs.h" | ||
| 8 | |||
| 9 | /* In-memory structures */ | ||
| 10 | struct omfs_sb_info { | ||
| 11 | u64 s_num_blocks; | ||
| 12 | u64 s_bitmap_ino; | ||
| 13 | u64 s_root_ino; | ||
| 14 | u32 s_blocksize; | ||
| 15 | u32 s_mirrors; | ||
| 16 | u32 s_sys_blocksize; | ||
| 17 | u32 s_clustersize; | ||
| 18 | int s_block_shift; | ||
| 19 | unsigned long **s_imap; | ||
| 20 | int s_imap_size; | ||
| 21 | struct mutex s_bitmap_lock; | ||
| 22 | int s_uid; | ||
| 23 | int s_gid; | ||
| 24 | int s_dmask; | ||
| 25 | int s_fmask; | ||
| 26 | }; | ||
| 27 | |||
| 28 | /* convert a cluster number to a scaled block number */ | ||
| 29 | static inline sector_t clus_to_blk(struct omfs_sb_info *sbi, sector_t block) | ||
| 30 | { | ||
| 31 | return block << sbi->s_block_shift; | ||
| 32 | } | ||
| 33 | |||
| 34 | static inline struct omfs_sb_info *OMFS_SB(struct super_block *sb) | ||
| 35 | { | ||
| 36 | return sb->s_fs_info; | ||
| 37 | } | ||
| 38 | |||
| 39 | /* bitmap.c */ | ||
| 40 | extern unsigned long omfs_count_free(struct super_block *sb); | ||
| 41 | extern int omfs_allocate_block(struct super_block *sb, u64 block); | ||
| 42 | extern int omfs_allocate_range(struct super_block *sb, int min_request, | ||
| 43 | int max_request, u64 *return_block, int *return_size); | ||
| 44 | extern int omfs_clear_range(struct super_block *sb, u64 block, int count); | ||
| 45 | |||
| 46 | /* dir.c */ | ||
| 47 | extern struct file_operations omfs_dir_operations; | ||
| 48 | extern struct inode_operations omfs_dir_inops; | ||
| 49 | extern int omfs_make_empty(struct inode *inode, struct super_block *sb); | ||
| 50 | extern int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, | ||
| 51 | u64 fsblock); | ||
| 52 | |||
| 53 | /* file.c */ | ||
| 54 | extern struct file_operations omfs_file_operations; | ||
| 55 | extern struct inode_operations omfs_file_inops; | ||
| 56 | extern struct address_space_operations omfs_aops; | ||
| 57 | extern void omfs_make_empty_table(struct buffer_head *bh, int offset); | ||
| 58 | extern int omfs_shrink_inode(struct inode *inode); | ||
| 59 | |||
| 60 | /* inode.c */ | ||
| 61 | extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); | ||
| 62 | extern struct inode *omfs_new_inode(struct inode *dir, int mode); | ||
| 63 | extern int omfs_reserve_block(struct super_block *sb, sector_t block); | ||
| 64 | extern int omfs_find_empty_block(struct super_block *sb, int mode, ino_t *ino); | ||
| 65 | extern int omfs_sync_inode(struct inode *inode); | ||
| 66 | |||
| 67 | #endif | ||
diff --git a/fs/omfs/omfs_fs.h b/fs/omfs/omfs_fs.h new file mode 100644 index 000000000000..12cca245d6e8 --- /dev/null +++ b/fs/omfs/omfs_fs.h | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | #ifndef _OMFS_FS_H | ||
| 2 | #define _OMFS_FS_H | ||
| 3 | |||
| 4 | /* OMFS On-disk structures */ | ||
| 5 | |||
| 6 | #define OMFS_MAGIC 0xC2993D87 | ||
| 7 | #define OMFS_IMAGIC 0xD2 | ||
| 8 | |||
| 9 | #define OMFS_DIR 'D' | ||
| 10 | #define OMFS_FILE 'F' | ||
| 11 | #define OMFS_INODE_NORMAL 'e' | ||
| 12 | #define OMFS_INODE_CONTINUATION 'c' | ||
| 13 | #define OMFS_INODE_SYSTEM 's' | ||
| 14 | #define OMFS_NAMELEN 256 | ||
| 15 | #define OMFS_DIR_START 0x1b8 | ||
| 16 | #define OMFS_EXTENT_START 0x1d0 | ||
| 17 | #define OMFS_EXTENT_CONT 0x40 | ||
| 18 | #define OMFS_XOR_COUNT 19 | ||
| 19 | #define OMFS_MAX_BLOCK_SIZE 8192 | ||
| 20 | |||
| 21 | struct omfs_super_block { | ||
| 22 | char s_fill1[256]; | ||
| 23 | __be64 s_root_block; /* block number of omfs_root_block */ | ||
| 24 | __be64 s_num_blocks; /* total number of FS blocks */ | ||
| 25 | __be32 s_magic; /* OMFS_MAGIC */ | ||
| 26 | __be32 s_blocksize; /* size of a block */ | ||
| 27 | __be32 s_mirrors; /* # of mirrors of system blocks */ | ||
| 28 | __be32 s_sys_blocksize; /* size of non-data blocks */ | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct omfs_header { | ||
| 32 | __be64 h_self; /* FS block where this is located */ | ||
| 33 | __be32 h_body_size; /* size of useful data after header */ | ||
| 34 | __be16 h_crc; /* crc-ccitt of body_size bytes */ | ||
| 35 | char h_fill1[2]; | ||
| 36 | u8 h_version; /* version, always 1 */ | ||
| 37 | char h_type; /* OMFS_INODE_X */ | ||
| 38 | u8 h_magic; /* OMFS_IMAGIC */ | ||
| 39 | u8 h_check_xor; /* XOR of header bytes before this */ | ||
| 40 | __be32 h_fill2; | ||
| 41 | }; | ||
| 42 | |||
| 43 | struct omfs_root_block { | ||
| 44 | struct omfs_header r_head; /* header */ | ||
| 45 | __be64 r_fill1; | ||
| 46 | __be64 r_num_blocks; /* total number of FS blocks */ | ||
| 47 | __be64 r_root_dir; /* block # of root directory */ | ||
| 48 | __be64 r_bitmap; /* block # of free space bitmap */ | ||
| 49 | __be32 r_blocksize; /* size of a block */ | ||
| 50 | __be32 r_clustersize; /* size allocated for data blocks */ | ||
| 51 | __be64 r_mirrors; /* # of mirrors of system blocks */ | ||
| 52 | char r_name[OMFS_NAMELEN]; /* partition label */ | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct omfs_inode { | ||
| 56 | struct omfs_header i_head; /* header */ | ||
| 57 | __be64 i_parent; /* parent containing this inode */ | ||
| 58 | __be64 i_sibling; /* next inode in hash bucket */ | ||
| 59 | __be64 i_ctime; /* ctime, in milliseconds */ | ||
| 60 | char i_fill1[35]; | ||
| 61 | char i_type; /* OMFS_[DIR,FILE] */ | ||
| 62 | __be32 i_fill2; | ||
| 63 | char i_fill3[64]; | ||
| 64 | char i_name[OMFS_NAMELEN]; /* filename */ | ||
| 65 | __be64 i_size; /* size of file, in bytes */ | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct omfs_extent_entry { | ||
| 69 | __be64 e_cluster; /* start location of a set of blocks */ | ||
| 70 | __be64 e_blocks; /* number of blocks after e_cluster */ | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct omfs_extent { | ||
| 74 | __be64 e_next; /* next extent table location */ | ||
| 75 | __be32 e_extent_count; /* total # extents in this table */ | ||
| 76 | __be32 e_fill; | ||
| 77 | struct omfs_extent_entry e_entry; /* start of extent entries */ | ||
| 78 | }; | ||
| 79 | |||
| 80 | #endif | ||
| @@ -122,37 +122,37 @@ static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) | |||
| 122 | return 0; | 122 | return 0; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) | 125 | asmlinkage long sys_statfs(const char __user *pathname, struct statfs __user * buf) |
| 126 | { | 126 | { |
| 127 | struct nameidata nd; | 127 | struct path path; |
| 128 | int error; | 128 | int error; |
| 129 | 129 | ||
| 130 | error = user_path_walk(path, &nd); | 130 | error = user_path(pathname, &path); |
| 131 | if (!error) { | 131 | if (!error) { |
| 132 | struct statfs tmp; | 132 | struct statfs tmp; |
| 133 | error = vfs_statfs_native(nd.path.dentry, &tmp); | 133 | error = vfs_statfs_native(path.dentry, &tmp); |
| 134 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 134 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
| 135 | error = -EFAULT; | 135 | error = -EFAULT; |
| 136 | path_put(&nd.path); | 136 | path_put(&path); |
| 137 | } | 137 | } |
| 138 | return error; | 138 | return error; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | 141 | ||
| 142 | asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf) | 142 | asmlinkage long sys_statfs64(const char __user *pathname, size_t sz, struct statfs64 __user *buf) |
| 143 | { | 143 | { |
| 144 | struct nameidata nd; | 144 | struct path path; |
| 145 | long error; | 145 | long error; |
| 146 | 146 | ||
| 147 | if (sz != sizeof(*buf)) | 147 | if (sz != sizeof(*buf)) |
| 148 | return -EINVAL; | 148 | return -EINVAL; |
| 149 | error = user_path_walk(path, &nd); | 149 | error = user_path(pathname, &path); |
| 150 | if (!error) { | 150 | if (!error) { |
| 151 | struct statfs64 tmp; | 151 | struct statfs64 tmp; |
| 152 | error = vfs_statfs64(nd.path.dentry, &tmp); | 152 | error = vfs_statfs64(path.dentry, &tmp); |
| 153 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 153 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
| 154 | error = -EFAULT; | 154 | error = -EFAULT; |
| 155 | path_put(&nd.path); | 155 | path_put(&path); |
| 156 | } | 156 | } |
| 157 | return error; | 157 | return error; |
| 158 | } | 158 | } |
| @@ -223,20 +223,20 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | |||
| 223 | return err; | 223 | return err; |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | static long do_sys_truncate(const char __user * path, loff_t length) | 226 | static long do_sys_truncate(const char __user *pathname, loff_t length) |
| 227 | { | 227 | { |
| 228 | struct nameidata nd; | 228 | struct path path; |
| 229 | struct inode * inode; | 229 | struct inode *inode; |
| 230 | int error; | 230 | int error; |
| 231 | 231 | ||
| 232 | error = -EINVAL; | 232 | error = -EINVAL; |
| 233 | if (length < 0) /* sorry, but loff_t says... */ | 233 | if (length < 0) /* sorry, but loff_t says... */ |
| 234 | goto out; | 234 | goto out; |
| 235 | 235 | ||
| 236 | error = user_path_walk(path, &nd); | 236 | error = user_path(pathname, &path); |
| 237 | if (error) | 237 | if (error) |
| 238 | goto out; | 238 | goto out; |
| 239 | inode = nd.path.dentry->d_inode; | 239 | inode = path.dentry->d_inode; |
| 240 | 240 | ||
| 241 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ | 241 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ |
| 242 | error = -EISDIR; | 242 | error = -EISDIR; |
| @@ -247,16 +247,16 @@ static long do_sys_truncate(const char __user * path, loff_t length) | |||
| 247 | if (!S_ISREG(inode->i_mode)) | 247 | if (!S_ISREG(inode->i_mode)) |
| 248 | goto dput_and_out; | 248 | goto dput_and_out; |
| 249 | 249 | ||
| 250 | error = mnt_want_write(nd.path.mnt); | 250 | error = mnt_want_write(path.mnt); |
| 251 | if (error) | 251 | if (error) |
| 252 | goto dput_and_out; | 252 | goto dput_and_out; |
| 253 | 253 | ||
| 254 | error = vfs_permission(&nd, MAY_WRITE); | 254 | error = inode_permission(inode, MAY_WRITE); |
| 255 | if (error) | 255 | if (error) |
| 256 | goto mnt_drop_write_and_out; | 256 | goto mnt_drop_write_and_out; |
| 257 | 257 | ||
| 258 | error = -EPERM; | 258 | error = -EPERM; |
| 259 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 259 | if (IS_APPEND(inode)) |
| 260 | goto mnt_drop_write_and_out; | 260 | goto mnt_drop_write_and_out; |
| 261 | 261 | ||
| 262 | error = get_write_access(inode); | 262 | error = get_write_access(inode); |
| @@ -274,15 +274,15 @@ static long do_sys_truncate(const char __user * path, loff_t length) | |||
| 274 | error = locks_verify_truncate(inode, NULL, length); | 274 | error = locks_verify_truncate(inode, NULL, length); |
| 275 | if (!error) { | 275 | if (!error) { |
| 276 | DQUOT_INIT(inode); | 276 | DQUOT_INIT(inode); |
| 277 | error = do_truncate(nd.path.dentry, length, 0, NULL); | 277 | error = do_truncate(path.dentry, length, 0, NULL); |
| 278 | } | 278 | } |
| 279 | 279 | ||
| 280 | put_write_and_out: | 280 | put_write_and_out: |
| 281 | put_write_access(inode); | 281 | put_write_access(inode); |
| 282 | mnt_drop_write_and_out: | 282 | mnt_drop_write_and_out: |
| 283 | mnt_drop_write(nd.path.mnt); | 283 | mnt_drop_write(path.mnt); |
| 284 | dput_and_out: | 284 | dput_and_out: |
| 285 | path_put(&nd.path); | 285 | path_put(&path); |
| 286 | out: | 286 | out: |
| 287 | return error; | 287 | return error; |
| 288 | } | 288 | } |
| @@ -425,7 +425,8 @@ out: | |||
| 425 | */ | 425 | */ |
| 426 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | 426 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) |
| 427 | { | 427 | { |
| 428 | struct nameidata nd; | 428 | struct path path; |
| 429 | struct inode *inode; | ||
| 429 | int old_fsuid, old_fsgid; | 430 | int old_fsuid, old_fsgid; |
| 430 | kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */ | 431 | kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */ |
| 431 | int res; | 432 | int res; |
| @@ -448,7 +449,7 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
| 448 | * FIXME: There is a race here against sys_capset. The | 449 | * FIXME: There is a race here against sys_capset. The |
| 449 | * capabilities can change yet we will restore the old | 450 | * capabilities can change yet we will restore the old |
| 450 | * value below. We should hold task_capabilities_lock, | 451 | * value below. We should hold task_capabilities_lock, |
| 451 | * but we cannot because user_path_walk can sleep. | 452 | * but we cannot because user_path_at can sleep. |
| 452 | */ | 453 | */ |
| 453 | #endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */ | 454 | #endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */ |
| 454 | if (current->uid) | 455 | if (current->uid) |
| @@ -457,14 +458,25 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
| 457 | old_cap = cap_set_effective(current->cap_permitted); | 458 | old_cap = cap_set_effective(current->cap_permitted); |
| 458 | } | 459 | } |
| 459 | 460 | ||
| 460 | res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); | 461 | res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); |
| 461 | if (res) | 462 | if (res) |
| 462 | goto out; | 463 | goto out; |
| 463 | 464 | ||
| 464 | res = vfs_permission(&nd, mode); | 465 | inode = path.dentry->d_inode; |
| 466 | |||
| 467 | if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { | ||
| 468 | /* | ||
| 469 | * MAY_EXEC on regular files is denied if the fs is mounted | ||
| 470 | * with the "noexec" flag. | ||
| 471 | */ | ||
| 472 | res = -EACCES; | ||
| 473 | if (path.mnt->mnt_flags & MNT_NOEXEC) | ||
| 474 | goto out_path_release; | ||
| 475 | } | ||
| 476 | |||
| 477 | res = inode_permission(inode, mode | MAY_ACCESS); | ||
| 465 | /* SuS v2 requires we report a read only fs too */ | 478 | /* SuS v2 requires we report a read only fs too */ |
| 466 | if(res || !(mode & S_IWOTH) || | 479 | if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) |
| 467 | special_file(nd.path.dentry->d_inode->i_mode)) | ||
| 468 | goto out_path_release; | 480 | goto out_path_release; |
| 469 | /* | 481 | /* |
| 470 | * This is a rare case where using __mnt_is_readonly() | 482 | * This is a rare case where using __mnt_is_readonly() |
| @@ -476,11 +488,11 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
| 476 | * inherently racy and know that the fs may change | 488 | * inherently racy and know that the fs may change |
| 477 | * state before we even see this result. | 489 | * state before we even see this result. |
| 478 | */ | 490 | */ |
| 479 | if (__mnt_is_readonly(nd.path.mnt)) | 491 | if (__mnt_is_readonly(path.mnt)) |
| 480 | res = -EROFS; | 492 | res = -EROFS; |
| 481 | 493 | ||
| 482 | out_path_release: | 494 | out_path_release: |
| 483 | path_put(&nd.path); | 495 | path_put(&path); |
| 484 | out: | 496 | out: |
| 485 | current->fsuid = old_fsuid; | 497 | current->fsuid = old_fsuid; |
| 486 | current->fsgid = old_fsgid; | 498 | current->fsgid = old_fsgid; |
| @@ -498,22 +510,21 @@ asmlinkage long sys_access(const char __user *filename, int mode) | |||
| 498 | 510 | ||
| 499 | asmlinkage long sys_chdir(const char __user * filename) | 511 | asmlinkage long sys_chdir(const char __user * filename) |
| 500 | { | 512 | { |
| 501 | struct nameidata nd; | 513 | struct path path; |
| 502 | int error; | 514 | int error; |
| 503 | 515 | ||
| 504 | error = __user_walk(filename, | 516 | error = user_path_dir(filename, &path); |
| 505 | LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd); | ||
| 506 | if (error) | 517 | if (error) |
| 507 | goto out; | 518 | goto out; |
| 508 | 519 | ||
| 509 | error = vfs_permission(&nd, MAY_EXEC); | 520 | error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); |
| 510 | if (error) | 521 | if (error) |
| 511 | goto dput_and_out; | 522 | goto dput_and_out; |
| 512 | 523 | ||
| 513 | set_fs_pwd(current->fs, &nd.path); | 524 | set_fs_pwd(current->fs, &path); |
| 514 | 525 | ||
| 515 | dput_and_out: | 526 | dput_and_out: |
| 516 | path_put(&nd.path); | 527 | path_put(&path); |
| 517 | out: | 528 | out: |
| 518 | return error; | 529 | return error; |
| 519 | } | 530 | } |
| @@ -535,7 +546,7 @@ asmlinkage long sys_fchdir(unsigned int fd) | |||
| 535 | if (!S_ISDIR(inode->i_mode)) | 546 | if (!S_ISDIR(inode->i_mode)) |
| 536 | goto out_putf; | 547 | goto out_putf; |
| 537 | 548 | ||
| 538 | error = file_permission(file, MAY_EXEC); | 549 | error = inode_permission(inode, MAY_EXEC | MAY_ACCESS); |
| 539 | if (!error) | 550 | if (!error) |
| 540 | set_fs_pwd(current->fs, &file->f_path); | 551 | set_fs_pwd(current->fs, &file->f_path); |
| 541 | out_putf: | 552 | out_putf: |
| @@ -546,14 +557,14 @@ out: | |||
| 546 | 557 | ||
| 547 | asmlinkage long sys_chroot(const char __user * filename) | 558 | asmlinkage long sys_chroot(const char __user * filename) |
| 548 | { | 559 | { |
| 549 | struct nameidata nd; | 560 | struct path path; |
| 550 | int error; | 561 | int error; |
| 551 | 562 | ||
| 552 | error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd); | 563 | error = user_path_dir(filename, &path); |
| 553 | if (error) | 564 | if (error) |
| 554 | goto out; | 565 | goto out; |
| 555 | 566 | ||
| 556 | error = vfs_permission(&nd, MAY_EXEC); | 567 | error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); |
| 557 | if (error) | 568 | if (error) |
| 558 | goto dput_and_out; | 569 | goto dput_and_out; |
| 559 | 570 | ||
| @@ -561,11 +572,10 @@ asmlinkage long sys_chroot(const char __user * filename) | |||
| 561 | if (!capable(CAP_SYS_CHROOT)) | 572 | if (!capable(CAP_SYS_CHROOT)) |
| 562 | goto dput_and_out; | 573 | goto dput_and_out; |
| 563 | 574 | ||
| 564 | set_fs_root(current->fs, &nd.path); | 575 | set_fs_root(current->fs, &path); |
| 565 | set_fs_altroot(); | ||
| 566 | error = 0; | 576 | error = 0; |
| 567 | dput_and_out: | 577 | dput_and_out: |
| 568 | path_put(&nd.path); | 578 | path_put(&path); |
| 569 | out: | 579 | out: |
| 570 | return error; | 580 | return error; |
| 571 | } | 581 | } |
| @@ -590,9 +600,6 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) | |||
| 590 | err = mnt_want_write(file->f_path.mnt); | 600 | err = mnt_want_write(file->f_path.mnt); |
| 591 | if (err) | 601 | if (err) |
| 592 | goto out_putf; | 602 | goto out_putf; |
| 593 | err = -EPERM; | ||
| 594 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
| 595 | goto out_drop_write; | ||
| 596 | mutex_lock(&inode->i_mutex); | 603 | mutex_lock(&inode->i_mutex); |
| 597 | if (mode == (mode_t) -1) | 604 | if (mode == (mode_t) -1) |
| 598 | mode = inode->i_mode; | 605 | mode = inode->i_mode; |
| @@ -600,8 +607,6 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) | |||
| 600 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 607 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
| 601 | err = notify_change(dentry, &newattrs); | 608 | err = notify_change(dentry, &newattrs); |
| 602 | mutex_unlock(&inode->i_mutex); | 609 | mutex_unlock(&inode->i_mutex); |
| 603 | |||
| 604 | out_drop_write: | ||
| 605 | mnt_drop_write(file->f_path.mnt); | 610 | mnt_drop_write(file->f_path.mnt); |
| 606 | out_putf: | 611 | out_putf: |
| 607 | fput(file); | 612 | fput(file); |
| @@ -612,36 +617,29 @@ out: | |||
| 612 | asmlinkage long sys_fchmodat(int dfd, const char __user *filename, | 617 | asmlinkage long sys_fchmodat(int dfd, const char __user *filename, |
| 613 | mode_t mode) | 618 | mode_t mode) |
| 614 | { | 619 | { |
| 615 | struct nameidata nd; | 620 | struct path path; |
| 616 | struct inode * inode; | 621 | struct inode *inode; |
| 617 | int error; | 622 | int error; |
| 618 | struct iattr newattrs; | 623 | struct iattr newattrs; |
| 619 | 624 | ||
| 620 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); | 625 | error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); |
| 621 | if (error) | 626 | if (error) |
| 622 | goto out; | 627 | goto out; |
| 623 | inode = nd.path.dentry->d_inode; | 628 | inode = path.dentry->d_inode; |
| 624 | 629 | ||
| 625 | error = mnt_want_write(nd.path.mnt); | 630 | error = mnt_want_write(path.mnt); |
| 626 | if (error) | 631 | if (error) |
| 627 | goto dput_and_out; | 632 | goto dput_and_out; |
| 628 | |||
| 629 | error = -EPERM; | ||
| 630 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
| 631 | goto out_drop_write; | ||
| 632 | |||
| 633 | mutex_lock(&inode->i_mutex); | 633 | mutex_lock(&inode->i_mutex); |
| 634 | if (mode == (mode_t) -1) | 634 | if (mode == (mode_t) -1) |
| 635 | mode = inode->i_mode; | 635 | mode = inode->i_mode; |
| 636 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); | 636 | newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); |
| 637 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; | 637 | newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; |
| 638 | error = notify_change(nd.path.dentry, &newattrs); | 638 | error = notify_change(path.dentry, &newattrs); |
| 639 | mutex_unlock(&inode->i_mutex); | 639 | mutex_unlock(&inode->i_mutex); |
| 640 | 640 | mnt_drop_write(path.mnt); | |
| 641 | out_drop_write: | ||
| 642 | mnt_drop_write(nd.path.mnt); | ||
| 643 | dput_and_out: | 641 | dput_and_out: |
| 644 | path_put(&nd.path); | 642 | path_put(&path); |
| 645 | out: | 643 | out: |
| 646 | return error; | 644 | return error; |
| 647 | } | 645 | } |
| @@ -653,18 +651,10 @@ asmlinkage long sys_chmod(const char __user *filename, mode_t mode) | |||
| 653 | 651 | ||
| 654 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | 652 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) |
| 655 | { | 653 | { |
| 656 | struct inode * inode; | 654 | struct inode *inode = dentry->d_inode; |
| 657 | int error; | 655 | int error; |
| 658 | struct iattr newattrs; | 656 | struct iattr newattrs; |
| 659 | 657 | ||
| 660 | error = -ENOENT; | ||
| 661 | if (!(inode = dentry->d_inode)) { | ||
| 662 | printk(KERN_ERR "chown_common: NULL inode\n"); | ||
| 663 | goto out; | ||
| 664 | } | ||
| 665 | error = -EPERM; | ||
| 666 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
| 667 | goto out; | ||
| 668 | newattrs.ia_valid = ATTR_CTIME; | 658 | newattrs.ia_valid = ATTR_CTIME; |
| 669 | if (user != (uid_t) -1) { | 659 | if (user != (uid_t) -1) { |
| 670 | newattrs.ia_valid |= ATTR_UID; | 660 | newattrs.ia_valid |= ATTR_UID; |
| @@ -680,25 +670,25 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | |||
| 680 | mutex_lock(&inode->i_mutex); | 670 | mutex_lock(&inode->i_mutex); |
| 681 | error = notify_change(dentry, &newattrs); | 671 | error = notify_change(dentry, &newattrs); |
| 682 | mutex_unlock(&inode->i_mutex); | 672 | mutex_unlock(&inode->i_mutex); |
| 683 | out: | 673 | |
| 684 | return error; | 674 | return error; |
| 685 | } | 675 | } |
| 686 | 676 | ||
| 687 | asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) | 677 | asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) |
| 688 | { | 678 | { |
| 689 | struct nameidata nd; | 679 | struct path path; |
| 690 | int error; | 680 | int error; |
| 691 | 681 | ||
| 692 | error = user_path_walk(filename, &nd); | 682 | error = user_path(filename, &path); |
| 693 | if (error) | 683 | if (error) |
| 694 | goto out; | 684 | goto out; |
| 695 | error = mnt_want_write(nd.path.mnt); | 685 | error = mnt_want_write(path.mnt); |
| 696 | if (error) | 686 | if (error) |
| 697 | goto out_release; | 687 | goto out_release; |
| 698 | error = chown_common(nd.path.dentry, user, group); | 688 | error = chown_common(path.dentry, user, group); |
| 699 | mnt_drop_write(nd.path.mnt); | 689 | mnt_drop_write(path.mnt); |
| 700 | out_release: | 690 | out_release: |
| 701 | path_put(&nd.path); | 691 | path_put(&path); |
| 702 | out: | 692 | out: |
| 703 | return error; | 693 | return error; |
| 704 | } | 694 | } |
| @@ -706,7 +696,7 @@ out: | |||
| 706 | asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, | 696 | asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, |
| 707 | gid_t group, int flag) | 697 | gid_t group, int flag) |
| 708 | { | 698 | { |
| 709 | struct nameidata nd; | 699 | struct path path; |
| 710 | int error = -EINVAL; | 700 | int error = -EINVAL; |
| 711 | int follow; | 701 | int follow; |
| 712 | 702 | ||
| @@ -714,35 +704,35 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, | |||
| 714 | goto out; | 704 | goto out; |
| 715 | 705 | ||
| 716 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; | 706 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; |
| 717 | error = __user_walk_fd(dfd, filename, follow, &nd); | 707 | error = user_path_at(dfd, filename, follow, &path); |
| 718 | if (error) | 708 | if (error) |
| 719 | goto out; | 709 | goto out; |
| 720 | error = mnt_want_write(nd.path.mnt); | 710 | error = mnt_want_write(path.mnt); |
| 721 | if (error) | 711 | if (error) |
| 722 | goto out_release; | 712 | goto out_release; |
| 723 | error = chown_common(nd.path.dentry, user, group); | 713 | error = chown_common(path.dentry, user, group); |
| 724 | mnt_drop_write(nd.path.mnt); | 714 | mnt_drop_write(path.mnt); |
| 725 | out_release: | 715 | out_release: |
| 726 | path_put(&nd.path); | 716 | path_put(&path); |
| 727 | out: | 717 | out: |
| 728 | return error; | 718 | return error; |
| 729 | } | 719 | } |
| 730 | 720 | ||
| 731 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) | 721 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) |
| 732 | { | 722 | { |
| 733 | struct nameidata nd; | 723 | struct path path; |
| 734 | int error; | 724 | int error; |
| 735 | 725 | ||
| 736 | error = user_path_walk_link(filename, &nd); | 726 | error = user_lpath(filename, &path); |
| 737 | if (error) | 727 | if (error) |
| 738 | goto out; | 728 | goto out; |
| 739 | error = mnt_want_write(nd.path.mnt); | 729 | error = mnt_want_write(path.mnt); |
| 740 | if (error) | 730 | if (error) |
| 741 | goto out_release; | 731 | goto out_release; |
| 742 | error = chown_common(nd.path.dentry, user, group); | 732 | error = chown_common(path.dentry, user, group); |
| 743 | mnt_drop_write(nd.path.mnt); | 733 | mnt_drop_write(path.mnt); |
| 744 | out_release: | 734 | out_release: |
| 745 | path_put(&nd.path); | 735 | path_put(&path); |
| 746 | out: | 736 | out: |
| 747 | return error; | 737 | return error; |
| 748 | } | 738 | } |
| @@ -973,71 +963,6 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
| 973 | } | 963 | } |
| 974 | EXPORT_SYMBOL(dentry_open); | 964 | EXPORT_SYMBOL(dentry_open); |
| 975 | 965 | ||
| 976 | /* | ||
| 977 | * Find an empty file descriptor entry, and mark it busy. | ||
| 978 | */ | ||
| 979 | int get_unused_fd_flags(int flags) | ||
| 980 | { | ||
| 981 | struct files_struct * files = current->files; | ||
| 982 | int fd, error; | ||
| 983 | struct fdtable *fdt; | ||
| 984 | |||
| 985 | error = -EMFILE; | ||
| 986 | spin_lock(&files->file_lock); | ||
| 987 | |||
| 988 | repeat: | ||
| 989 | fdt = files_fdtable(files); | ||
| 990 | fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds, | ||
| 991 | files->next_fd); | ||
| 992 | |||
| 993 | /* | ||
| 994 | * N.B. For clone tasks sharing a files structure, this test | ||
| 995 | * will limit the total number of files that can be opened. | ||
| 996 | */ | ||
| 997 | if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) | ||
| 998 | goto out; | ||
| 999 | |||
| 1000 | /* Do we need to expand the fd array or fd set? */ | ||
| 1001 | error = expand_files(files, fd); | ||
| 1002 | if (error < 0) | ||
| 1003 | goto out; | ||
| 1004 | |||
| 1005 | if (error) { | ||
| 1006 | /* | ||
| 1007 | * If we needed to expand the fs array we | ||
| 1008 | * might have blocked - try again. | ||
| 1009 | */ | ||
| 1010 | error = -EMFILE; | ||
| 1011 | goto repeat; | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | FD_SET(fd, fdt->open_fds); | ||
| 1015 | if (flags & O_CLOEXEC) | ||
| 1016 | FD_SET(fd, fdt->close_on_exec); | ||
| 1017 | else | ||
| 1018 | FD_CLR(fd, fdt->close_on_exec); | ||
| 1019 | files->next_fd = fd + 1; | ||
| 1020 | #if 1 | ||
| 1021 | /* Sanity check */ | ||
| 1022 | if (fdt->fd[fd] != NULL) { | ||
| 1023 | printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd); | ||
| 1024 | fdt->fd[fd] = NULL; | ||
| 1025 | } | ||
| 1026 | #endif | ||
| 1027 | error = fd; | ||
| 1028 | |||
| 1029 | out: | ||
| 1030 | spin_unlock(&files->file_lock); | ||
| 1031 | return error; | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | int get_unused_fd(void) | ||
| 1035 | { | ||
| 1036 | return get_unused_fd_flags(0); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | EXPORT_SYMBOL(get_unused_fd); | ||
| 1040 | |||
| 1041 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) | 966 | static void __put_unused_fd(struct files_struct *files, unsigned int fd) |
| 1042 | { | 967 | { |
| 1043 | struct fdtable *fdt = files_fdtable(files); | 968 | struct fdtable *fdt = files_fdtable(files); |
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index d17b4fd204e1..9f5b054f06b9 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c | |||
| @@ -430,7 +430,7 @@ static struct file_system_type openprom_fs_type = { | |||
| 430 | .kill_sb = kill_anon_super, | 430 | .kill_sb = kill_anon_super, |
| 431 | }; | 431 | }; |
| 432 | 432 | ||
| 433 | static void op_inode_init_once(struct kmem_cache * cachep, void *data) | 433 | static void op_inode_init_once(void *data) |
| 434 | { | 434 | { |
| 435 | struct op_inode_info *oi = (struct op_inode_info *) data; | 435 | struct op_inode_info *oi = (struct op_inode_info *) data; |
| 436 | 436 | ||
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index efef715135d3..ecc3330972e5 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -344,18 +344,18 @@ static ssize_t whole_disk_show(struct device *dev, | |||
| 344 | static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, | 344 | static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, |
| 345 | whole_disk_show, NULL); | 345 | whole_disk_show, NULL); |
| 346 | 346 | ||
| 347 | void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) | 347 | int add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) |
| 348 | { | 348 | { |
| 349 | struct hd_struct *p; | 349 | struct hd_struct *p; |
| 350 | int err; | 350 | int err; |
| 351 | 351 | ||
| 352 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 352 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 353 | if (!p) | 353 | if (!p) |
| 354 | return; | 354 | return -ENOMEM; |
| 355 | 355 | ||
| 356 | if (!init_part_stats(p)) { | 356 | if (!init_part_stats(p)) { |
| 357 | kfree(p); | 357 | err = -ENOMEM; |
| 358 | return; | 358 | goto out0; |
| 359 | } | 359 | } |
| 360 | p->start_sect = start; | 360 | p->start_sect = start; |
| 361 | p->nr_sects = len; | 361 | p->nr_sects = len; |
| @@ -378,15 +378,31 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, | |||
| 378 | 378 | ||
| 379 | /* delay uevent until 'holders' subdir is created */ | 379 | /* delay uevent until 'holders' subdir is created */ |
| 380 | p->dev.uevent_suppress = 1; | 380 | p->dev.uevent_suppress = 1; |
| 381 | device_add(&p->dev); | 381 | err = device_add(&p->dev); |
| 382 | if (err) | ||
| 383 | goto out1; | ||
| 382 | partition_sysfs_add_subdir(p); | 384 | partition_sysfs_add_subdir(p); |
| 383 | p->dev.uevent_suppress = 0; | 385 | p->dev.uevent_suppress = 0; |
| 384 | if (flags & ADDPART_FLAG_WHOLEDISK) | 386 | if (flags & ADDPART_FLAG_WHOLEDISK) { |
| 385 | err = device_create_file(&p->dev, &dev_attr_whole_disk); | 387 | err = device_create_file(&p->dev, &dev_attr_whole_disk); |
| 388 | if (err) | ||
| 389 | goto out2; | ||
| 390 | } | ||
| 386 | 391 | ||
| 387 | /* suppress uevent if the disk supresses it */ | 392 | /* suppress uevent if the disk supresses it */ |
| 388 | if (!disk->dev.uevent_suppress) | 393 | if (!disk->dev.uevent_suppress) |
| 389 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); | 394 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); |
| 395 | |||
| 396 | return 0; | ||
| 397 | |||
| 398 | out2: | ||
| 399 | device_del(&p->dev); | ||
| 400 | out1: | ||
| 401 | put_device(&p->dev); | ||
| 402 | free_part_stats(p); | ||
| 403 | out0: | ||
| 404 | kfree(p); | ||
| 405 | return err; | ||
| 390 | } | 406 | } |
| 391 | 407 | ||
| 392 | /* Not exported, helper to add_disk(). */ | 408 | /* Not exported, helper to add_disk(). */ |
| @@ -483,10 +499,16 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | |||
| 483 | if (!size) | 499 | if (!size) |
| 484 | continue; | 500 | continue; |
| 485 | if (from + size > get_capacity(disk)) { | 501 | if (from + size > get_capacity(disk)) { |
| 486 | printk(" %s: p%d exceeds device capacity\n", | 502 | printk(KERN_WARNING |
| 503 | "%s: p%d exceeds device capacity\n", | ||
| 487 | disk->disk_name, p); | 504 | disk->disk_name, p); |
| 488 | } | 505 | } |
| 489 | add_partition(disk, p, from, size, state->parts[p].flags); | 506 | res = add_partition(disk, p, from, size, state->parts[p].flags); |
| 507 | if (res) { | ||
| 508 | printk(KERN_ERR " %s: p%d could not be added: %d\n", | ||
| 509 | disk->disk_name, p, -res); | ||
| 510 | continue; | ||
| 511 | } | ||
| 490 | #ifdef CONFIG_BLK_DEV_MD | 512 | #ifdef CONFIG_BLK_DEV_MD |
| 491 | if (state->parts[p].flags & ADDPART_FLAG_RAID) | 513 | if (state->parts[p].flags & ADDPART_FLAG_RAID) |
| 492 | md_autodetect_dev(bdev->bd_dev+p); | 514 | md_autodetect_dev(bdev->bd_dev+p); |
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index e7b07006bc41..038a6022152f 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c | |||
| @@ -95,13 +95,6 @@ | |||
| 95 | #include "check.h" | 95 | #include "check.h" |
| 96 | #include "efi.h" | 96 | #include "efi.h" |
| 97 | 97 | ||
| 98 | #undef EFI_DEBUG | ||
| 99 | #ifdef EFI_DEBUG | ||
| 100 | #define Dprintk(x...) printk(KERN_DEBUG x) | ||
| 101 | #else | ||
| 102 | #define Dprintk(x...) | ||
| 103 | #endif | ||
| 104 | |||
| 105 | /* This allows a kernel command line option 'gpt' to override | 98 | /* This allows a kernel command line option 'gpt' to override |
| 106 | * the test for invalid PMBR. Not __initdata because reloading | 99 | * the test for invalid PMBR. Not __initdata because reloading |
| 107 | * the partition tables happens after init too. | 100 | * the partition tables happens after init too. |
| @@ -305,10 +298,10 @@ is_gpt_valid(struct block_device *bdev, u64 lba, | |||
| 305 | 298 | ||
| 306 | /* Check the GUID Partition Table signature */ | 299 | /* Check the GUID Partition Table signature */ |
| 307 | if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { | 300 | if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { |
| 308 | Dprintk("GUID Partition Table Header signature is wrong:" | 301 | pr_debug("GUID Partition Table Header signature is wrong:" |
| 309 | "%lld != %lld\n", | 302 | "%lld != %lld\n", |
| 310 | (unsigned long long)le64_to_cpu((*gpt)->signature), | 303 | (unsigned long long)le64_to_cpu((*gpt)->signature), |
| 311 | (unsigned long long)GPT_HEADER_SIGNATURE); | 304 | (unsigned long long)GPT_HEADER_SIGNATURE); |
| 312 | goto fail; | 305 | goto fail; |
| 313 | } | 306 | } |
| 314 | 307 | ||
| @@ -318,9 +311,8 @@ is_gpt_valid(struct block_device *bdev, u64 lba, | |||
| 318 | crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); | 311 | crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); |
| 319 | 312 | ||
| 320 | if (crc != origcrc) { | 313 | if (crc != origcrc) { |
| 321 | Dprintk | 314 | pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n", |
| 322 | ("GUID Partition Table Header CRC is wrong: %x != %x\n", | 315 | crc, origcrc); |
| 323 | crc, origcrc); | ||
| 324 | goto fail; | 316 | goto fail; |
| 325 | } | 317 | } |
| 326 | (*gpt)->header_crc32 = cpu_to_le32(origcrc); | 318 | (*gpt)->header_crc32 = cpu_to_le32(origcrc); |
| @@ -328,9 +320,9 @@ is_gpt_valid(struct block_device *bdev, u64 lba, | |||
| 328 | /* Check that the my_lba entry points to the LBA that contains | 320 | /* Check that the my_lba entry points to the LBA that contains |
| 329 | * the GUID Partition Table */ | 321 | * the GUID Partition Table */ |
| 330 | if (le64_to_cpu((*gpt)->my_lba) != lba) { | 322 | if (le64_to_cpu((*gpt)->my_lba) != lba) { |
| 331 | Dprintk("GPT my_lba incorrect: %lld != %lld\n", | 323 | pr_debug("GPT my_lba incorrect: %lld != %lld\n", |
| 332 | (unsigned long long)le64_to_cpu((*gpt)->my_lba), | 324 | (unsigned long long)le64_to_cpu((*gpt)->my_lba), |
| 333 | (unsigned long long)lba); | 325 | (unsigned long long)lba); |
| 334 | goto fail; | 326 | goto fail; |
| 335 | } | 327 | } |
| 336 | 328 | ||
| @@ -339,15 +331,15 @@ is_gpt_valid(struct block_device *bdev, u64 lba, | |||
| 339 | */ | 331 | */ |
| 340 | lastlba = last_lba(bdev); | 332 | lastlba = last_lba(bdev); |
| 341 | if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { | 333 | if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { |
| 342 | Dprintk("GPT: first_usable_lba incorrect: %lld > %lld\n", | 334 | pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n", |
| 343 | (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), | 335 | (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), |
| 344 | (unsigned long long)lastlba); | 336 | (unsigned long long)lastlba); |
| 345 | goto fail; | 337 | goto fail; |
| 346 | } | 338 | } |
| 347 | if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { | 339 | if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { |
| 348 | Dprintk("GPT: last_usable_lba incorrect: %lld > %lld\n", | 340 | pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", |
| 349 | (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), | 341 | (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), |
| 350 | (unsigned long long)lastlba); | 342 | (unsigned long long)lastlba); |
| 351 | goto fail; | 343 | goto fail; |
| 352 | } | 344 | } |
| 353 | 345 | ||
| @@ -360,7 +352,7 @@ is_gpt_valid(struct block_device *bdev, u64 lba, | |||
| 360 | le32_to_cpu((*gpt)->sizeof_partition_entry)); | 352 | le32_to_cpu((*gpt)->sizeof_partition_entry)); |
| 361 | 353 | ||
| 362 | if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { | 354 | if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { |
| 363 | Dprintk("GUID Partitition Entry Array CRC check failed.\n"); | 355 | pr_debug("GUID Partitition Entry Array CRC check failed.\n"); |
| 364 | goto fail_ptes; | 356 | goto fail_ptes; |
| 365 | } | 357 | } |
| 366 | 358 | ||
| @@ -616,7 +608,7 @@ efi_partition(struct parsed_partitions *state, struct block_device *bdev) | |||
| 616 | return 0; | 608 | return 0; |
| 617 | } | 609 | } |
| 618 | 610 | ||
| 619 | Dprintk("GUID Partition Table is valid! Yea!\n"); | 611 | pr_debug("GUID Partition Table is valid! Yea!\n"); |
| 620 | 612 | ||
| 621 | for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { | 613 | for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { |
| 622 | if (!is_pte_valid(&ptes[i], last_lba(bdev))) | 614 | if (!is_pte_valid(&ptes[i], last_lba(bdev))) |
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 0fdda2e8a4cc..8652fb99e962 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c | |||
| @@ -133,17 +133,17 @@ static bool ldm_parse_privhead(const u8 *data, struct privhead *ph) | |||
| 133 | bool is_vista = false; | 133 | bool is_vista = false; |
| 134 | 134 | ||
| 135 | BUG_ON(!data || !ph); | 135 | BUG_ON(!data || !ph); |
| 136 | if (MAGIC_PRIVHEAD != BE64(data)) { | 136 | if (MAGIC_PRIVHEAD != get_unaligned_be64(data)) { |
| 137 | ldm_error("Cannot find PRIVHEAD structure. LDM database is" | 137 | ldm_error("Cannot find PRIVHEAD structure. LDM database is" |
| 138 | " corrupt. Aborting."); | 138 | " corrupt. Aborting."); |
| 139 | return false; | 139 | return false; |
| 140 | } | 140 | } |
| 141 | ph->ver_major = BE16(data + 0x000C); | 141 | ph->ver_major = get_unaligned_be16(data + 0x000C); |
| 142 | ph->ver_minor = BE16(data + 0x000E); | 142 | ph->ver_minor = get_unaligned_be16(data + 0x000E); |
| 143 | ph->logical_disk_start = BE64(data + 0x011B); | 143 | ph->logical_disk_start = get_unaligned_be64(data + 0x011B); |
| 144 | ph->logical_disk_size = BE64(data + 0x0123); | 144 | ph->logical_disk_size = get_unaligned_be64(data + 0x0123); |
| 145 | ph->config_start = BE64(data + 0x012B); | 145 | ph->config_start = get_unaligned_be64(data + 0x012B); |
| 146 | ph->config_size = BE64(data + 0x0133); | 146 | ph->config_size = get_unaligned_be64(data + 0x0133); |
| 147 | /* Version 2.11 is Win2k/XP and version 2.12 is Vista. */ | 147 | /* Version 2.11 is Win2k/XP and version 2.12 is Vista. */ |
| 148 | if (ph->ver_major == 2 && ph->ver_minor == 12) | 148 | if (ph->ver_major == 2 && ph->ver_minor == 12) |
| 149 | is_vista = true; | 149 | is_vista = true; |
| @@ -191,14 +191,14 @@ static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc) | |||
| 191 | { | 191 | { |
| 192 | BUG_ON (!data || !toc); | 192 | BUG_ON (!data || !toc); |
| 193 | 193 | ||
| 194 | if (MAGIC_TOCBLOCK != BE64 (data)) { | 194 | if (MAGIC_TOCBLOCK != get_unaligned_be64(data)) { |
| 195 | ldm_crit ("Cannot find TOCBLOCK, database may be corrupt."); | 195 | ldm_crit ("Cannot find TOCBLOCK, database may be corrupt."); |
| 196 | return false; | 196 | return false; |
| 197 | } | 197 | } |
| 198 | strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name)); | 198 | strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name)); |
| 199 | toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0; | 199 | toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0; |
| 200 | toc->bitmap1_start = BE64 (data + 0x2E); | 200 | toc->bitmap1_start = get_unaligned_be64(data + 0x2E); |
| 201 | toc->bitmap1_size = BE64 (data + 0x36); | 201 | toc->bitmap1_size = get_unaligned_be64(data + 0x36); |
| 202 | 202 | ||
| 203 | if (strncmp (toc->bitmap1_name, TOC_BITMAP1, | 203 | if (strncmp (toc->bitmap1_name, TOC_BITMAP1, |
| 204 | sizeof (toc->bitmap1_name)) != 0) { | 204 | sizeof (toc->bitmap1_name)) != 0) { |
| @@ -208,8 +208,8 @@ static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc) | |||
| 208 | } | 208 | } |
| 209 | strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name)); | 209 | strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name)); |
| 210 | toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0; | 210 | toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0; |
| 211 | toc->bitmap2_start = BE64 (data + 0x50); | 211 | toc->bitmap2_start = get_unaligned_be64(data + 0x50); |
| 212 | toc->bitmap2_size = BE64 (data + 0x58); | 212 | toc->bitmap2_size = get_unaligned_be64(data + 0x58); |
| 213 | if (strncmp (toc->bitmap2_name, TOC_BITMAP2, | 213 | if (strncmp (toc->bitmap2_name, TOC_BITMAP2, |
| 214 | sizeof (toc->bitmap2_name)) != 0) { | 214 | sizeof (toc->bitmap2_name)) != 0) { |
| 215 | ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.", | 215 | ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.", |
| @@ -237,22 +237,22 @@ static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm) | |||
| 237 | { | 237 | { |
| 238 | BUG_ON (!data || !vm); | 238 | BUG_ON (!data || !vm); |
| 239 | 239 | ||
| 240 | if (MAGIC_VMDB != BE32 (data)) { | 240 | if (MAGIC_VMDB != get_unaligned_be32(data)) { |
| 241 | ldm_crit ("Cannot find the VMDB, database may be corrupt."); | 241 | ldm_crit ("Cannot find the VMDB, database may be corrupt."); |
| 242 | return false; | 242 | return false; |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | vm->ver_major = BE16 (data + 0x12); | 245 | vm->ver_major = get_unaligned_be16(data + 0x12); |
| 246 | vm->ver_minor = BE16 (data + 0x14); | 246 | vm->ver_minor = get_unaligned_be16(data + 0x14); |
| 247 | if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { | 247 | if ((vm->ver_major != 4) || (vm->ver_minor != 10)) { |
| 248 | ldm_error ("Expected VMDB version %d.%d, got %d.%d. " | 248 | ldm_error ("Expected VMDB version %d.%d, got %d.%d. " |
| 249 | "Aborting.", 4, 10, vm->ver_major, vm->ver_minor); | 249 | "Aborting.", 4, 10, vm->ver_major, vm->ver_minor); |
| 250 | return false; | 250 | return false; |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | vm->vblk_size = BE32 (data + 0x08); | 253 | vm->vblk_size = get_unaligned_be32(data + 0x08); |
| 254 | vm->vblk_offset = BE32 (data + 0x0C); | 254 | vm->vblk_offset = get_unaligned_be32(data + 0x0C); |
| 255 | vm->last_vblk_seq = BE32 (data + 0x04); | 255 | vm->last_vblk_seq = get_unaligned_be32(data + 0x04); |
| 256 | 256 | ||
| 257 | ldm_debug ("Parsed VMDB successfully."); | 257 | ldm_debug ("Parsed VMDB successfully."); |
| 258 | return true; | 258 | return true; |
| @@ -507,7 +507,7 @@ static bool ldm_validate_vmdb (struct block_device *bdev, unsigned long base, | |||
| 507 | goto out; /* Already logged */ | 507 | goto out; /* Already logged */ |
| 508 | 508 | ||
| 509 | /* Are there uncommitted transactions? */ | 509 | /* Are there uncommitted transactions? */ |
| 510 | if (BE16(data + 0x10) != 0x01) { | 510 | if (get_unaligned_be16(data + 0x10) != 0x01) { |
| 511 | ldm_crit ("Database is not in a consistent state. Aborting."); | 511 | ldm_crit ("Database is not in a consistent state. Aborting."); |
| 512 | goto out; | 512 | goto out; |
| 513 | } | 513 | } |
| @@ -802,7 +802,7 @@ static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb) | |||
| 802 | return false; | 802 | return false; |
| 803 | 803 | ||
| 804 | len += VBLK_SIZE_CMP3; | 804 | len += VBLK_SIZE_CMP3; |
| 805 | if (len != BE32 (buffer + 0x14)) | 805 | if (len != get_unaligned_be32(buffer + 0x14)) |
| 806 | return false; | 806 | return false; |
| 807 | 807 | ||
| 808 | comp = &vb->vblk.comp; | 808 | comp = &vb->vblk.comp; |
| @@ -851,7 +851,7 @@ static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb) | |||
| 851 | return false; | 851 | return false; |
| 852 | 852 | ||
| 853 | len += VBLK_SIZE_DGR3; | 853 | len += VBLK_SIZE_DGR3; |
| 854 | if (len != BE32 (buffer + 0x14)) | 854 | if (len != get_unaligned_be32(buffer + 0x14)) |
| 855 | return false; | 855 | return false; |
| 856 | 856 | ||
| 857 | dgrp = &vb->vblk.dgrp; | 857 | dgrp = &vb->vblk.dgrp; |
| @@ -895,7 +895,7 @@ static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb) | |||
| 895 | return false; | 895 | return false; |
| 896 | 896 | ||
| 897 | len += VBLK_SIZE_DGR4; | 897 | len += VBLK_SIZE_DGR4; |
| 898 | if (len != BE32 (buffer + 0x14)) | 898 | if (len != get_unaligned_be32(buffer + 0x14)) |
| 899 | return false; | 899 | return false; |
| 900 | 900 | ||
| 901 | dgrp = &vb->vblk.dgrp; | 901 | dgrp = &vb->vblk.dgrp; |
| @@ -931,7 +931,7 @@ static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb) | |||
| 931 | return false; | 931 | return false; |
| 932 | 932 | ||
| 933 | len += VBLK_SIZE_DSK3; | 933 | len += VBLK_SIZE_DSK3; |
| 934 | if (len != BE32 (buffer + 0x14)) | 934 | if (len != get_unaligned_be32(buffer + 0x14)) |
| 935 | return false; | 935 | return false; |
| 936 | 936 | ||
| 937 | disk = &vb->vblk.disk; | 937 | disk = &vb->vblk.disk; |
| @@ -968,7 +968,7 @@ static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb) | |||
| 968 | return false; | 968 | return false; |
| 969 | 969 | ||
| 970 | len += VBLK_SIZE_DSK4; | 970 | len += VBLK_SIZE_DSK4; |
| 971 | if (len != BE32 (buffer + 0x14)) | 971 | if (len != get_unaligned_be32(buffer + 0x14)) |
| 972 | return false; | 972 | return false; |
| 973 | 973 | ||
| 974 | disk = &vb->vblk.disk; | 974 | disk = &vb->vblk.disk; |
| @@ -1034,14 +1034,14 @@ static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb) | |||
| 1034 | return false; | 1034 | return false; |
| 1035 | } | 1035 | } |
| 1036 | len += VBLK_SIZE_PRT3; | 1036 | len += VBLK_SIZE_PRT3; |
| 1037 | if (len > BE32(buffer + 0x14)) { | 1037 | if (len > get_unaligned_be32(buffer + 0x14)) { |
| 1038 | ldm_error("len %d > BE32(buffer + 0x14) %d", len, | 1038 | ldm_error("len %d > BE32(buffer + 0x14) %d", len, |
| 1039 | BE32(buffer + 0x14)); | 1039 | get_unaligned_be32(buffer + 0x14)); |
| 1040 | return false; | 1040 | return false; |
| 1041 | } | 1041 | } |
| 1042 | part = &vb->vblk.part; | 1042 | part = &vb->vblk.part; |
| 1043 | part->start = BE64(buffer + 0x24 + r_name); | 1043 | part->start = get_unaligned_be64(buffer + 0x24 + r_name); |
| 1044 | part->volume_offset = BE64(buffer + 0x2C + r_name); | 1044 | part->volume_offset = get_unaligned_be64(buffer + 0x2C + r_name); |
| 1045 | part->size = ldm_get_vnum(buffer + 0x34 + r_name); | 1045 | part->size = ldm_get_vnum(buffer + 0x34 + r_name); |
| 1046 | part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size); | 1046 | part->parent_id = ldm_get_vnum(buffer + 0x34 + r_size); |
| 1047 | part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent); | 1047 | part->disk_id = ldm_get_vnum(buffer + 0x34 + r_parent); |
| @@ -1139,9 +1139,9 @@ static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb) | |||
| 1139 | return false; | 1139 | return false; |
| 1140 | } | 1140 | } |
| 1141 | len += VBLK_SIZE_VOL5; | 1141 | len += VBLK_SIZE_VOL5; |
| 1142 | if (len > BE32(buffer + 0x14)) { | 1142 | if (len > get_unaligned_be32(buffer + 0x14)) { |
| 1143 | ldm_error("len %d > BE32(buffer + 0x14) %d", len, | 1143 | ldm_error("len %d > BE32(buffer + 0x14) %d", len, |
| 1144 | BE32(buffer + 0x14)); | 1144 | get_unaligned_be32(buffer + 0x14)); |
| 1145 | return false; | 1145 | return false; |
| 1146 | } | 1146 | } |
| 1147 | volu = &vb->vblk.volu; | 1147 | volu = &vb->vblk.volu; |
| @@ -1294,9 +1294,9 @@ static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags) | |||
| 1294 | 1294 | ||
| 1295 | BUG_ON (!data || !frags); | 1295 | BUG_ON (!data || !frags); |
| 1296 | 1296 | ||
| 1297 | group = BE32 (data + 0x08); | 1297 | group = get_unaligned_be32(data + 0x08); |
| 1298 | rec = BE16 (data + 0x0C); | 1298 | rec = get_unaligned_be16(data + 0x0C); |
| 1299 | num = BE16 (data + 0x0E); | 1299 | num = get_unaligned_be16(data + 0x0E); |
| 1300 | if ((num < 1) || (num > 4)) { | 1300 | if ((num < 1) || (num > 4)) { |
| 1301 | ldm_error ("A VBLK claims to have %d parts.", num); | 1301 | ldm_error ("A VBLK claims to have %d parts.", num); |
| 1302 | return false; | 1302 | return false; |
| @@ -1425,12 +1425,12 @@ static bool ldm_get_vblks (struct block_device *bdev, unsigned long base, | |||
| 1425 | } | 1425 | } |
| 1426 | 1426 | ||
| 1427 | for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */ | 1427 | for (v = 0; v < perbuf; v++, data+=size) { /* For each vblk */ |
| 1428 | if (MAGIC_VBLK != BE32 (data)) { | 1428 | if (MAGIC_VBLK != get_unaligned_be32(data)) { |
| 1429 | ldm_error ("Expected to find a VBLK."); | 1429 | ldm_error ("Expected to find a VBLK."); |
| 1430 | goto out; | 1430 | goto out; |
| 1431 | } | 1431 | } |
| 1432 | 1432 | ||
| 1433 | recs = BE16 (data + 0x0E); /* Number of records */ | 1433 | recs = get_unaligned_be16(data + 0x0E); /* Number of records */ |
| 1434 | if (recs == 1) { | 1434 | if (recs == 1) { |
| 1435 | if (!ldm_ldmdb_add (data, size, ldb)) | 1435 | if (!ldm_ldmdb_add (data, size, ldb)) |
| 1436 | goto out; /* Already logged */ | 1436 | goto out; /* Already logged */ |
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h index 80f63b5fdd9f..30e08e809c1d 100644 --- a/fs/partitions/ldm.h +++ b/fs/partitions/ldm.h | |||
| @@ -98,11 +98,6 @@ struct parsed_partitions; | |||
| 98 | #define TOC_BITMAP1 "config" /* Names of the two defined */ | 98 | #define TOC_BITMAP1 "config" /* Names of the two defined */ |
| 99 | #define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ | 99 | #define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ |
| 100 | 100 | ||
| 101 | /* Most numbers we deal with are big-endian and won't be aligned. */ | ||
| 102 | #define BE16(x) ((u16)be16_to_cpu(get_unaligned((__be16*)(x)))) | ||
| 103 | #define BE32(x) ((u32)be32_to_cpu(get_unaligned((__be32*)(x)))) | ||
| 104 | #define BE64(x) ((u64)be64_to_cpu(get_unaligned((__be64*)(x)))) | ||
| 105 | |||
| 106 | /* Borrowed from msdos.c */ | 101 | /* Borrowed from msdos.c */ |
| 107 | #define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) | 102 | #define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) |
| 108 | 103 | ||
| @@ -777,45 +777,10 @@ pipe_rdwr_open(struct inode *inode, struct file *filp) | |||
| 777 | /* | 777 | /* |
| 778 | * The file_operations structs are not static because they | 778 | * The file_operations structs are not static because they |
| 779 | * are also used in linux/fs/fifo.c to do operations on FIFOs. | 779 | * are also used in linux/fs/fifo.c to do operations on FIFOs. |
| 780 | * | ||
| 781 | * Pipes reuse fifos' file_operations structs. | ||
| 780 | */ | 782 | */ |
| 781 | const struct file_operations read_fifo_fops = { | 783 | const struct file_operations read_pipefifo_fops = { |
| 782 | .llseek = no_llseek, | ||
| 783 | .read = do_sync_read, | ||
| 784 | .aio_read = pipe_read, | ||
| 785 | .write = bad_pipe_w, | ||
| 786 | .poll = pipe_poll, | ||
| 787 | .unlocked_ioctl = pipe_ioctl, | ||
| 788 | .open = pipe_read_open, | ||
| 789 | .release = pipe_read_release, | ||
| 790 | .fasync = pipe_read_fasync, | ||
| 791 | }; | ||
| 792 | |||
| 793 | const struct file_operations write_fifo_fops = { | ||
| 794 | .llseek = no_llseek, | ||
| 795 | .read = bad_pipe_r, | ||
| 796 | .write = do_sync_write, | ||
| 797 | .aio_write = pipe_write, | ||
| 798 | .poll = pipe_poll, | ||
| 799 | .unlocked_ioctl = pipe_ioctl, | ||
| 800 | .open = pipe_write_open, | ||
| 801 | .release = pipe_write_release, | ||
| 802 | .fasync = pipe_write_fasync, | ||
| 803 | }; | ||
| 804 | |||
| 805 | const struct file_operations rdwr_fifo_fops = { | ||
| 806 | .llseek = no_llseek, | ||
| 807 | .read = do_sync_read, | ||
| 808 | .aio_read = pipe_read, | ||
| 809 | .write = do_sync_write, | ||
| 810 | .aio_write = pipe_write, | ||
| 811 | .poll = pipe_poll, | ||
| 812 | .unlocked_ioctl = pipe_ioctl, | ||
| 813 | .open = pipe_rdwr_open, | ||
| 814 | .release = pipe_rdwr_release, | ||
| 815 | .fasync = pipe_rdwr_fasync, | ||
| 816 | }; | ||
| 817 | |||
| 818 | static const struct file_operations read_pipe_fops = { | ||
| 819 | .llseek = no_llseek, | 784 | .llseek = no_llseek, |
| 820 | .read = do_sync_read, | 785 | .read = do_sync_read, |
| 821 | .aio_read = pipe_read, | 786 | .aio_read = pipe_read, |
| @@ -827,7 +792,7 @@ static const struct file_operations read_pipe_fops = { | |||
| 827 | .fasync = pipe_read_fasync, | 792 | .fasync = pipe_read_fasync, |
| 828 | }; | 793 | }; |
| 829 | 794 | ||
| 830 | static const struct file_operations write_pipe_fops = { | 795 | const struct file_operations write_pipefifo_fops = { |
| 831 | .llseek = no_llseek, | 796 | .llseek = no_llseek, |
| 832 | .read = bad_pipe_r, | 797 | .read = bad_pipe_r, |
| 833 | .write = do_sync_write, | 798 | .write = do_sync_write, |
| @@ -839,7 +804,7 @@ static const struct file_operations write_pipe_fops = { | |||
| 839 | .fasync = pipe_write_fasync, | 804 | .fasync = pipe_write_fasync, |
| 840 | }; | 805 | }; |
| 841 | 806 | ||
| 842 | static const struct file_operations rdwr_pipe_fops = { | 807 | const struct file_operations rdwr_pipefifo_fops = { |
| 843 | .llseek = no_llseek, | 808 | .llseek = no_llseek, |
| 844 | .read = do_sync_read, | 809 | .read = do_sync_read, |
| 845 | .aio_read = pipe_read, | 810 | .aio_read = pipe_read, |
| @@ -927,7 +892,7 @@ static struct inode * get_pipe_inode(void) | |||
| 927 | inode->i_pipe = pipe; | 892 | inode->i_pipe = pipe; |
| 928 | 893 | ||
| 929 | pipe->readers = pipe->writers = 1; | 894 | pipe->readers = pipe->writers = 1; |
| 930 | inode->i_fop = &rdwr_pipe_fops; | 895 | inode->i_fop = &rdwr_pipefifo_fops; |
| 931 | 896 | ||
| 932 | /* | 897 | /* |
| 933 | * Mark the inode dirty from the very beginning, | 898 | * Mark the inode dirty from the very beginning, |
| @@ -978,7 +943,7 @@ struct file *create_write_pipe(int flags) | |||
| 978 | d_instantiate(dentry, inode); | 943 | d_instantiate(dentry, inode); |
| 979 | 944 | ||
| 980 | err = -ENFILE; | 945 | err = -ENFILE; |
| 981 | f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipe_fops); | 946 | f = alloc_file(pipe_mnt, dentry, FMODE_WRITE, &write_pipefifo_fops); |
| 982 | if (!f) | 947 | if (!f) |
| 983 | goto err_dentry; | 948 | goto err_dentry; |
| 984 | f->f_mapping = inode->i_mapping; | 949 | f->f_mapping = inode->i_mapping; |
| @@ -1020,7 +985,7 @@ struct file *create_read_pipe(struct file *wrf, int flags) | |||
| 1020 | 985 | ||
| 1021 | f->f_pos = 0; | 986 | f->f_pos = 0; |
| 1022 | f->f_flags = O_RDONLY | (flags & O_NONBLOCK); | 987 | f->f_flags = O_RDONLY | (flags & O_NONBLOCK); |
| 1023 | f->f_op = &read_pipe_fops; | 988 | f->f_op = &read_pipefifo_fops; |
| 1024 | f->f_mode = FMODE_READ; | 989 | f->f_mode = FMODE_READ; |
| 1025 | f->f_version = 0; | 990 | f->f_version = 0; |
| 1026 | 991 | ||
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig new file mode 100644 index 000000000000..73cd7a418f06 --- /dev/null +++ b/fs/proc/Kconfig | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | config PROC_FS | ||
| 2 | bool "/proc file system support" if EMBEDDED | ||
| 3 | default y | ||
| 4 | help | ||
| 5 | This is a virtual file system providing information about the status | ||
| 6 | of the system. "Virtual" means that it doesn't take up any space on | ||
| 7 | your hard disk: the files are created on the fly by the kernel when | ||
| 8 | you try to access them. Also, you cannot read the files with older | ||
| 9 | version of the program less: you need to use more or cat. | ||
| 10 | |||
| 11 | It's totally cool; for example, "cat /proc/interrupts" gives | ||
| 12 | information about what the different IRQs are used for at the moment | ||
| 13 | (there is a small number of Interrupt ReQuest lines in your computer | ||
| 14 | that are used by the attached devices to gain the CPU's attention -- | ||
| 15 | often a source of trouble if two devices are mistakenly configured | ||
| 16 | to use the same IRQ). The program procinfo to display some | ||
| 17 | information about your system gathered from the /proc file system. | ||
| 18 | |||
| 19 | Before you can use the /proc file system, it has to be mounted, | ||
| 20 | meaning it has to be given a location in the directory hierarchy. | ||
| 21 | That location should be /proc. A command such as "mount -t proc proc | ||
| 22 | /proc" or the equivalent line in /etc/fstab does the job. | ||
| 23 | |||
| 24 | The /proc file system is explained in the file | ||
| 25 | <file:Documentation/filesystems/proc.txt> and on the proc(5) manpage | ||
| 26 | ("man 5 proc"). | ||
| 27 | |||
| 28 | This option will enlarge your kernel by about 67 KB. Several | ||
| 29 | programs depend on this, so everyone should say Y here. | ||
| 30 | |||
| 31 | config PROC_KCORE | ||
| 32 | bool "/proc/kcore support" if !ARM | ||
| 33 | depends on PROC_FS && MMU | ||
| 34 | |||
| 35 | config PROC_VMCORE | ||
| 36 | bool "/proc/vmcore support (EXPERIMENTAL)" | ||
| 37 | depends on PROC_FS && CRASH_DUMP | ||
| 38 | default y | ||
| 39 | help | ||
| 40 | Exports the dump image of crashed kernel in ELF format. | ||
| 41 | |||
| 42 | config PROC_SYSCTL | ||
| 43 | bool "Sysctl support (/proc/sys)" if EMBEDDED | ||
| 44 | depends on PROC_FS | ||
| 45 | select SYSCTL | ||
| 46 | default y | ||
| 47 | ---help--- | ||
| 48 | The sysctl interface provides a means of dynamically changing | ||
| 49 | certain kernel parameters and variables on the fly without requiring | ||
| 50 | a recompile of the kernel or reboot of the system. The primary | ||
| 51 | interface is through /proc/sys. If you say Y here a tree of | ||
| 52 | modifiable sysctl entries will be generated beneath the | ||
| 53 | /proc/sys directory. They are explained in the files | ||
| 54 | in <file:Documentation/sysctl/>. Note that enabling this | ||
| 55 | option will enlarge the kernel by at least 8 KB. | ||
| 56 | |||
| 57 | As it is generally a good thing, you should say Y here unless | ||
| 58 | building a kernel for install/rescue disks or your system is very | ||
| 59 | limited in memory. | ||
diff --git a/fs/proc/array.c b/fs/proc/array.c index 797d775e0354..71c9be59c9c2 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -80,6 +80,7 @@ | |||
| 80 | #include <linux/delayacct.h> | 80 | #include <linux/delayacct.h> |
| 81 | #include <linux/seq_file.h> | 81 | #include <linux/seq_file.h> |
| 82 | #include <linux/pid_namespace.h> | 82 | #include <linux/pid_namespace.h> |
| 83 | #include <linux/tracehook.h> | ||
| 83 | 84 | ||
| 84 | #include <asm/pgtable.h> | 85 | #include <asm/pgtable.h> |
| 85 | #include <asm/processor.h> | 86 | #include <asm/processor.h> |
| @@ -168,8 +169,12 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
| 168 | rcu_read_lock(); | 169 | rcu_read_lock(); |
| 169 | ppid = pid_alive(p) ? | 170 | ppid = pid_alive(p) ? |
| 170 | task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; | 171 | task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; |
| 171 | tpid = pid_alive(p) && p->ptrace ? | 172 | tpid = 0; |
| 172 | task_pid_nr_ns(rcu_dereference(p->parent), ns) : 0; | 173 | if (pid_alive(p)) { |
| 174 | struct task_struct *tracer = tracehook_tracer_task(p); | ||
| 175 | if (tracer) | ||
| 176 | tpid = task_pid_nr_ns(tracer, ns); | ||
| 177 | } | ||
| 173 | seq_printf(m, | 178 | seq_printf(m, |
| 174 | "State:\t%s\n" | 179 | "State:\t%s\n" |
| 175 | "Tgid:\t%d\n" | 180 | "Tgid:\t%d\n" |
| @@ -332,65 +337,6 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | |||
| 332 | return 0; | 337 | return 0; |
| 333 | } | 338 | } |
| 334 | 339 | ||
| 335 | /* | ||
| 336 | * Use precise platform statistics if available: | ||
| 337 | */ | ||
| 338 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | ||
| 339 | static cputime_t task_utime(struct task_struct *p) | ||
| 340 | { | ||
| 341 | return p->utime; | ||
| 342 | } | ||
| 343 | |||
| 344 | static cputime_t task_stime(struct task_struct *p) | ||
| 345 | { | ||
| 346 | return p->stime; | ||
| 347 | } | ||
| 348 | #else | ||
| 349 | static cputime_t task_utime(struct task_struct *p) | ||
| 350 | { | ||
| 351 | clock_t utime = cputime_to_clock_t(p->utime), | ||
| 352 | total = utime + cputime_to_clock_t(p->stime); | ||
| 353 | u64 temp; | ||
| 354 | |||
| 355 | /* | ||
| 356 | * Use CFS's precise accounting: | ||
| 357 | */ | ||
| 358 | temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime); | ||
| 359 | |||
| 360 | if (total) { | ||
| 361 | temp *= utime; | ||
| 362 | do_div(temp, total); | ||
| 363 | } | ||
| 364 | utime = (clock_t)temp; | ||
| 365 | |||
| 366 | p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime)); | ||
| 367 | return p->prev_utime; | ||
| 368 | } | ||
| 369 | |||
| 370 | static cputime_t task_stime(struct task_struct *p) | ||
| 371 | { | ||
| 372 | clock_t stime; | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Use CFS's precise accounting. (we subtract utime from | ||
| 376 | * the total, to make sure the total observed by userspace | ||
| 377 | * grows monotonically - apps rely on that): | ||
| 378 | */ | ||
| 379 | stime = nsec_to_clock_t(p->se.sum_exec_runtime) - | ||
| 380 | cputime_to_clock_t(task_utime(p)); | ||
| 381 | |||
| 382 | if (stime >= 0) | ||
| 383 | p->prev_stime = max(p->prev_stime, clock_t_to_cputime(stime)); | ||
| 384 | |||
| 385 | return p->prev_stime; | ||
| 386 | } | ||
| 387 | #endif | ||
| 388 | |||
| 389 | static cputime_t task_gtime(struct task_struct *p) | ||
| 390 | { | ||
| 391 | return p->gtime; | ||
| 392 | } | ||
| 393 | |||
| 394 | static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | 340 | static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, |
| 395 | struct pid *pid, struct task_struct *task, int whole) | 341 | struct pid *pid, struct task_struct *task, int whole) |
| 396 | { | 342 | { |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 58c3e6a8e15e..a28840b11b89 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <linux/time.h> | 53 | #include <linux/time.h> |
| 54 | #include <linux/proc_fs.h> | 54 | #include <linux/proc_fs.h> |
| 55 | #include <linux/stat.h> | 55 | #include <linux/stat.h> |
| 56 | #include <linux/task_io_accounting_ops.h> | ||
| 56 | #include <linux/init.h> | 57 | #include <linux/init.h> |
| 57 | #include <linux/capability.h> | 58 | #include <linux/capability.h> |
| 58 | #include <linux/file.h> | 59 | #include <linux/file.h> |
| @@ -69,6 +70,7 @@ | |||
| 69 | #include <linux/mount.h> | 70 | #include <linux/mount.h> |
| 70 | #include <linux/security.h> | 71 | #include <linux/security.h> |
| 71 | #include <linux/ptrace.h> | 72 | #include <linux/ptrace.h> |
| 73 | #include <linux/tracehook.h> | ||
| 72 | #include <linux/cgroup.h> | 74 | #include <linux/cgroup.h> |
| 73 | #include <linux/cpuset.h> | 75 | #include <linux/cpuset.h> |
| 74 | #include <linux/audit.h> | 76 | #include <linux/audit.h> |
| @@ -231,10 +233,14 @@ static int check_mem_permission(struct task_struct *task) | |||
| 231 | * If current is actively ptrace'ing, and would also be | 233 | * If current is actively ptrace'ing, and would also be |
| 232 | * permitted to freshly attach with ptrace now, permit it. | 234 | * permitted to freshly attach with ptrace now, permit it. |
| 233 | */ | 235 | */ |
| 234 | if (task->parent == current && (task->ptrace & PT_PTRACED) && | 236 | if (task_is_stopped_or_traced(task)) { |
| 235 | task_is_stopped_or_traced(task) && | 237 | int match; |
| 236 | ptrace_may_access(task, PTRACE_MODE_ATTACH)) | 238 | rcu_read_lock(); |
| 237 | return 0; | 239 | match = (tracehook_tracer_task(task) == current); |
| 240 | rcu_read_unlock(); | ||
| 241 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) | ||
| 242 | return 0; | ||
| 243 | } | ||
| 238 | 244 | ||
| 239 | /* | 245 | /* |
| 240 | * Noone else is allowed. | 246 | * Noone else is allowed. |
| @@ -504,6 +510,26 @@ static int proc_pid_limits(struct task_struct *task, char *buffer) | |||
| 504 | return count; | 510 | return count; |
| 505 | } | 511 | } |
| 506 | 512 | ||
| 513 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | ||
| 514 | static int proc_pid_syscall(struct task_struct *task, char *buffer) | ||
| 515 | { | ||
| 516 | long nr; | ||
| 517 | unsigned long args[6], sp, pc; | ||
| 518 | |||
| 519 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) | ||
| 520 | return sprintf(buffer, "running\n"); | ||
| 521 | |||
| 522 | if (nr < 0) | ||
| 523 | return sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); | ||
| 524 | |||
| 525 | return sprintf(buffer, | ||
| 526 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | ||
| 527 | nr, | ||
| 528 | args[0], args[1], args[2], args[3], args[4], args[5], | ||
| 529 | sp, pc); | ||
| 530 | } | ||
| 531 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ | ||
| 532 | |||
| 507 | /************************************************************************/ | 533 | /************************************************************************/ |
| 508 | /* Here the fs part begins */ | 534 | /* Here the fs part begins */ |
| 509 | /************************************************************************/ | 535 | /************************************************************************/ |
| @@ -1834,8 +1860,7 @@ static const struct file_operations proc_fd_operations = { | |||
| 1834 | * /proc/pid/fd needs a special permission handler so that a process can still | 1860 | * /proc/pid/fd needs a special permission handler so that a process can still |
| 1835 | * access /proc/self/fd after it has executed a setuid(). | 1861 | * access /proc/self/fd after it has executed a setuid(). |
| 1836 | */ | 1862 | */ |
| 1837 | static int proc_fd_permission(struct inode *inode, int mask, | 1863 | static int proc_fd_permission(struct inode *inode, int mask) |
| 1838 | struct nameidata *nd) | ||
| 1839 | { | 1864 | { |
| 1840 | int rv; | 1865 | int rv; |
| 1841 | 1866 | ||
| @@ -2376,29 +2401,47 @@ static int proc_base_fill_cache(struct file *filp, void *dirent, | |||
| 2376 | } | 2401 | } |
| 2377 | 2402 | ||
| 2378 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2403 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
| 2379 | static int proc_pid_io_accounting(struct task_struct *task, char *buffer) | 2404 | static int do_io_accounting(struct task_struct *task, char *buffer, int whole) |
| 2380 | { | 2405 | { |
| 2406 | struct task_io_accounting acct = task->ioac; | ||
| 2407 | unsigned long flags; | ||
| 2408 | |||
| 2409 | if (whole && lock_task_sighand(task, &flags)) { | ||
| 2410 | struct task_struct *t = task; | ||
| 2411 | |||
| 2412 | task_io_accounting_add(&acct, &task->signal->ioac); | ||
| 2413 | while_each_thread(task, t) | ||
| 2414 | task_io_accounting_add(&acct, &t->ioac); | ||
| 2415 | |||
| 2416 | unlock_task_sighand(task, &flags); | ||
| 2417 | } | ||
| 2381 | return sprintf(buffer, | 2418 | return sprintf(buffer, |
| 2382 | #ifdef CONFIG_TASK_XACCT | ||
| 2383 | "rchar: %llu\n" | 2419 | "rchar: %llu\n" |
| 2384 | "wchar: %llu\n" | 2420 | "wchar: %llu\n" |
| 2385 | "syscr: %llu\n" | 2421 | "syscr: %llu\n" |
| 2386 | "syscw: %llu\n" | 2422 | "syscw: %llu\n" |
| 2387 | #endif | ||
| 2388 | "read_bytes: %llu\n" | 2423 | "read_bytes: %llu\n" |
| 2389 | "write_bytes: %llu\n" | 2424 | "write_bytes: %llu\n" |
| 2390 | "cancelled_write_bytes: %llu\n", | 2425 | "cancelled_write_bytes: %llu\n", |
| 2391 | #ifdef CONFIG_TASK_XACCT | 2426 | (unsigned long long)acct.rchar, |
| 2392 | (unsigned long long)task->rchar, | 2427 | (unsigned long long)acct.wchar, |
| 2393 | (unsigned long long)task->wchar, | 2428 | (unsigned long long)acct.syscr, |
| 2394 | (unsigned long long)task->syscr, | 2429 | (unsigned long long)acct.syscw, |
| 2395 | (unsigned long long)task->syscw, | 2430 | (unsigned long long)acct.read_bytes, |
| 2396 | #endif | 2431 | (unsigned long long)acct.write_bytes, |
| 2397 | (unsigned long long)task->ioac.read_bytes, | 2432 | (unsigned long long)acct.cancelled_write_bytes); |
| 2398 | (unsigned long long)task->ioac.write_bytes, | 2433 | } |
| 2399 | (unsigned long long)task->ioac.cancelled_write_bytes); | 2434 | |
| 2435 | static int proc_tid_io_accounting(struct task_struct *task, char *buffer) | ||
| 2436 | { | ||
| 2437 | return do_io_accounting(task, buffer, 0); | ||
| 2400 | } | 2438 | } |
| 2401 | #endif | 2439 | |
| 2440 | static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | ||
| 2441 | { | ||
| 2442 | return do_io_accounting(task, buffer, 1); | ||
| 2443 | } | ||
| 2444 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ | ||
| 2402 | 2445 | ||
| 2403 | /* | 2446 | /* |
| 2404 | * Thread groups | 2447 | * Thread groups |
| @@ -2420,6 +2463,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2420 | #ifdef CONFIG_SCHED_DEBUG | 2463 | #ifdef CONFIG_SCHED_DEBUG |
| 2421 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), | 2464 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), |
| 2422 | #endif | 2465 | #endif |
| 2466 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | ||
| 2467 | INF("syscall", S_IRUSR, pid_syscall), | ||
| 2468 | #endif | ||
| 2423 | INF("cmdline", S_IRUGO, pid_cmdline), | 2469 | INF("cmdline", S_IRUGO, pid_cmdline), |
| 2424 | ONE("stat", S_IRUGO, tgid_stat), | 2470 | ONE("stat", S_IRUGO, tgid_stat), |
| 2425 | ONE("statm", S_IRUGO, pid_statm), | 2471 | ONE("statm", S_IRUGO, pid_statm), |
| @@ -2470,7 +2516,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2470 | REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter), | 2516 | REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter), |
| 2471 | #endif | 2517 | #endif |
| 2472 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2518 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
| 2473 | INF("io", S_IRUGO, pid_io_accounting), | 2519 | INF("io", S_IRUGO, tgid_io_accounting), |
| 2474 | #endif | 2520 | #endif |
| 2475 | }; | 2521 | }; |
| 2476 | 2522 | ||
| @@ -2752,6 +2798,9 @@ static const struct pid_entry tid_base_stuff[] = { | |||
| 2752 | #ifdef CONFIG_SCHED_DEBUG | 2798 | #ifdef CONFIG_SCHED_DEBUG |
| 2753 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), | 2799 | REG("sched", S_IRUGO|S_IWUSR, pid_sched), |
| 2754 | #endif | 2800 | #endif |
| 2801 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | ||
| 2802 | INF("syscall", S_IRUSR, pid_syscall), | ||
| 2803 | #endif | ||
| 2755 | INF("cmdline", S_IRUGO, pid_cmdline), | 2804 | INF("cmdline", S_IRUGO, pid_cmdline), |
| 2756 | ONE("stat", S_IRUGO, tid_stat), | 2805 | ONE("stat", S_IRUGO, tid_stat), |
| 2757 | ONE("statm", S_IRUGO, pid_statm), | 2806 | ONE("statm", S_IRUGO, pid_statm), |
| @@ -2797,6 +2846,9 @@ static const struct pid_entry tid_base_stuff[] = { | |||
| 2797 | #ifdef CONFIG_FAULT_INJECTION | 2846 | #ifdef CONFIG_FAULT_INJECTION |
| 2798 | REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), | 2847 | REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), |
| 2799 | #endif | 2848 | #endif |
| 2849 | #ifdef CONFIG_TASK_IO_ACCOUNTING | ||
| 2850 | INF("io", S_IRUGO, tid_io_accounting), | ||
| 2851 | #endif | ||
| 2800 | }; | 2852 | }; |
| 2801 | 2853 | ||
| 2802 | static int proc_tid_base_readdir(struct file * filp, | 2854 | static int proc_tid_base_readdir(struct file * filp, |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 43e54e86cefd..7821589a17d5 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -300,10 +300,10 @@ out: | |||
| 300 | return rtn; | 300 | return rtn; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | static DEFINE_IDR(proc_inum_idr); | 303 | static DEFINE_IDA(proc_inum_ida); |
| 304 | static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | 304 | static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ |
| 305 | 305 | ||
| 306 | #define PROC_DYNAMIC_FIRST 0xF0000000UL | 306 | #define PROC_DYNAMIC_FIRST 0xF0000000U |
| 307 | 307 | ||
| 308 | /* | 308 | /* |
| 309 | * Return an inode number between PROC_DYNAMIC_FIRST and | 309 | * Return an inode number between PROC_DYNAMIC_FIRST and |
| @@ -311,36 +311,34 @@ static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ | |||
| 311 | */ | 311 | */ |
| 312 | static unsigned int get_inode_number(void) | 312 | static unsigned int get_inode_number(void) |
| 313 | { | 313 | { |
| 314 | int i, inum = 0; | 314 | unsigned int i; |
| 315 | int error; | 315 | int error; |
| 316 | 316 | ||
| 317 | retry: | 317 | retry: |
| 318 | if (idr_pre_get(&proc_inum_idr, GFP_KERNEL) == 0) | 318 | if (ida_pre_get(&proc_inum_ida, GFP_KERNEL) == 0) |
| 319 | return 0; | 319 | return 0; |
| 320 | 320 | ||
| 321 | spin_lock(&proc_inum_lock); | 321 | spin_lock(&proc_inum_lock); |
| 322 | error = idr_get_new(&proc_inum_idr, NULL, &i); | 322 | error = ida_get_new(&proc_inum_ida, &i); |
| 323 | spin_unlock(&proc_inum_lock); | 323 | spin_unlock(&proc_inum_lock); |
| 324 | if (error == -EAGAIN) | 324 | if (error == -EAGAIN) |
| 325 | goto retry; | 325 | goto retry; |
| 326 | else if (error) | 326 | else if (error) |
| 327 | return 0; | 327 | return 0; |
| 328 | 328 | ||
| 329 | inum = (i & MAX_ID_MASK) + PROC_DYNAMIC_FIRST; | 329 | if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { |
| 330 | 330 | spin_lock(&proc_inum_lock); | |
| 331 | /* inum will never be more than 0xf0ffffff, so no check | 331 | ida_remove(&proc_inum_ida, i); |
| 332 | * for overflow. | 332 | spin_unlock(&proc_inum_lock); |
| 333 | */ | 333 | return 0; |
| 334 | 334 | } | |
| 335 | return inum; | 335 | return PROC_DYNAMIC_FIRST + i; |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | static void release_inode_number(unsigned int inum) | 338 | static void release_inode_number(unsigned int inum) |
| 339 | { | 339 | { |
| 340 | int id = (inum - PROC_DYNAMIC_FIRST) | ~MAX_ID_MASK; | ||
| 341 | |||
| 342 | spin_lock(&proc_inum_lock); | 340 | spin_lock(&proc_inum_lock); |
| 343 | idr_remove(&proc_inum_idr, id); | 341 | ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); |
| 344 | spin_unlock(&proc_inum_lock); | 342 | spin_unlock(&proc_inum_lock); |
| 345 | } | 343 | } |
| 346 | 344 | ||
| @@ -549,8 +547,8 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
| 549 | 547 | ||
| 550 | for (tmp = dir->subdir; tmp; tmp = tmp->next) | 548 | for (tmp = dir->subdir; tmp; tmp = tmp->next) |
| 551 | if (strcmp(tmp->name, dp->name) == 0) { | 549 | if (strcmp(tmp->name, dp->name) == 0) { |
| 552 | printk(KERN_WARNING "proc_dir_entry '%s' already " | 550 | printk(KERN_WARNING "proc_dir_entry '%s/%s' already registered\n", |
| 553 | "registered\n", dp->name); | 551 | dir->name, dp->name); |
| 554 | dump_stack(); | 552 | dump_stack(); |
| 555 | break; | 553 | break; |
| 556 | } | 554 | } |
| @@ -597,6 +595,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
| 597 | ent->pde_users = 0; | 595 | ent->pde_users = 0; |
| 598 | spin_lock_init(&ent->pde_unload_lock); | 596 | spin_lock_init(&ent->pde_unload_lock); |
| 599 | ent->pde_unload_completion = NULL; | 597 | ent->pde_unload_completion = NULL; |
| 598 | INIT_LIST_HEAD(&ent->pde_openers); | ||
| 600 | out: | 599 | out: |
| 601 | return ent; | 600 | return ent; |
| 602 | } | 601 | } |
| @@ -789,15 +788,25 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
| 789 | spin_unlock(&de->pde_unload_lock); | 788 | spin_unlock(&de->pde_unload_lock); |
| 790 | 789 | ||
| 791 | continue_removing: | 790 | continue_removing: |
| 791 | spin_lock(&de->pde_unload_lock); | ||
| 792 | while (!list_empty(&de->pde_openers)) { | ||
| 793 | struct pde_opener *pdeo; | ||
| 794 | |||
| 795 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); | ||
| 796 | list_del(&pdeo->lh); | ||
| 797 | spin_unlock(&de->pde_unload_lock); | ||
| 798 | pdeo->release(pdeo->inode, pdeo->file); | ||
| 799 | kfree(pdeo); | ||
| 800 | spin_lock(&de->pde_unload_lock); | ||
| 801 | } | ||
| 802 | spin_unlock(&de->pde_unload_lock); | ||
| 803 | |||
| 792 | if (S_ISDIR(de->mode)) | 804 | if (S_ISDIR(de->mode)) |
| 793 | parent->nlink--; | 805 | parent->nlink--; |
| 794 | de->nlink = 0; | 806 | de->nlink = 0; |
| 795 | if (de->subdir) { | 807 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " |
| 796 | printk(KERN_WARNING "%s: removing non-empty directory " | ||
| 797 | "'%s/%s', leaking at least '%s'\n", __func__, | 808 | "'%s/%s', leaking at least '%s'\n", __func__, |
| 798 | de->parent->name, de->name, de->subdir->name); | 809 | de->parent->name, de->name, de->subdir->name); |
| 799 | WARN_ON(1); | ||
| 800 | } | ||
| 801 | if (atomic_dec_and_test(&de->count)) | 810 | if (atomic_dec_and_test(&de->count)) |
| 802 | free_proc_entry(de); | 811 | free_proc_entry(de); |
| 803 | } | 812 | } |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index b08d10017911..8bb03f056c28 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
| 20 | #include <linux/sysctl.h> | ||
| 20 | 21 | ||
| 21 | #include <asm/system.h> | 22 | #include <asm/system.h> |
| 22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
| @@ -65,6 +66,8 @@ static void proc_delete_inode(struct inode *inode) | |||
| 65 | module_put(de->owner); | 66 | module_put(de->owner); |
| 66 | de_put(de); | 67 | de_put(de); |
| 67 | } | 68 | } |
| 69 | if (PROC_I(inode)->sysctl) | ||
| 70 | sysctl_head_put(PROC_I(inode)->sysctl); | ||
| 68 | clear_inode(inode); | 71 | clear_inode(inode); |
| 69 | } | 72 | } |
| 70 | 73 | ||
| @@ -84,6 +87,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb) | |||
| 84 | ei->fd = 0; | 87 | ei->fd = 0; |
| 85 | ei->op.proc_get_link = NULL; | 88 | ei->op.proc_get_link = NULL; |
| 86 | ei->pde = NULL; | 89 | ei->pde = NULL; |
| 90 | ei->sysctl = NULL; | ||
| 91 | ei->sysctl_entry = NULL; | ||
| 87 | inode = &ei->vfs_inode; | 92 | inode = &ei->vfs_inode; |
| 88 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 93 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 89 | return inode; | 94 | return inode; |
| @@ -94,7 +99,7 @@ static void proc_destroy_inode(struct inode *inode) | |||
| 94 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); | 99 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); |
| 95 | } | 100 | } |
| 96 | 101 | ||
| 97 | static void init_once(struct kmem_cache * cachep, void *foo) | 102 | static void init_once(void *foo) |
| 98 | { | 103 | { |
| 99 | struct proc_inode *ei = (struct proc_inode *) foo; | 104 | struct proc_inode *ei = (struct proc_inode *) foo; |
| 100 | 105 | ||
| @@ -111,27 +116,25 @@ int __init proc_init_inodecache(void) | |||
| 111 | return 0; | 116 | return 0; |
| 112 | } | 117 | } |
| 113 | 118 | ||
| 114 | static int proc_remount(struct super_block *sb, int *flags, char *data) | ||
| 115 | { | ||
| 116 | *flags |= MS_NODIRATIME; | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | static const struct super_operations proc_sops = { | 119 | static const struct super_operations proc_sops = { |
| 121 | .alloc_inode = proc_alloc_inode, | 120 | .alloc_inode = proc_alloc_inode, |
| 122 | .destroy_inode = proc_destroy_inode, | 121 | .destroy_inode = proc_destroy_inode, |
| 123 | .drop_inode = generic_delete_inode, | 122 | .drop_inode = generic_delete_inode, |
| 124 | .delete_inode = proc_delete_inode, | 123 | .delete_inode = proc_delete_inode, |
| 125 | .statfs = simple_statfs, | 124 | .statfs = simple_statfs, |
| 126 | .remount_fs = proc_remount, | ||
| 127 | }; | 125 | }; |
| 128 | 126 | ||
| 129 | static void pde_users_dec(struct proc_dir_entry *pde) | 127 | static void __pde_users_dec(struct proc_dir_entry *pde) |
| 130 | { | 128 | { |
| 131 | spin_lock(&pde->pde_unload_lock); | ||
| 132 | pde->pde_users--; | 129 | pde->pde_users--; |
| 133 | if (pde->pde_unload_completion && pde->pde_users == 0) | 130 | if (pde->pde_unload_completion && pde->pde_users == 0) |
| 134 | complete(pde->pde_unload_completion); | 131 | complete(pde->pde_unload_completion); |
| 132 | } | ||
| 133 | |||
| 134 | static void pde_users_dec(struct proc_dir_entry *pde) | ||
| 135 | { | ||
| 136 | spin_lock(&pde->pde_unload_lock); | ||
| 137 | __pde_users_dec(pde); | ||
| 135 | spin_unlock(&pde->pde_unload_lock); | 138 | spin_unlock(&pde->pde_unload_lock); |
| 136 | } | 139 | } |
| 137 | 140 | ||
| @@ -318,36 +321,97 @@ static int proc_reg_open(struct inode *inode, struct file *file) | |||
| 318 | struct proc_dir_entry *pde = PDE(inode); | 321 | struct proc_dir_entry *pde = PDE(inode); |
| 319 | int rv = 0; | 322 | int rv = 0; |
| 320 | int (*open)(struct inode *, struct file *); | 323 | int (*open)(struct inode *, struct file *); |
| 324 | int (*release)(struct inode *, struct file *); | ||
| 325 | struct pde_opener *pdeo; | ||
| 326 | |||
| 327 | /* | ||
| 328 | * What for, you ask? Well, we can have open, rmmod, remove_proc_entry | ||
| 329 | * sequence. ->release won't be called because ->proc_fops will be | ||
| 330 | * cleared. Depending on complexity of ->release, consequences vary. | ||
| 331 | * | ||
| 332 | * We can't wait for mercy when close will be done for real, it's | ||
| 333 | * deadlockable: rmmod foo </proc/foo . So, we're going to do ->release | ||
| 334 | * by hand in remove_proc_entry(). For this, save opener's credentials | ||
| 335 | * for later. | ||
| 336 | */ | ||
| 337 | pdeo = kmalloc(sizeof(struct pde_opener), GFP_KERNEL); | ||
| 338 | if (!pdeo) | ||
| 339 | return -ENOMEM; | ||
| 321 | 340 | ||
| 322 | spin_lock(&pde->pde_unload_lock); | 341 | spin_lock(&pde->pde_unload_lock); |
| 323 | if (!pde->proc_fops) { | 342 | if (!pde->proc_fops) { |
| 324 | spin_unlock(&pde->pde_unload_lock); | 343 | spin_unlock(&pde->pde_unload_lock); |
| 344 | kfree(pdeo); | ||
| 325 | return rv; | 345 | return rv; |
| 326 | } | 346 | } |
| 327 | pde->pde_users++; | 347 | pde->pde_users++; |
| 328 | open = pde->proc_fops->open; | 348 | open = pde->proc_fops->open; |
| 349 | release = pde->proc_fops->release; | ||
| 329 | spin_unlock(&pde->pde_unload_lock); | 350 | spin_unlock(&pde->pde_unload_lock); |
| 330 | 351 | ||
| 331 | if (open) | 352 | if (open) |
| 332 | rv = open(inode, file); | 353 | rv = open(inode, file); |
| 333 | 354 | ||
| 334 | pde_users_dec(pde); | 355 | spin_lock(&pde->pde_unload_lock); |
| 356 | if (rv == 0 && release) { | ||
| 357 | /* To know what to release. */ | ||
| 358 | pdeo->inode = inode; | ||
| 359 | pdeo->file = file; | ||
| 360 | /* Strictly for "too late" ->release in proc_reg_release(). */ | ||
| 361 | pdeo->release = release; | ||
| 362 | list_add(&pdeo->lh, &pde->pde_openers); | ||
| 363 | } else | ||
| 364 | kfree(pdeo); | ||
| 365 | __pde_users_dec(pde); | ||
| 366 | spin_unlock(&pde->pde_unload_lock); | ||
| 335 | return rv; | 367 | return rv; |
| 336 | } | 368 | } |
| 337 | 369 | ||
| 370 | static struct pde_opener *find_pde_opener(struct proc_dir_entry *pde, | ||
| 371 | struct inode *inode, struct file *file) | ||
| 372 | { | ||
| 373 | struct pde_opener *pdeo; | ||
| 374 | |||
| 375 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { | ||
| 376 | if (pdeo->inode == inode && pdeo->file == file) | ||
| 377 | return pdeo; | ||
| 378 | } | ||
| 379 | return NULL; | ||
| 380 | } | ||
| 381 | |||
| 338 | static int proc_reg_release(struct inode *inode, struct file *file) | 382 | static int proc_reg_release(struct inode *inode, struct file *file) |
| 339 | { | 383 | { |
| 340 | struct proc_dir_entry *pde = PDE(inode); | 384 | struct proc_dir_entry *pde = PDE(inode); |
| 341 | int rv = 0; | 385 | int rv = 0; |
| 342 | int (*release)(struct inode *, struct file *); | 386 | int (*release)(struct inode *, struct file *); |
| 387 | struct pde_opener *pdeo; | ||
| 343 | 388 | ||
| 344 | spin_lock(&pde->pde_unload_lock); | 389 | spin_lock(&pde->pde_unload_lock); |
| 390 | pdeo = find_pde_opener(pde, inode, file); | ||
| 345 | if (!pde->proc_fops) { | 391 | if (!pde->proc_fops) { |
| 346 | spin_unlock(&pde->pde_unload_lock); | 392 | /* |
| 393 | * Can't simply exit, __fput() will think that everything is OK, | ||
| 394 | * and move on to freeing struct file. remove_proc_entry() will | ||
| 395 | * find slacker in opener's list and will try to do non-trivial | ||
| 396 | * things with struct file. Therefore, remove opener from list. | ||
| 397 | * | ||
| 398 | * But if opener is removed from list, who will ->release it? | ||
| 399 | */ | ||
| 400 | if (pdeo) { | ||
| 401 | list_del(&pdeo->lh); | ||
| 402 | spin_unlock(&pde->pde_unload_lock); | ||
| 403 | rv = pdeo->release(inode, file); | ||
| 404 | kfree(pdeo); | ||
| 405 | } else | ||
| 406 | spin_unlock(&pde->pde_unload_lock); | ||
| 347 | return rv; | 407 | return rv; |
| 348 | } | 408 | } |
| 349 | pde->pde_users++; | 409 | pde->pde_users++; |
| 350 | release = pde->proc_fops->release; | 410 | release = pde->proc_fops->release; |
| 411 | if (pdeo) { | ||
| 412 | list_del(&pdeo->lh); | ||
| 413 | kfree(pdeo); | ||
| 414 | } | ||
| 351 | spin_unlock(&pde->pde_unload_lock); | 415 | spin_unlock(&pde->pde_unload_lock); |
| 352 | 416 | ||
| 353 | if (release) | 417 | if (release) |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 28cbca805905..442202314d53 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -63,6 +63,7 @@ extern const struct file_operations proc_smaps_operations; | |||
| 63 | extern const struct file_operations proc_clear_refs_operations; | 63 | extern const struct file_operations proc_clear_refs_operations; |
| 64 | extern const struct file_operations proc_pagemap_operations; | 64 | extern const struct file_operations proc_pagemap_operations; |
| 65 | extern const struct file_operations proc_net_operations; | 65 | extern const struct file_operations proc_net_operations; |
| 66 | extern const struct file_operations proc_kmsg_operations; | ||
| 66 | extern const struct inode_operations proc_net_inode_operations; | 67 | extern const struct inode_operations proc_net_inode_operations; |
| 67 | 68 | ||
| 68 | void free_proc_entry(struct proc_dir_entry *de); | 69 | void free_proc_entry(struct proc_dir_entry *de); |
| @@ -88,3 +89,10 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *ino, | |||
| 88 | struct dentry *dentry); | 89 | struct dentry *dentry); |
| 89 | int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | 90 | int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, |
| 90 | filldir_t filldir); | 91 | filldir_t filldir); |
| 92 | |||
| 93 | struct pde_opener { | ||
| 94 | struct inode *inode; | ||
| 95 | struct file *file; | ||
| 96 | int (*release)(struct inode *, struct file *); | ||
| 97 | struct list_head lh; | ||
| 98 | }; | ||
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index e78c81fcf547..c2370c76fb71 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
| @@ -23,6 +23,10 @@ | |||
| 23 | 23 | ||
| 24 | #define CORE_STR "CORE" | 24 | #define CORE_STR "CORE" |
| 25 | 25 | ||
| 26 | #ifndef ELF_CORE_EFLAGS | ||
| 27 | #define ELF_CORE_EFLAGS 0 | ||
| 28 | #endif | ||
| 29 | |||
| 26 | static int open_kcore(struct inode * inode, struct file * filp) | 30 | static int open_kcore(struct inode * inode, struct file * filp) |
| 27 | { | 31 | { |
| 28 | return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; | 32 | return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; |
| @@ -164,11 +168,7 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff) | |||
| 164 | elf->e_entry = 0; | 168 | elf->e_entry = 0; |
| 165 | elf->e_phoff = sizeof(struct elfhdr); | 169 | elf->e_phoff = sizeof(struct elfhdr); |
| 166 | elf->e_shoff = 0; | 170 | elf->e_shoff = 0; |
| 167 | #if defined(CONFIG_H8300) | 171 | elf->e_flags = ELF_CORE_EFLAGS; |
| 168 | elf->e_flags = ELF_FLAGS; | ||
| 169 | #else | ||
| 170 | elf->e_flags = 0; | ||
| 171 | #endif | ||
| 172 | elf->e_ehsize = sizeof(struct elfhdr); | 172 | elf->e_ehsize = sizeof(struct elfhdr); |
| 173 | elf->e_phentsize= sizeof(struct elf_phdr); | 173 | elf->e_phentsize= sizeof(struct elf_phdr); |
| 174 | elf->e_phnum = nphdr; | 174 | elf->e_phnum = nphdr; |
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index ff3b90b56e9d..9fd5df3f40ce 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c | |||
| @@ -15,6 +15,8 @@ | |||
| 15 | #include <asm/uaccess.h> | 15 | #include <asm/uaccess.h> |
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | 17 | ||
| 18 | #include "internal.h" | ||
| 19 | |||
| 18 | extern wait_queue_head_t log_wait; | 20 | extern wait_queue_head_t log_wait; |
| 19 | 21 | ||
| 20 | extern int do_syslog(int type, char __user *bug, int count); | 22 | extern int do_syslog(int type, char __user *bug, int count); |
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 79ecd281d2cb..3f87d2632947 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c | |||
| @@ -52,14 +52,14 @@ int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) | |||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | seq_printf(m, | 54 | seq_printf(m, |
| 55 | "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", | 55 | "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", |
| 56 | vma->vm_start, | 56 | vma->vm_start, |
| 57 | vma->vm_end, | 57 | vma->vm_end, |
| 58 | flags & VM_READ ? 'r' : '-', | 58 | flags & VM_READ ? 'r' : '-', |
| 59 | flags & VM_WRITE ? 'w' : '-', | 59 | flags & VM_WRITE ? 'w' : '-', |
| 60 | flags & VM_EXEC ? 'x' : '-', | 60 | flags & VM_EXEC ? 'x' : '-', |
| 61 | flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', | 61 | flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', |
| 62 | vma->vm_pgoff << PAGE_SHIFT, | 62 | ((loff_t)vma->vm_pgoff) << PAGE_SHIFT, |
| 63 | MAJOR(dev), MINOR(dev), ino, &len); | 63 | MAJOR(dev), MINOR(dev), ino, &len); |
| 64 | 64 | ||
| 65 | if (file) { | 65 | if (file) { |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index ded969862960..29e20c6b1f7f 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/tty.h> | 24 | #include <linux/tty.h> |
| 25 | #include <linux/string.h> | 25 | #include <linux/string.h> |
| 26 | #include <linux/mman.h> | 26 | #include <linux/mman.h> |
| 27 | #include <linux/quicklist.h> | ||
| 27 | #include <linux/proc_fs.h> | 28 | #include <linux/proc_fs.h> |
| 28 | #include <linux/ioport.h> | 29 | #include <linux/ioport.h> |
| 29 | #include <linux/mm.h> | 30 | #include <linux/mm.h> |
| @@ -182,6 +183,9 @@ static int meminfo_read_proc(char *page, char **start, off_t off, | |||
| 182 | "SReclaimable: %8lu kB\n" | 183 | "SReclaimable: %8lu kB\n" |
| 183 | "SUnreclaim: %8lu kB\n" | 184 | "SUnreclaim: %8lu kB\n" |
| 184 | "PageTables: %8lu kB\n" | 185 | "PageTables: %8lu kB\n" |
| 186 | #ifdef CONFIG_QUICKLIST | ||
| 187 | "Quicklists: %8lu kB\n" | ||
| 188 | #endif | ||
| 185 | "NFS_Unstable: %8lu kB\n" | 189 | "NFS_Unstable: %8lu kB\n" |
| 186 | "Bounce: %8lu kB\n" | 190 | "Bounce: %8lu kB\n" |
| 187 | "WritebackTmp: %8lu kB\n" | 191 | "WritebackTmp: %8lu kB\n" |
| @@ -214,6 +218,9 @@ static int meminfo_read_proc(char *page, char **start, off_t off, | |||
| 214 | K(global_page_state(NR_SLAB_RECLAIMABLE)), | 218 | K(global_page_state(NR_SLAB_RECLAIMABLE)), |
| 215 | K(global_page_state(NR_SLAB_UNRECLAIMABLE)), | 219 | K(global_page_state(NR_SLAB_UNRECLAIMABLE)), |
| 216 | K(global_page_state(NR_PAGETABLE)), | 220 | K(global_page_state(NR_PAGETABLE)), |
| 221 | #ifdef CONFIG_QUICKLIST | ||
| 222 | K(quicklist_total_size()), | ||
| 223 | #endif | ||
| 217 | K(global_page_state(NR_UNSTABLE_NFS)), | 224 | K(global_page_state(NR_UNSTABLE_NFS)), |
| 218 | K(global_page_state(NR_BOUNCE)), | 225 | K(global_page_state(NR_BOUNCE)), |
| 219 | K(global_page_state(NR_WRITEBACK_TEMP)), | 226 | K(global_page_state(NR_WRITEBACK_TEMP)), |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 5acc001d49f6..f9a8b892718f 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -10,149 +10,110 @@ | |||
| 10 | static struct dentry_operations proc_sys_dentry_operations; | 10 | static struct dentry_operations proc_sys_dentry_operations; |
| 11 | static const struct file_operations proc_sys_file_operations; | 11 | static const struct file_operations proc_sys_file_operations; |
| 12 | static const struct inode_operations proc_sys_inode_operations; | 12 | static const struct inode_operations proc_sys_inode_operations; |
| 13 | static const struct file_operations proc_sys_dir_file_operations; | ||
| 14 | static const struct inode_operations proc_sys_dir_operations; | ||
| 13 | 15 | ||
| 14 | static void proc_sys_refresh_inode(struct inode *inode, struct ctl_table *table) | 16 | static struct inode *proc_sys_make_inode(struct super_block *sb, |
| 15 | { | 17 | struct ctl_table_header *head, struct ctl_table *table) |
| 16 | /* Refresh the cached information bits in the inode */ | ||
| 17 | if (table) { | ||
| 18 | inode->i_uid = 0; | ||
| 19 | inode->i_gid = 0; | ||
| 20 | inode->i_mode = table->mode; | ||
| 21 | if (table->proc_handler) { | ||
| 22 | inode->i_mode |= S_IFREG; | ||
| 23 | inode->i_nlink = 1; | ||
| 24 | } else { | ||
| 25 | inode->i_mode |= S_IFDIR; | ||
| 26 | inode->i_nlink = 0; /* It is too hard to figure out */ | ||
| 27 | } | ||
| 28 | } | ||
| 29 | } | ||
| 30 | |||
| 31 | static struct inode *proc_sys_make_inode(struct inode *dir, struct ctl_table *table) | ||
| 32 | { | 18 | { |
| 33 | struct inode *inode; | 19 | struct inode *inode; |
| 34 | struct proc_inode *dir_ei, *ei; | 20 | struct proc_inode *ei; |
| 35 | int depth; | ||
| 36 | 21 | ||
| 37 | inode = new_inode(dir->i_sb); | 22 | inode = new_inode(sb); |
| 38 | if (!inode) | 23 | if (!inode) |
| 39 | goto out; | 24 | goto out; |
| 40 | 25 | ||
| 41 | /* A directory is always one deeper than it's parent */ | 26 | sysctl_head_get(head); |
| 42 | dir_ei = PROC_I(dir); | ||
| 43 | depth = dir_ei->fd + 1; | ||
| 44 | |||
| 45 | ei = PROC_I(inode); | 27 | ei = PROC_I(inode); |
| 46 | ei->fd = depth; | 28 | ei->sysctl = head; |
| 29 | ei->sysctl_entry = table; | ||
| 30 | |||
| 47 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 31 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 48 | inode->i_op = &proc_sys_inode_operations; | ||
| 49 | inode->i_fop = &proc_sys_file_operations; | ||
| 50 | inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */ | 32 | inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */ |
| 51 | proc_sys_refresh_inode(inode, table); | 33 | inode->i_mode = table->mode; |
| 34 | if (!table->child) { | ||
| 35 | inode->i_mode |= S_IFREG; | ||
| 36 | inode->i_op = &proc_sys_inode_operations; | ||
| 37 | inode->i_fop = &proc_sys_file_operations; | ||
| 38 | } else { | ||
| 39 | inode->i_mode |= S_IFDIR; | ||
| 40 | inode->i_nlink = 0; | ||
| 41 | inode->i_op = &proc_sys_dir_operations; | ||
| 42 | inode->i_fop = &proc_sys_dir_file_operations; | ||
| 43 | } | ||
| 52 | out: | 44 | out: |
| 53 | return inode; | 45 | return inode; |
| 54 | } | 46 | } |
| 55 | 47 | ||
| 56 | static struct dentry *proc_sys_ancestor(struct dentry *dentry, int depth) | 48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) |
| 57 | { | ||
| 58 | for (;;) { | ||
| 59 | struct proc_inode *ei; | ||
| 60 | |||
| 61 | ei = PROC_I(dentry->d_inode); | ||
| 62 | if (ei->fd == depth) | ||
| 63 | break; /* found */ | ||
| 64 | |||
| 65 | dentry = dentry->d_parent; | ||
| 66 | } | ||
| 67 | return dentry; | ||
| 68 | } | ||
| 69 | |||
| 70 | static struct ctl_table *proc_sys_lookup_table_one(struct ctl_table *table, | ||
| 71 | struct qstr *name) | ||
| 72 | { | 49 | { |
| 73 | int len; | 50 | int len; |
| 74 | for ( ; table->ctl_name || table->procname; table++) { | 51 | for ( ; p->ctl_name || p->procname; p++) { |
| 75 | 52 | ||
| 76 | if (!table->procname) | 53 | if (!p->procname) |
| 77 | continue; | 54 | continue; |
| 78 | 55 | ||
| 79 | len = strlen(table->procname); | 56 | len = strlen(p->procname); |
| 80 | if (len != name->len) | 57 | if (len != name->len) |
| 81 | continue; | 58 | continue; |
| 82 | 59 | ||
| 83 | if (memcmp(table->procname, name->name, len) != 0) | 60 | if (memcmp(p->procname, name->name, len) != 0) |
| 84 | continue; | 61 | continue; |
| 85 | 62 | ||
| 86 | /* I have a match */ | 63 | /* I have a match */ |
| 87 | return table; | 64 | return p; |
| 88 | } | 65 | } |
| 89 | return NULL; | 66 | return NULL; |
| 90 | } | 67 | } |
| 91 | 68 | ||
| 92 | static struct ctl_table *proc_sys_lookup_table(struct dentry *dentry, | 69 | struct ctl_table_header *grab_header(struct inode *inode) |
| 93 | struct ctl_table *table) | ||
| 94 | { | 70 | { |
| 95 | struct dentry *ancestor; | 71 | if (PROC_I(inode)->sysctl) |
| 96 | struct proc_inode *ei; | 72 | return sysctl_head_grab(PROC_I(inode)->sysctl); |
| 97 | int depth, i; | 73 | else |
| 74 | return sysctl_head_next(NULL); | ||
| 75 | } | ||
| 98 | 76 | ||
| 99 | ei = PROC_I(dentry->d_inode); | 77 | static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, |
| 100 | depth = ei->fd; | 78 | struct nameidata *nd) |
| 79 | { | ||
| 80 | struct ctl_table_header *head = grab_header(dir); | ||
| 81 | struct ctl_table *table = PROC_I(dir)->sysctl_entry; | ||
| 82 | struct ctl_table_header *h = NULL; | ||
| 83 | struct qstr *name = &dentry->d_name; | ||
| 84 | struct ctl_table *p; | ||
| 85 | struct inode *inode; | ||
| 86 | struct dentry *err = ERR_PTR(-ENOENT); | ||
| 101 | 87 | ||
| 102 | if (depth == 0) | 88 | if (IS_ERR(head)) |
| 103 | return table; | 89 | return ERR_CAST(head); |
| 104 | 90 | ||
| 105 | for (i = 1; table && (i <= depth); i++) { | 91 | if (table && !table->child) { |
| 106 | ancestor = proc_sys_ancestor(dentry, i); | 92 | WARN_ON(1); |
| 107 | table = proc_sys_lookup_table_one(table, &ancestor->d_name); | 93 | goto out; |
| 108 | if (table) | ||
| 109 | table = table->child; | ||
| 110 | } | 94 | } |
| 111 | return table; | ||
| 112 | |||
| 113 | } | ||
| 114 | static struct ctl_table *proc_sys_lookup_entry(struct dentry *dparent, | ||
| 115 | struct qstr *name, | ||
| 116 | struct ctl_table *table) | ||
| 117 | { | ||
| 118 | table = proc_sys_lookup_table(dparent, table); | ||
| 119 | if (table) | ||
| 120 | table = proc_sys_lookup_table_one(table, name); | ||
| 121 | return table; | ||
| 122 | } | ||
| 123 | 95 | ||
| 124 | static struct ctl_table *do_proc_sys_lookup(struct dentry *parent, | 96 | table = table ? table->child : head->ctl_table; |
| 125 | struct qstr *name, | ||
| 126 | struct ctl_table_header **ptr) | ||
| 127 | { | ||
| 128 | struct ctl_table_header *head; | ||
| 129 | struct ctl_table *table = NULL; | ||
| 130 | 97 | ||
| 131 | for (head = sysctl_head_next(NULL); head; | 98 | p = find_in_table(table, name); |
| 132 | head = sysctl_head_next(head)) { | 99 | if (!p) { |
| 133 | table = proc_sys_lookup_entry(parent, name, head->ctl_table); | 100 | for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) { |
| 134 | if (table) | 101 | if (h->attached_to != table) |
| 135 | break; | 102 | continue; |
| 103 | p = find_in_table(h->attached_by, name); | ||
| 104 | if (p) | ||
| 105 | break; | ||
| 106 | } | ||
| 136 | } | 107 | } |
| 137 | *ptr = head; | ||
| 138 | return table; | ||
| 139 | } | ||
| 140 | |||
| 141 | static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, | ||
| 142 | struct nameidata *nd) | ||
| 143 | { | ||
| 144 | struct ctl_table_header *head; | ||
| 145 | struct inode *inode; | ||
| 146 | struct dentry *err; | ||
| 147 | struct ctl_table *table; | ||
| 148 | 108 | ||
| 149 | err = ERR_PTR(-ENOENT); | 109 | if (!p) |
| 150 | table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); | ||
| 151 | if (!table) | ||
| 152 | goto out; | 110 | goto out; |
| 153 | 111 | ||
| 154 | err = ERR_PTR(-ENOMEM); | 112 | err = ERR_PTR(-ENOMEM); |
| 155 | inode = proc_sys_make_inode(dir, table); | 113 | inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); |
| 114 | if (h) | ||
| 115 | sysctl_head_finish(h); | ||
| 116 | |||
| 156 | if (!inode) | 117 | if (!inode) |
| 157 | goto out; | 118 | goto out; |
| 158 | 119 | ||
| @@ -168,22 +129,14 @@ out: | |||
| 168 | static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, | 129 | static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, |
| 169 | size_t count, loff_t *ppos, int write) | 130 | size_t count, loff_t *ppos, int write) |
| 170 | { | 131 | { |
| 171 | struct dentry *dentry = filp->f_dentry; | 132 | struct inode *inode = filp->f_path.dentry->d_inode; |
| 172 | struct ctl_table_header *head; | 133 | struct ctl_table_header *head = grab_header(inode); |
| 173 | struct ctl_table *table; | 134 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; |
| 174 | ssize_t error; | 135 | ssize_t error; |
| 175 | size_t res; | 136 | size_t res; |
| 176 | 137 | ||
| 177 | table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); | 138 | if (IS_ERR(head)) |
| 178 | /* Has the sysctl entry disappeared on us? */ | 139 | return PTR_ERR(head); |
| 179 | error = -ENOENT; | ||
| 180 | if (!table) | ||
| 181 | goto out; | ||
| 182 | |||
| 183 | /* Has the sysctl entry been replaced by a directory? */ | ||
| 184 | error = -EISDIR; | ||
| 185 | if (!table->proc_handler) | ||
| 186 | goto out; | ||
| 187 | 140 | ||
| 188 | /* | 141 | /* |
| 189 | * At this point we know that the sysctl was not unregistered | 142 | * At this point we know that the sysctl was not unregistered |
| @@ -193,6 +146,11 @@ static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, | |||
| 193 | if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ)) | 146 | if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ)) |
| 194 | goto out; | 147 | goto out; |
| 195 | 148 | ||
| 149 | /* if that can happen at all, it should be -EINVAL, not -EISDIR */ | ||
| 150 | error = -EINVAL; | ||
| 151 | if (!table->proc_handler) | ||
| 152 | goto out; | ||
| 153 | |||
| 196 | /* careful: calling conventions are nasty here */ | 154 | /* careful: calling conventions are nasty here */ |
| 197 | res = count; | 155 | res = count; |
| 198 | error = table->proc_handler(table, write, filp, buf, &res, ppos); | 156 | error = table->proc_handler(table, write, filp, buf, &res, ppos); |
| @@ -218,82 +176,86 @@ static ssize_t proc_sys_write(struct file *filp, const char __user *buf, | |||
| 218 | 176 | ||
| 219 | 177 | ||
| 220 | static int proc_sys_fill_cache(struct file *filp, void *dirent, | 178 | static int proc_sys_fill_cache(struct file *filp, void *dirent, |
| 221 | filldir_t filldir, struct ctl_table *table) | 179 | filldir_t filldir, |
| 180 | struct ctl_table_header *head, | ||
| 181 | struct ctl_table *table) | ||
| 222 | { | 182 | { |
| 223 | struct ctl_table_header *head; | ||
| 224 | struct ctl_table *child_table = NULL; | ||
| 225 | struct dentry *child, *dir = filp->f_path.dentry; | 183 | struct dentry *child, *dir = filp->f_path.dentry; |
| 226 | struct inode *inode; | 184 | struct inode *inode; |
| 227 | struct qstr qname; | 185 | struct qstr qname; |
| 228 | ino_t ino = 0; | 186 | ino_t ino = 0; |
| 229 | unsigned type = DT_UNKNOWN; | 187 | unsigned type = DT_UNKNOWN; |
| 230 | int ret; | ||
| 231 | 188 | ||
| 232 | qname.name = table->procname; | 189 | qname.name = table->procname; |
| 233 | qname.len = strlen(table->procname); | 190 | qname.len = strlen(table->procname); |
| 234 | qname.hash = full_name_hash(qname.name, qname.len); | 191 | qname.hash = full_name_hash(qname.name, qname.len); |
| 235 | 192 | ||
| 236 | /* Suppress duplicates. | ||
| 237 | * Only fill a directory entry if it is the value that | ||
| 238 | * an ordinary lookup of that name returns. Hide all | ||
| 239 | * others. | ||
| 240 | * | ||
| 241 | * If we ever cache this translation in the dcache | ||
| 242 | * I should do a dcache lookup first. But for now | ||
| 243 | * it is just simpler not to. | ||
| 244 | */ | ||
| 245 | ret = 0; | ||
| 246 | child_table = do_proc_sys_lookup(dir, &qname, &head); | ||
| 247 | sysctl_head_finish(head); | ||
| 248 | if (child_table != table) | ||
| 249 | return 0; | ||
| 250 | |||
| 251 | child = d_lookup(dir, &qname); | 193 | child = d_lookup(dir, &qname); |
| 252 | if (!child) { | 194 | if (!child) { |
| 253 | struct dentry *new; | 195 | child = d_alloc(dir, &qname); |
| 254 | new = d_alloc(dir, &qname); | 196 | if (child) { |
| 255 | if (new) { | 197 | inode = proc_sys_make_inode(dir->d_sb, head, table); |
| 256 | inode = proc_sys_make_inode(dir->d_inode, table); | 198 | if (!inode) { |
| 257 | if (!inode) | 199 | dput(child); |
| 258 | child = ERR_PTR(-ENOMEM); | 200 | return -ENOMEM; |
| 259 | else { | 201 | } else { |
| 260 | new->d_op = &proc_sys_dentry_operations; | 202 | child->d_op = &proc_sys_dentry_operations; |
| 261 | d_add(new, inode); | 203 | d_add(child, inode); |
| 262 | } | 204 | } |
| 263 | if (child) | 205 | } else { |
| 264 | dput(new); | 206 | return -ENOMEM; |
| 265 | else | ||
| 266 | child = new; | ||
| 267 | } | 207 | } |
| 268 | } | 208 | } |
| 269 | if (!child || IS_ERR(child) || !child->d_inode) | ||
| 270 | goto end_instantiate; | ||
| 271 | inode = child->d_inode; | 209 | inode = child->d_inode; |
| 272 | if (inode) { | 210 | ino = inode->i_ino; |
| 273 | ino = inode->i_ino; | 211 | type = inode->i_mode >> 12; |
| 274 | type = inode->i_mode >> 12; | ||
| 275 | } | ||
| 276 | dput(child); | 212 | dput(child); |
| 277 | end_instantiate: | 213 | return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); |
| 278 | if (!ino) | 214 | } |
| 279 | ino= find_inode_number(dir, &qname); | 215 | |
| 280 | if (!ino) | 216 | static int scan(struct ctl_table_header *head, ctl_table *table, |
| 281 | ino = 1; | 217 | unsigned long *pos, struct file *file, |
| 282 | return filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); | 218 | void *dirent, filldir_t filldir) |
| 219 | { | ||
| 220 | |||
| 221 | for (; table->ctl_name || table->procname; table++, (*pos)++) { | ||
| 222 | int res; | ||
| 223 | |||
| 224 | /* Can't do anything without a proc name */ | ||
| 225 | if (!table->procname) | ||
| 226 | continue; | ||
| 227 | |||
| 228 | if (*pos < file->f_pos) | ||
| 229 | continue; | ||
| 230 | |||
| 231 | res = proc_sys_fill_cache(file, dirent, filldir, head, table); | ||
| 232 | if (res) | ||
| 233 | return res; | ||
| 234 | |||
| 235 | file->f_pos = *pos + 1; | ||
| 236 | } | ||
| 237 | return 0; | ||
| 283 | } | 238 | } |
| 284 | 239 | ||
| 285 | static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) | 240 | static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) |
| 286 | { | 241 | { |
| 287 | struct dentry *dentry = filp->f_dentry; | 242 | struct dentry *dentry = filp->f_path.dentry; |
| 288 | struct inode *inode = dentry->d_inode; | 243 | struct inode *inode = dentry->d_inode; |
| 289 | struct ctl_table_header *head = NULL; | 244 | struct ctl_table_header *head = grab_header(inode); |
| 290 | struct ctl_table *table; | 245 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; |
| 246 | struct ctl_table_header *h = NULL; | ||
| 291 | unsigned long pos; | 247 | unsigned long pos; |
| 292 | int ret; | 248 | int ret = -EINVAL; |
| 249 | |||
| 250 | if (IS_ERR(head)) | ||
| 251 | return PTR_ERR(head); | ||
| 293 | 252 | ||
| 294 | ret = -ENOTDIR; | 253 | if (table && !table->child) { |
| 295 | if (!S_ISDIR(inode->i_mode)) | 254 | WARN_ON(1); |
| 296 | goto out; | 255 | goto out; |
| 256 | } | ||
| 257 | |||
| 258 | table = table ? table->child : head->ctl_table; | ||
| 297 | 259 | ||
| 298 | ret = 0; | 260 | ret = 0; |
| 299 | /* Avoid a switch here: arm builds fail with missing __cmpdi2 */ | 261 | /* Avoid a switch here: arm builds fail with missing __cmpdi2 */ |
| @@ -311,30 +273,17 @@ static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 311 | } | 273 | } |
| 312 | pos = 2; | 274 | pos = 2; |
| 313 | 275 | ||
| 314 | /* - Find each instance of the directory | 276 | ret = scan(head, table, &pos, filp, dirent, filldir); |
| 315 | * - Read all entries in each instance | 277 | if (ret) |
| 316 | * - Before returning an entry to user space lookup the entry | 278 | goto out; |
| 317 | * by name and if I find a different entry don't return | ||
| 318 | * this one because it means it is a buried dup. | ||
| 319 | * For sysctl this should only happen for directory entries. | ||
| 320 | */ | ||
| 321 | for (head = sysctl_head_next(NULL); head; head = sysctl_head_next(head)) { | ||
| 322 | table = proc_sys_lookup_table(dentry, head->ctl_table); | ||
| 323 | 279 | ||
| 324 | if (!table) | 280 | for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) { |
| 281 | if (h->attached_to != table) | ||
| 325 | continue; | 282 | continue; |
| 326 | 283 | ret = scan(h, h->attached_by, &pos, filp, dirent, filldir); | |
| 327 | for (; table->ctl_name || table->procname; table++, pos++) { | 284 | if (ret) { |
| 328 | /* Can't do anything without a proc name */ | 285 | sysctl_head_finish(h); |
| 329 | if (!table->procname) | 286 | break; |
| 330 | continue; | ||
| 331 | |||
| 332 | if (pos < filp->f_pos) | ||
| 333 | continue; | ||
| 334 | |||
| 335 | if (proc_sys_fill_cache(filp, dirent, filldir, table) < 0) | ||
| 336 | goto out; | ||
| 337 | filp->f_pos = pos + 1; | ||
| 338 | } | 287 | } |
| 339 | } | 288 | } |
| 340 | ret = 1; | 289 | ret = 1; |
| @@ -343,53 +292,24 @@ out: | |||
| 343 | return ret; | 292 | return ret; |
| 344 | } | 293 | } |
| 345 | 294 | ||
| 346 | static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *nd) | 295 | static int proc_sys_permission(struct inode *inode, int mask) |
| 347 | { | 296 | { |
| 348 | /* | 297 | /* |
| 349 | * sysctl entries that are not writeable, | 298 | * sysctl entries that are not writeable, |
| 350 | * are _NOT_ writeable, capabilities or not. | 299 | * are _NOT_ writeable, capabilities or not. |
| 351 | */ | 300 | */ |
| 352 | struct ctl_table_header *head; | 301 | struct ctl_table_header *head = grab_header(inode); |
| 353 | struct ctl_table *table; | 302 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; |
| 354 | struct dentry *dentry; | ||
| 355 | int mode; | ||
| 356 | int depth; | ||
| 357 | int error; | 303 | int error; |
| 358 | 304 | ||
| 359 | head = NULL; | 305 | if (IS_ERR(head)) |
| 360 | depth = PROC_I(inode)->fd; | 306 | return PTR_ERR(head); |
| 361 | |||
| 362 | /* First check the cached permissions, in case we don't have | ||
| 363 | * enough information to lookup the sysctl table entry. | ||
| 364 | */ | ||
| 365 | error = -EACCES; | ||
| 366 | mode = inode->i_mode; | ||
| 367 | |||
| 368 | if (current->euid == 0) | ||
| 369 | mode >>= 6; | ||
| 370 | else if (in_group_p(0)) | ||
| 371 | mode >>= 3; | ||
| 372 | |||
| 373 | if ((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask) | ||
| 374 | error = 0; | ||
| 375 | |||
| 376 | /* If we can't get a sysctl table entry the permission | ||
| 377 | * checks on the cached mode will have to be enough. | ||
| 378 | */ | ||
| 379 | if (!nd || !depth) | ||
| 380 | goto out; | ||
| 381 | 307 | ||
| 382 | dentry = nd->path.dentry; | 308 | if (!table) /* global root - r-xr-xr-x */ |
| 383 | table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); | 309 | error = mask & MAY_WRITE ? -EACCES : 0; |
| 310 | else /* Use the permissions on the sysctl table entry */ | ||
| 311 | error = sysctl_perm(head->root, table, mask); | ||
| 384 | 312 | ||
| 385 | /* If the entry does not exist deny permission */ | ||
| 386 | error = -EACCES; | ||
| 387 | if (!table) | ||
| 388 | goto out; | ||
| 389 | |||
| 390 | /* Use the permissions on the sysctl table entry */ | ||
| 391 | error = sysctl_perm(head->root, table, mask); | ||
| 392 | out: | ||
| 393 | sysctl_head_finish(head); | 313 | sysctl_head_finish(head); |
| 394 | return error; | 314 | return error; |
| 395 | } | 315 | } |
| @@ -409,33 +329,70 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 409 | return error; | 329 | return error; |
| 410 | } | 330 | } |
| 411 | 331 | ||
| 412 | /* I'm lazy and don't distinguish between files and directories, | 332 | static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) |
| 413 | * until access time. | 333 | { |
| 414 | */ | 334 | struct inode *inode = dentry->d_inode; |
| 335 | struct ctl_table_header *head = grab_header(inode); | ||
| 336 | struct ctl_table *table = PROC_I(inode)->sysctl_entry; | ||
| 337 | |||
| 338 | if (IS_ERR(head)) | ||
| 339 | return PTR_ERR(head); | ||
| 340 | |||
| 341 | generic_fillattr(inode, stat); | ||
| 342 | if (table) | ||
| 343 | stat->mode = (stat->mode & S_IFMT) | table->mode; | ||
| 344 | |||
| 345 | sysctl_head_finish(head); | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 415 | static const struct file_operations proc_sys_file_operations = { | 349 | static const struct file_operations proc_sys_file_operations = { |
| 416 | .read = proc_sys_read, | 350 | .read = proc_sys_read, |
| 417 | .write = proc_sys_write, | 351 | .write = proc_sys_write, |
| 352 | }; | ||
| 353 | |||
| 354 | static const struct file_operations proc_sys_dir_file_operations = { | ||
| 418 | .readdir = proc_sys_readdir, | 355 | .readdir = proc_sys_readdir, |
| 419 | }; | 356 | }; |
| 420 | 357 | ||
| 421 | static const struct inode_operations proc_sys_inode_operations = { | 358 | static const struct inode_operations proc_sys_inode_operations = { |
| 359 | .permission = proc_sys_permission, | ||
| 360 | .setattr = proc_sys_setattr, | ||
| 361 | .getattr = proc_sys_getattr, | ||
| 362 | }; | ||
| 363 | |||
| 364 | static const struct inode_operations proc_sys_dir_operations = { | ||
| 422 | .lookup = proc_sys_lookup, | 365 | .lookup = proc_sys_lookup, |
| 423 | .permission = proc_sys_permission, | 366 | .permission = proc_sys_permission, |
| 424 | .setattr = proc_sys_setattr, | 367 | .setattr = proc_sys_setattr, |
| 368 | .getattr = proc_sys_getattr, | ||
| 425 | }; | 369 | }; |
| 426 | 370 | ||
| 427 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) | 371 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) |
| 428 | { | 372 | { |
| 429 | struct ctl_table_header *head; | 373 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; |
| 430 | struct ctl_table *table; | 374 | } |
| 431 | table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); | 375 | |
| 432 | proc_sys_refresh_inode(dentry->d_inode, table); | 376 | static int proc_sys_delete(struct dentry *dentry) |
| 433 | sysctl_head_finish(head); | 377 | { |
| 434 | return !!table; | 378 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; |
| 379 | } | ||
| 380 | |||
| 381 | static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, | ||
| 382 | struct qstr *name) | ||
| 383 | { | ||
| 384 | struct dentry *dentry = container_of(qstr, struct dentry, d_name); | ||
| 385 | if (qstr->len != name->len) | ||
| 386 | return 1; | ||
| 387 | if (memcmp(qstr->name, name->name, name->len)) | ||
| 388 | return 1; | ||
| 389 | return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); | ||
| 435 | } | 390 | } |
| 436 | 391 | ||
| 437 | static struct dentry_operations proc_sys_dentry_operations = { | 392 | static struct dentry_operations proc_sys_dentry_operations = { |
| 438 | .d_revalidate = proc_sys_revalidate, | 393 | .d_revalidate = proc_sys_revalidate, |
| 394 | .d_delete = proc_sys_delete, | ||
| 395 | .d_compare = proc_sys_compare, | ||
| 439 | }; | 396 | }; |
| 440 | 397 | ||
| 441 | static struct proc_dir_entry *proc_sys_root; | 398 | static struct proc_dir_entry *proc_sys_root; |
| @@ -443,8 +400,8 @@ static struct proc_dir_entry *proc_sys_root; | |||
| 443 | int proc_sys_init(void) | 400 | int proc_sys_init(void) |
| 444 | { | 401 | { |
| 445 | proc_sys_root = proc_mkdir("sys", NULL); | 402 | proc_sys_root = proc_mkdir("sys", NULL); |
| 446 | proc_sys_root->proc_iops = &proc_sys_inode_operations; | 403 | proc_sys_root->proc_iops = &proc_sys_dir_operations; |
| 447 | proc_sys_root->proc_fops = &proc_sys_file_operations; | 404 | proc_sys_root->proc_fops = &proc_sys_dir_file_operations; |
| 448 | proc_sys_root->nlink = 0; | 405 | proc_sys_root->nlink = 0; |
| 449 | return 0; | 406 | return 0; |
| 450 | } | 407 | } |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7546a918f790..73d1891ee625 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
| @@ -219,14 +219,14 @@ static int show_map(struct seq_file *m, void *v) | |||
| 219 | ino = inode->i_ino; | 219 | ino = inode->i_ino; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08lx %02x:%02x %lu %n", | 222 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", |
| 223 | vma->vm_start, | 223 | vma->vm_start, |
| 224 | vma->vm_end, | 224 | vma->vm_end, |
| 225 | flags & VM_READ ? 'r' : '-', | 225 | flags & VM_READ ? 'r' : '-', |
| 226 | flags & VM_WRITE ? 'w' : '-', | 226 | flags & VM_WRITE ? 'w' : '-', |
| 227 | flags & VM_EXEC ? 'x' : '-', | 227 | flags & VM_EXEC ? 'x' : '-', |
| 228 | flags & VM_MAYSHARE ? 's' : 'p', | 228 | flags & VM_MAYSHARE ? 's' : 'p', |
| 229 | vma->vm_pgoff << PAGE_SHIFT, | 229 | ((loff_t)vma->vm_pgoff) << PAGE_SHIFT, |
| 230 | MAJOR(dev), MINOR(dev), ino, &len); | 230 | MAJOR(dev), MINOR(dev), ino, &len); |
| 231 | 231 | ||
| 232 | /* | 232 | /* |
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index b31ab78052b3..2aad1044b84c 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
| @@ -553,7 +553,7 @@ static void qnx4_destroy_inode(struct inode *inode) | |||
| 553 | kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); | 553 | kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); |
| 554 | } | 554 | } |
| 555 | 555 | ||
| 556 | static void init_once(struct kmem_cache *cachep, void *foo) | 556 | static void init_once(void *foo) |
| 557 | { | 557 | { |
| 558 | struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; | 558 | struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; |
| 559 | 559 | ||
diff --git a/fs/quota.c b/fs/quota.c index db1cc9f3c7aa..7f4386ebc23a 100644 --- a/fs/quota.c +++ b/fs/quota.c | |||
| @@ -186,7 +186,7 @@ static void quota_sync_sb(struct super_block *sb, int type) | |||
| 186 | 186 | ||
| 187 | void sync_dquots(struct super_block *sb, int type) | 187 | void sync_dquots(struct super_block *sb, int type) |
| 188 | { | 188 | { |
| 189 | int cnt, dirty; | 189 | int cnt; |
| 190 | 190 | ||
| 191 | if (sb) { | 191 | if (sb) { |
| 192 | if (sb->s_qcop->quota_sync) | 192 | if (sb->s_qcop->quota_sync) |
| @@ -198,11 +198,17 @@ void sync_dquots(struct super_block *sb, int type) | |||
| 198 | restart: | 198 | restart: |
| 199 | list_for_each_entry(sb, &super_blocks, s_list) { | 199 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 200 | /* This test just improves performance so it needn't be reliable... */ | 200 | /* This test just improves performance so it needn't be reliable... */ |
| 201 | for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) | 201 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { |
| 202 | if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) | 202 | if (type != -1 && type != cnt) |
| 203 | && info_any_dirty(&sb_dqopt(sb)->info[cnt])) | 203 | continue; |
| 204 | dirty = 1; | 204 | if (!sb_has_quota_enabled(sb, cnt)) |
| 205 | if (!dirty) | 205 | continue; |
| 206 | if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && | ||
| 207 | list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) | ||
| 208 | continue; | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | if (cnt == MAXQUOTAS) | ||
| 206 | continue; | 212 | continue; |
| 207 | sb->s_count++; | 213 | sb->s_count++; |
| 208 | spin_unlock(&sb_lock); | 214 | spin_unlock(&sb_lock); |
diff --git a/fs/quota_v1.c b/fs/quota_v1.c index a6cf9269105c..5ae15b13eeb0 100644 --- a/fs/quota_v1.c +++ b/fs/quota_v1.c | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #include <linux/errno.h> | 1 | #include <linux/errno.h> |
| 2 | #include <linux/fs.h> | 2 | #include <linux/fs.h> |
| 3 | #include <linux/quota.h> | 3 | #include <linux/quota.h> |
| 4 | #include <linux/quotaops.h> | ||
| 4 | #include <linux/dqblk_v1.h> | 5 | #include <linux/dqblk_v1.h> |
| 5 | #include <linux/quotaio_v1.h> | 6 | #include <linux/quotaio_v1.h> |
| 6 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
diff --git a/fs/quota_v2.c b/fs/quota_v2.c index 234ada903633..b53827dc02d9 100644 --- a/fs/quota_v2.c +++ b/fs/quota_v2.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 14 | #include <linux/quotaops.h> | ||
| 14 | 15 | ||
| 15 | #include <asm/byteorder.h> | 16 | #include <asm/byteorder.h> |
| 16 | 17 | ||
diff --git a/fs/readdir.c b/fs/readdir.c index 4e026e5407fb..93a7559bbfd8 100644 --- a/fs/readdir.c +++ b/fs/readdir.c | |||
| @@ -80,8 +80,10 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset | |||
| 80 | if (buf->result) | 80 | if (buf->result) |
| 81 | return -EINVAL; | 81 | return -EINVAL; |
| 82 | d_ino = ino; | 82 | d_ino = ino; |
| 83 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) | 83 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { |
| 84 | buf->result = -EOVERFLOW; | ||
| 84 | return -EOVERFLOW; | 85 | return -EOVERFLOW; |
| 86 | } | ||
| 85 | buf->result++; | 87 | buf->result++; |
| 86 | dirent = buf->dirent; | 88 | dirent = buf->dirent; |
| 87 | if (!access_ok(VERIFY_WRITE, dirent, | 89 | if (!access_ok(VERIFY_WRITE, dirent, |
| @@ -155,8 +157,10 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, | |||
| 155 | if (reclen > buf->count) | 157 | if (reclen > buf->count) |
| 156 | return -EINVAL; | 158 | return -EINVAL; |
| 157 | d_ino = ino; | 159 | d_ino = ino; |
| 158 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) | 160 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { |
| 161 | buf->error = -EOVERFLOW; | ||
| 159 | return -EOVERFLOW; | 162 | return -EOVERFLOW; |
| 163 | } | ||
| 160 | dirent = buf->previous; | 164 | dirent = buf->previous; |
| 161 | if (dirent) { | 165 | if (dirent) { |
| 162 | if (__put_user(offset, &dirent->d_off)) | 166 | if (__put_user(offset, &dirent->d_off)) |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 192269698a8a..5699171212ae 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
| @@ -2435,7 +2435,7 @@ static int reiserfs_write_full_page(struct page *page, | |||
| 2435 | if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { | 2435 | if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) { |
| 2436 | lock_buffer(bh); | 2436 | lock_buffer(bh); |
| 2437 | } else { | 2437 | } else { |
| 2438 | if (test_set_buffer_locked(bh)) { | 2438 | if (!trylock_buffer(bh)) { |
| 2439 | redirty_page_for_writepage(wbc, page); | 2439 | redirty_page_for_writepage(wbc, page); |
| 2440 | continue; | 2440 | continue; |
| 2441 | } | 2441 | } |
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index e396b2fa4743..c21df71943a6 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
| @@ -34,15 +34,10 @@ | |||
| 34 | ** from within kupdate, it will ignore the immediate flag | 34 | ** from within kupdate, it will ignore the immediate flag |
| 35 | */ | 35 | */ |
| 36 | 36 | ||
| 37 | #include <asm/uaccess.h> | ||
| 38 | #include <asm/system.h> | ||
| 39 | |||
| 40 | #include <linux/time.h> | 37 | #include <linux/time.h> |
| 41 | #include <linux/semaphore.h> | 38 | #include <linux/semaphore.h> |
| 42 | |||
| 43 | #include <linux/vmalloc.h> | 39 | #include <linux/vmalloc.h> |
| 44 | #include <linux/reiserfs_fs.h> | 40 | #include <linux/reiserfs_fs.h> |
| 45 | |||
| 46 | #include <linux/kernel.h> | 41 | #include <linux/kernel.h> |
| 47 | #include <linux/errno.h> | 42 | #include <linux/errno.h> |
| 48 | #include <linux/fcntl.h> | 43 | #include <linux/fcntl.h> |
| @@ -54,6 +49,9 @@ | |||
| 54 | #include <linux/writeback.h> | 49 | #include <linux/writeback.h> |
| 55 | #include <linux/blkdev.h> | 50 | #include <linux/blkdev.h> |
| 56 | #include <linux/backing-dev.h> | 51 | #include <linux/backing-dev.h> |
| 52 | #include <linux/uaccess.h> | ||
| 53 | |||
| 54 | #include <asm/system.h> | ||
| 57 | 55 | ||
| 58 | /* gets a struct reiserfs_journal_list * from a list head */ | 56 | /* gets a struct reiserfs_journal_list * from a list head */ |
| 59 | #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \ | 57 | #define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \ |
| @@ -558,13 +556,13 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table, | |||
| 558 | static inline void lock_journal(struct super_block *p_s_sb) | 556 | static inline void lock_journal(struct super_block *p_s_sb) |
| 559 | { | 557 | { |
| 560 | PROC_INFO_INC(p_s_sb, journal.lock_journal); | 558 | PROC_INFO_INC(p_s_sb, journal.lock_journal); |
| 561 | down(&SB_JOURNAL(p_s_sb)->j_lock); | 559 | mutex_lock(&SB_JOURNAL(p_s_sb)->j_mutex); |
| 562 | } | 560 | } |
| 563 | 561 | ||
| 564 | /* unlock the current transaction */ | 562 | /* unlock the current transaction */ |
| 565 | static inline void unlock_journal(struct super_block *p_s_sb) | 563 | static inline void unlock_journal(struct super_block *p_s_sb) |
| 566 | { | 564 | { |
| 567 | up(&SB_JOURNAL(p_s_sb)->j_lock); | 565 | mutex_unlock(&SB_JOURNAL(p_s_sb)->j_mutex); |
| 568 | } | 566 | } |
| 569 | 567 | ||
| 570 | static inline void get_journal_list(struct reiserfs_journal_list *jl) | 568 | static inline void get_journal_list(struct reiserfs_journal_list *jl) |
| @@ -629,7 +627,7 @@ static int journal_list_still_alive(struct super_block *s, | |||
| 629 | static void release_buffer_page(struct buffer_head *bh) | 627 | static void release_buffer_page(struct buffer_head *bh) |
| 630 | { | 628 | { |
| 631 | struct page *page = bh->b_page; | 629 | struct page *page = bh->b_page; |
| 632 | if (!page->mapping && !TestSetPageLocked(page)) { | 630 | if (!page->mapping && trylock_page(page)) { |
| 633 | page_cache_get(page); | 631 | page_cache_get(page); |
| 634 | put_bh(bh); | 632 | put_bh(bh); |
| 635 | if (!page->mapping) | 633 | if (!page->mapping) |
| @@ -857,7 +855,7 @@ static int write_ordered_buffers(spinlock_t * lock, | |||
| 857 | jh = JH_ENTRY(list->next); | 855 | jh = JH_ENTRY(list->next); |
| 858 | bh = jh->bh; | 856 | bh = jh->bh; |
| 859 | get_bh(bh); | 857 | get_bh(bh); |
| 860 | if (test_set_buffer_locked(bh)) { | 858 | if (!trylock_buffer(bh)) { |
| 861 | if (!buffer_dirty(bh)) { | 859 | if (!buffer_dirty(bh)) { |
| 862 | list_move(&jh->list, &tmp); | 860 | list_move(&jh->list, &tmp); |
| 863 | goto loop_next; | 861 | goto loop_next; |
| @@ -1045,9 +1043,9 @@ static int flush_commit_list(struct super_block *s, | |||
| 1045 | } | 1043 | } |
| 1046 | 1044 | ||
| 1047 | /* make sure nobody is trying to flush this one at the same time */ | 1045 | /* make sure nobody is trying to flush this one at the same time */ |
| 1048 | down(&jl->j_commit_lock); | 1046 | mutex_lock(&jl->j_commit_mutex); |
| 1049 | if (!journal_list_still_alive(s, trans_id)) { | 1047 | if (!journal_list_still_alive(s, trans_id)) { |
| 1050 | up(&jl->j_commit_lock); | 1048 | mutex_unlock(&jl->j_commit_mutex); |
| 1051 | goto put_jl; | 1049 | goto put_jl; |
| 1052 | } | 1050 | } |
| 1053 | BUG_ON(jl->j_trans_id == 0); | 1051 | BUG_ON(jl->j_trans_id == 0); |
| @@ -1057,7 +1055,7 @@ static int flush_commit_list(struct super_block *s, | |||
| 1057 | if (flushall) { | 1055 | if (flushall) { |
| 1058 | atomic_set(&(jl->j_older_commits_done), 1); | 1056 | atomic_set(&(jl->j_older_commits_done), 1); |
| 1059 | } | 1057 | } |
| 1060 | up(&jl->j_commit_lock); | 1058 | mutex_unlock(&jl->j_commit_mutex); |
| 1061 | goto put_jl; | 1059 | goto put_jl; |
| 1062 | } | 1060 | } |
| 1063 | 1061 | ||
| @@ -1181,7 +1179,7 @@ static int flush_commit_list(struct super_block *s, | |||
| 1181 | if (flushall) { | 1179 | if (flushall) { |
| 1182 | atomic_set(&(jl->j_older_commits_done), 1); | 1180 | atomic_set(&(jl->j_older_commits_done), 1); |
| 1183 | } | 1181 | } |
| 1184 | up(&jl->j_commit_lock); | 1182 | mutex_unlock(&jl->j_commit_mutex); |
| 1185 | put_jl: | 1183 | put_jl: |
| 1186 | put_journal_list(s, jl); | 1184 | put_journal_list(s, jl); |
| 1187 | 1185 | ||
| @@ -1411,8 +1409,8 @@ static int flush_journal_list(struct super_block *s, | |||
| 1411 | 1409 | ||
| 1412 | /* if flushall == 0, the lock is already held */ | 1410 | /* if flushall == 0, the lock is already held */ |
| 1413 | if (flushall) { | 1411 | if (flushall) { |
| 1414 | down(&journal->j_flush_sem); | 1412 | mutex_lock(&journal->j_flush_mutex); |
| 1415 | } else if (!down_trylock(&journal->j_flush_sem)) { | 1413 | } else if (mutex_trylock(&journal->j_flush_mutex)) { |
| 1416 | BUG(); | 1414 | BUG(); |
| 1417 | } | 1415 | } |
| 1418 | 1416 | ||
| @@ -1642,7 +1640,7 @@ static int flush_journal_list(struct super_block *s, | |||
| 1642 | jl->j_state = 0; | 1640 | jl->j_state = 0; |
| 1643 | put_journal_list(s, jl); | 1641 | put_journal_list(s, jl); |
| 1644 | if (flushall) | 1642 | if (flushall) |
| 1645 | up(&journal->j_flush_sem); | 1643 | mutex_unlock(&journal->j_flush_mutex); |
| 1646 | put_fs_excl(); | 1644 | put_fs_excl(); |
| 1647 | return err; | 1645 | return err; |
| 1648 | } | 1646 | } |
| @@ -1772,12 +1770,12 @@ static int kupdate_transactions(struct super_block *s, | |||
| 1772 | struct reiserfs_journal *journal = SB_JOURNAL(s); | 1770 | struct reiserfs_journal *journal = SB_JOURNAL(s); |
| 1773 | chunk.nr = 0; | 1771 | chunk.nr = 0; |
| 1774 | 1772 | ||
| 1775 | down(&journal->j_flush_sem); | 1773 | mutex_lock(&journal->j_flush_mutex); |
| 1776 | if (!journal_list_still_alive(s, orig_trans_id)) { | 1774 | if (!journal_list_still_alive(s, orig_trans_id)) { |
| 1777 | goto done; | 1775 | goto done; |
| 1778 | } | 1776 | } |
| 1779 | 1777 | ||
| 1780 | /* we've got j_flush_sem held, nobody is going to delete any | 1778 | /* we've got j_flush_mutex held, nobody is going to delete any |
| 1781 | * of these lists out from underneath us | 1779 | * of these lists out from underneath us |
| 1782 | */ | 1780 | */ |
| 1783 | while ((num_trans && transactions_flushed < num_trans) || | 1781 | while ((num_trans && transactions_flushed < num_trans) || |
| @@ -1812,7 +1810,7 @@ static int kupdate_transactions(struct super_block *s, | |||
| 1812 | } | 1810 | } |
| 1813 | 1811 | ||
| 1814 | done: | 1812 | done: |
| 1815 | up(&journal->j_flush_sem); | 1813 | mutex_unlock(&journal->j_flush_mutex); |
| 1816 | return ret; | 1814 | return ret; |
| 1817 | } | 1815 | } |
| 1818 | 1816 | ||
| @@ -2556,7 +2554,7 @@ static struct reiserfs_journal_list *alloc_journal_list(struct super_block *s) | |||
| 2556 | INIT_LIST_HEAD(&jl->j_working_list); | 2554 | INIT_LIST_HEAD(&jl->j_working_list); |
| 2557 | INIT_LIST_HEAD(&jl->j_tail_bh_list); | 2555 | INIT_LIST_HEAD(&jl->j_tail_bh_list); |
| 2558 | INIT_LIST_HEAD(&jl->j_bh_list); | 2556 | INIT_LIST_HEAD(&jl->j_bh_list); |
| 2559 | sema_init(&jl->j_commit_lock, 1); | 2557 | mutex_init(&jl->j_commit_mutex); |
| 2560 | SB_JOURNAL(s)->j_num_lists++; | 2558 | SB_JOURNAL(s)->j_num_lists++; |
| 2561 | get_journal_list(jl); | 2559 | get_journal_list(jl); |
| 2562 | return jl; | 2560 | return jl; |
| @@ -2837,8 +2835,8 @@ int journal_init(struct super_block *p_s_sb, const char *j_dev_name, | |||
| 2837 | journal->j_last = NULL; | 2835 | journal->j_last = NULL; |
| 2838 | journal->j_first = NULL; | 2836 | journal->j_first = NULL; |
| 2839 | init_waitqueue_head(&(journal->j_join_wait)); | 2837 | init_waitqueue_head(&(journal->j_join_wait)); |
| 2840 | sema_init(&journal->j_lock, 1); | 2838 | mutex_init(&journal->j_mutex); |
| 2841 | sema_init(&journal->j_flush_sem, 1); | 2839 | mutex_init(&journal->j_flush_mutex); |
| 2842 | 2840 | ||
| 2843 | journal->j_trans_id = 10; | 2841 | journal->j_trans_id = 10; |
| 2844 | journal->j_mount_id = 10; | 2842 | journal->j_mount_id = 10; |
| @@ -3873,7 +3871,7 @@ int reiserfs_prepare_for_journal(struct super_block *p_s_sb, | |||
| 3873 | { | 3871 | { |
| 3874 | PROC_INFO_INC(p_s_sb, journal.prepare); | 3872 | PROC_INFO_INC(p_s_sb, journal.prepare); |
| 3875 | 3873 | ||
| 3876 | if (test_set_buffer_locked(bh)) { | 3874 | if (!trylock_buffer(bh)) { |
| 3877 | if (!wait) | 3875 | if (!wait) |
| 3878 | return 0; | 3876 | return 0; |
| 3879 | lock_buffer(bh); | 3877 | lock_buffer(bh); |
| @@ -4030,7 +4028,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, | |||
| 4030 | * the new transaction is fully setup, and we've already flushed the | 4028 | * the new transaction is fully setup, and we've already flushed the |
| 4031 | * ordered bh list | 4029 | * ordered bh list |
| 4032 | */ | 4030 | */ |
| 4033 | down(&jl->j_commit_lock); | 4031 | mutex_lock(&jl->j_commit_mutex); |
| 4034 | 4032 | ||
| 4035 | /* save the transaction id in case we need to commit it later */ | 4033 | /* save the transaction id in case we need to commit it later */ |
| 4036 | commit_trans_id = jl->j_trans_id; | 4034 | commit_trans_id = jl->j_trans_id; |
| @@ -4196,7 +4194,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, | |||
| 4196 | lock_kernel(); | 4194 | lock_kernel(); |
| 4197 | } | 4195 | } |
| 4198 | BUG_ON(!list_empty(&jl->j_tail_bh_list)); | 4196 | BUG_ON(!list_empty(&jl->j_tail_bh_list)); |
| 4199 | up(&jl->j_commit_lock); | 4197 | mutex_unlock(&jl->j_commit_mutex); |
| 4200 | 4198 | ||
| 4201 | /* honor the flush wishes from the caller, simple commits can | 4199 | /* honor the flush wishes from the caller, simple commits can |
| 4202 | ** be done outside the journal lock, they are done below | 4200 | ** be done outside the journal lock, they are done below |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 1d40f2bd1970..d318c7e663fa 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -22,11 +22,11 @@ | |||
| 22 | #include <linux/blkdev.h> | 22 | #include <linux/blkdev.h> |
| 23 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
| 24 | #include <linux/exportfs.h> | 24 | #include <linux/exportfs.h> |
| 25 | #include <linux/quotaops.h> | ||
| 25 | #include <linux/vfs.h> | 26 | #include <linux/vfs.h> |
| 26 | #include <linux/mnt_namespace.h> | 27 | #include <linux/mnt_namespace.h> |
| 27 | #include <linux/mount.h> | 28 | #include <linux/mount.h> |
| 28 | #include <linux/namei.h> | 29 | #include <linux/namei.h> |
| 29 | #include <linux/quotaops.h> | ||
| 30 | 30 | ||
| 31 | struct file_system_type reiserfs_fs_type; | 31 | struct file_system_type reiserfs_fs_type; |
| 32 | 32 | ||
| @@ -182,7 +182,7 @@ static int finish_unfinished(struct super_block *s) | |||
| 182 | int ret = reiserfs_quota_on_mount(s, i); | 182 | int ret = reiserfs_quota_on_mount(s, i); |
| 183 | if (ret < 0) | 183 | if (ret < 0) |
| 184 | reiserfs_warning(s, | 184 | reiserfs_warning(s, |
| 185 | "reiserfs: cannot turn on journalled quota: error %d", | 185 | "reiserfs: cannot turn on journaled quota: error %d", |
| 186 | ret); | 186 | ret); |
| 187 | } | 187 | } |
| 188 | } | 188 | } |
| @@ -520,7 +520,7 @@ static void reiserfs_destroy_inode(struct inode *inode) | |||
| 520 | kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); | 520 | kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | static void init_once(struct kmem_cache * cachep, void *foo) | 523 | static void init_once(void *foo) |
| 524 | { | 524 | { |
| 525 | struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; | 525 | struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; |
| 526 | 526 | ||
| @@ -876,7 +876,9 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
| 876 | mount options were selected. */ | 876 | mount options were selected. */ |
| 877 | unsigned long *blocks, /* strtol-ed from NNN of resize=NNN */ | 877 | unsigned long *blocks, /* strtol-ed from NNN of resize=NNN */ |
| 878 | char **jdev_name, | 878 | char **jdev_name, |
| 879 | unsigned int *commit_max_age) | 879 | unsigned int *commit_max_age, |
| 880 | char **qf_names, | ||
| 881 | unsigned int *qfmt) | ||
| 880 | { | 882 | { |
| 881 | int c; | 883 | int c; |
| 882 | char *arg = NULL; | 884 | char *arg = NULL; |
| @@ -992,9 +994,11 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
| 992 | if (c == 'u' || c == 'g') { | 994 | if (c == 'u' || c == 'g') { |
| 993 | int qtype = c == 'u' ? USRQUOTA : GRPQUOTA; | 995 | int qtype = c == 'u' ? USRQUOTA : GRPQUOTA; |
| 994 | 996 | ||
| 995 | if (sb_any_quota_enabled(s)) { | 997 | if ((sb_any_quota_enabled(s) || |
| 998 | sb_any_quota_suspended(s)) && | ||
| 999 | (!*arg != !REISERFS_SB(s)->s_qf_names[qtype])) { | ||
| 996 | reiserfs_warning(s, | 1000 | reiserfs_warning(s, |
| 997 | "reiserfs_parse_options: cannot change journalled quota options when quota turned on."); | 1001 | "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); |
| 998 | return 0; | 1002 | return 0; |
| 999 | } | 1003 | } |
| 1000 | if (*arg) { /* Some filename specified? */ | 1004 | if (*arg) { /* Some filename specified? */ |
| @@ -1011,46 +1015,54 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
| 1011 | "reiserfs_parse_options: quotafile must be on filesystem root."); | 1015 | "reiserfs_parse_options: quotafile must be on filesystem root."); |
| 1012 | return 0; | 1016 | return 0; |
| 1013 | } | 1017 | } |
| 1014 | REISERFS_SB(s)->s_qf_names[qtype] = | 1018 | qf_names[qtype] = |
| 1015 | kmalloc(strlen(arg) + 1, GFP_KERNEL); | 1019 | kmalloc(strlen(arg) + 1, GFP_KERNEL); |
| 1016 | if (!REISERFS_SB(s)->s_qf_names[qtype]) { | 1020 | if (!qf_names[qtype]) { |
| 1017 | reiserfs_warning(s, | 1021 | reiserfs_warning(s, |
| 1018 | "reiserfs_parse_options: not enough memory for storing quotafile name."); | 1022 | "reiserfs_parse_options: not enough memory for storing quotafile name."); |
| 1019 | return 0; | 1023 | return 0; |
| 1020 | } | 1024 | } |
| 1021 | strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); | 1025 | strcpy(qf_names[qtype], arg); |
| 1022 | *mount_options |= 1 << REISERFS_QUOTA; | 1026 | *mount_options |= 1 << REISERFS_QUOTA; |
| 1023 | } else { | 1027 | } else { |
| 1024 | kfree(REISERFS_SB(s)->s_qf_names[qtype]); | 1028 | if (qf_names[qtype] != |
| 1025 | REISERFS_SB(s)->s_qf_names[qtype] = NULL; | 1029 | REISERFS_SB(s)->s_qf_names[qtype]) |
| 1030 | kfree(qf_names[qtype]); | ||
| 1031 | qf_names[qtype] = NULL; | ||
| 1026 | } | 1032 | } |
| 1027 | } | 1033 | } |
| 1028 | if (c == 'f') { | 1034 | if (c == 'f') { |
| 1029 | if (!strcmp(arg, "vfsold")) | 1035 | if (!strcmp(arg, "vfsold")) |
| 1030 | REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_OLD; | 1036 | *qfmt = QFMT_VFS_OLD; |
| 1031 | else if (!strcmp(arg, "vfsv0")) | 1037 | else if (!strcmp(arg, "vfsv0")) |
| 1032 | REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_V0; | 1038 | *qfmt = QFMT_VFS_V0; |
| 1033 | else { | 1039 | else { |
| 1034 | reiserfs_warning(s, | 1040 | reiserfs_warning(s, |
| 1035 | "reiserfs_parse_options: unknown quota format specified."); | 1041 | "reiserfs_parse_options: unknown quota format specified."); |
| 1036 | return 0; | 1042 | return 0; |
| 1037 | } | 1043 | } |
| 1044 | if ((sb_any_quota_enabled(s) || | ||
| 1045 | sb_any_quota_suspended(s)) && | ||
| 1046 | *qfmt != REISERFS_SB(s)->s_jquota_fmt) { | ||
| 1047 | reiserfs_warning(s, | ||
| 1048 | "reiserfs_parse_options: cannot change journaled quota options when quota turned on."); | ||
| 1049 | return 0; | ||
| 1050 | } | ||
| 1038 | } | 1051 | } |
| 1039 | #else | 1052 | #else |
| 1040 | if (c == 'u' || c == 'g' || c == 'f') { | 1053 | if (c == 'u' || c == 'g' || c == 'f') { |
| 1041 | reiserfs_warning(s, | 1054 | reiserfs_warning(s, |
| 1042 | "reiserfs_parse_options: journalled quota options not supported."); | 1055 | "reiserfs_parse_options: journaled quota options not supported."); |
| 1043 | return 0; | 1056 | return 0; |
| 1044 | } | 1057 | } |
| 1045 | #endif | 1058 | #endif |
| 1046 | } | 1059 | } |
| 1047 | 1060 | ||
| 1048 | #ifdef CONFIG_QUOTA | 1061 | #ifdef CONFIG_QUOTA |
| 1049 | if (!REISERFS_SB(s)->s_jquota_fmt | 1062 | if (!REISERFS_SB(s)->s_jquota_fmt && !*qfmt |
| 1050 | && (REISERFS_SB(s)->s_qf_names[USRQUOTA] | 1063 | && (qf_names[USRQUOTA] || qf_names[GRPQUOTA])) { |
| 1051 | || REISERFS_SB(s)->s_qf_names[GRPQUOTA])) { | ||
| 1052 | reiserfs_warning(s, | 1064 | reiserfs_warning(s, |
| 1053 | "reiserfs_parse_options: journalled quota format not specified."); | 1065 | "reiserfs_parse_options: journaled quota format not specified."); |
| 1054 | return 0; | 1066 | return 0; |
| 1055 | } | 1067 | } |
| 1056 | /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ | 1068 | /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ |
| @@ -1130,6 +1142,21 @@ static void handle_attrs(struct super_block *s) | |||
| 1130 | } | 1142 | } |
| 1131 | } | 1143 | } |
| 1132 | 1144 | ||
| 1145 | #ifdef CONFIG_QUOTA | ||
| 1146 | static void handle_quota_files(struct super_block *s, char **qf_names, | ||
| 1147 | unsigned int *qfmt) | ||
| 1148 | { | ||
| 1149 | int i; | ||
| 1150 | |||
| 1151 | for (i = 0; i < MAXQUOTAS; i++) { | ||
| 1152 | if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i]) | ||
| 1153 | kfree(REISERFS_SB(s)->s_qf_names[i]); | ||
| 1154 | REISERFS_SB(s)->s_qf_names[i] = qf_names[i]; | ||
| 1155 | } | ||
| 1156 | REISERFS_SB(s)->s_jquota_fmt = *qfmt; | ||
| 1157 | } | ||
| 1158 | #endif | ||
| 1159 | |||
| 1133 | static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | 1160 | static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) |
| 1134 | { | 1161 | { |
| 1135 | struct reiserfs_super_block *rs; | 1162 | struct reiserfs_super_block *rs; |
| @@ -1141,23 +1168,30 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | |||
| 1141 | struct reiserfs_journal *journal = SB_JOURNAL(s); | 1168 | struct reiserfs_journal *journal = SB_JOURNAL(s); |
| 1142 | char *new_opts = kstrdup(arg, GFP_KERNEL); | 1169 | char *new_opts = kstrdup(arg, GFP_KERNEL); |
| 1143 | int err; | 1170 | int err; |
| 1171 | char *qf_names[MAXQUOTAS]; | ||
| 1172 | unsigned int qfmt = 0; | ||
| 1144 | #ifdef CONFIG_QUOTA | 1173 | #ifdef CONFIG_QUOTA |
| 1145 | int i; | 1174 | int i; |
| 1175 | |||
| 1176 | memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names)); | ||
| 1146 | #endif | 1177 | #endif |
| 1147 | 1178 | ||
| 1148 | rs = SB_DISK_SUPER_BLOCK(s); | 1179 | rs = SB_DISK_SUPER_BLOCK(s); |
| 1149 | 1180 | ||
| 1150 | if (!reiserfs_parse_options | 1181 | if (!reiserfs_parse_options |
| 1151 | (s, arg, &mount_options, &blocks, NULL, &commit_max_age)) { | 1182 | (s, arg, &mount_options, &blocks, NULL, &commit_max_age, |
| 1183 | qf_names, &qfmt)) { | ||
| 1152 | #ifdef CONFIG_QUOTA | 1184 | #ifdef CONFIG_QUOTA |
| 1153 | for (i = 0; i < MAXQUOTAS; i++) { | 1185 | for (i = 0; i < MAXQUOTAS; i++) |
| 1154 | kfree(REISERFS_SB(s)->s_qf_names[i]); | 1186 | if (qf_names[i] != REISERFS_SB(s)->s_qf_names[i]) |
| 1155 | REISERFS_SB(s)->s_qf_names[i] = NULL; | 1187 | kfree(qf_names[i]); |
| 1156 | } | ||
| 1157 | #endif | 1188 | #endif |
| 1158 | err = -EINVAL; | 1189 | err = -EINVAL; |
| 1159 | goto out_err; | 1190 | goto out_err; |
| 1160 | } | 1191 | } |
| 1192 | #ifdef CONFIG_QUOTA | ||
| 1193 | handle_quota_files(s, qf_names, &qfmt); | ||
| 1194 | #endif | ||
| 1161 | 1195 | ||
| 1162 | handle_attrs(s); | 1196 | handle_attrs(s); |
| 1163 | 1197 | ||
| @@ -1570,6 +1604,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 1570 | char *jdev_name; | 1604 | char *jdev_name; |
| 1571 | struct reiserfs_sb_info *sbi; | 1605 | struct reiserfs_sb_info *sbi; |
| 1572 | int errval = -EINVAL; | 1606 | int errval = -EINVAL; |
| 1607 | char *qf_names[MAXQUOTAS] = {}; | ||
| 1608 | unsigned int qfmt = 0; | ||
| 1573 | 1609 | ||
| 1574 | save_mount_options(s, data); | 1610 | save_mount_options(s, data); |
| 1575 | 1611 | ||
| @@ -1597,9 +1633,12 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 1597 | jdev_name = NULL; | 1633 | jdev_name = NULL; |
| 1598 | if (reiserfs_parse_options | 1634 | if (reiserfs_parse_options |
| 1599 | (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, | 1635 | (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name, |
| 1600 | &commit_max_age) == 0) { | 1636 | &commit_max_age, qf_names, &qfmt) == 0) { |
| 1601 | goto error; | 1637 | goto error; |
| 1602 | } | 1638 | } |
| 1639 | #ifdef CONFIG_QUOTA | ||
| 1640 | handle_quota_files(s, qf_names, &qfmt); | ||
| 1641 | #endif | ||
| 1603 | 1642 | ||
| 1604 | if (blocks) { | 1643 | if (blocks) { |
| 1605 | SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option " | 1644 | SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option " |
| @@ -1819,7 +1858,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 1819 | 1858 | ||
| 1820 | return (0); | 1859 | return (0); |
| 1821 | 1860 | ||
| 1822 | error: | 1861 | error: |
| 1823 | if (jinit_done) { /* kill the commit thread, free journal ram */ | 1862 | if (jinit_done) { /* kill the commit thread, free journal ram */ |
| 1824 | journal_release_error(NULL, s); | 1863 | journal_release_error(NULL, s); |
| 1825 | } | 1864 | } |
| @@ -1830,10 +1869,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 1830 | #ifdef CONFIG_QUOTA | 1869 | #ifdef CONFIG_QUOTA |
| 1831 | { | 1870 | { |
| 1832 | int j; | 1871 | int j; |
| 1833 | for (j = 0; j < MAXQUOTAS; j++) { | 1872 | for (j = 0; j < MAXQUOTAS; j++) |
| 1834 | kfree(sbi->s_qf_names[j]); | 1873 | kfree(qf_names[j]); |
| 1835 | sbi->s_qf_names[j] = NULL; | ||
| 1836 | } | ||
| 1837 | } | 1874 | } |
| 1838 | #endif | 1875 | #endif |
| 1839 | kfree(sbi); | 1876 | kfree(sbi); |
| @@ -1980,7 +2017,7 @@ static int reiserfs_release_dquot(struct dquot *dquot) | |||
| 1980 | 2017 | ||
| 1981 | static int reiserfs_mark_dquot_dirty(struct dquot *dquot) | 2018 | static int reiserfs_mark_dquot_dirty(struct dquot *dquot) |
| 1982 | { | 2019 | { |
| 1983 | /* Are we journalling quotas? */ | 2020 | /* Are we journaling quotas? */ |
| 1984 | if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || | 2021 | if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || |
| 1985 | REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { | 2022 | REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { |
| 1986 | dquot_mark_dquot_dirty(dquot); | 2023 | dquot_mark_dquot_dirty(dquot); |
| @@ -2026,6 +2063,7 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2026 | int err; | 2063 | int err; |
| 2027 | struct nameidata nd; | 2064 | struct nameidata nd; |
| 2028 | struct inode *inode; | 2065 | struct inode *inode; |
| 2066 | struct reiserfs_transaction_handle th; | ||
| 2029 | 2067 | ||
| 2030 | if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) | 2068 | if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA))) |
| 2031 | return -EINVAL; | 2069 | return -EINVAL; |
| @@ -2037,8 +2075,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2037 | return err; | 2075 | return err; |
| 2038 | /* Quotafile not on the same filesystem? */ | 2076 | /* Quotafile not on the same filesystem? */ |
| 2039 | if (nd.path.mnt->mnt_sb != sb) { | 2077 | if (nd.path.mnt->mnt_sb != sb) { |
| 2040 | path_put(&nd.path); | 2078 | err = -EXDEV; |
| 2041 | return -EXDEV; | 2079 | goto out; |
| 2042 | } | 2080 | } |
| 2043 | inode = nd.path.dentry->d_inode; | 2081 | inode = nd.path.dentry->d_inode; |
| 2044 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ | 2082 | /* We must not pack tails for quota files on reiserfs for quota IO to work */ |
| @@ -2048,24 +2086,37 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, | |||
| 2048 | reiserfs_warning(sb, | 2086 | reiserfs_warning(sb, |
| 2049 | "reiserfs: Unpacking tail of quota file failed" | 2087 | "reiserfs: Unpacking tail of quota file failed" |
| 2050 | " (%d). Cannot turn on quotas.", err); | 2088 | " (%d). Cannot turn on quotas.", err); |
| 2051 | path_put(&nd.path); | 2089 | err = -EINVAL; |
| 2052 | return -EINVAL; | 2090 | goto out; |
| 2053 | } | 2091 | } |
| 2054 | mark_inode_dirty(inode); | 2092 | mark_inode_dirty(inode); |
| 2055 | } | 2093 | } |
| 2056 | /* Not journalling quota? No more tests needed... */ | 2094 | /* Journaling quota? */ |
| 2057 | if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] && | 2095 | if (REISERFS_SB(sb)->s_qf_names[type]) { |
| 2058 | !REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) { | 2096 | /* Quotafile not of fs root? */ |
| 2059 | path_put(&nd.path); | 2097 | if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) |
| 2060 | return vfs_quota_on(sb, type, format_id, path, 0); | 2098 | reiserfs_warning(sb, |
| 2061 | } | ||
| 2062 | /* Quotafile not of fs root? */ | ||
| 2063 | if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) | ||
| 2064 | reiserfs_warning(sb, | ||
| 2065 | "reiserfs: Quota file not on filesystem root. " | 2099 | "reiserfs: Quota file not on filesystem root. " |
| 2066 | "Journalled quota will not work."); | 2100 | "Journalled quota will not work."); |
| 2101 | } | ||
| 2102 | |||
| 2103 | /* | ||
| 2104 | * When we journal data on quota file, we have to flush journal to see | ||
| 2105 | * all updates to the file when we bypass pagecache... | ||
| 2106 | */ | ||
| 2107 | if (reiserfs_file_data_log(inode)) { | ||
| 2108 | /* Just start temporary transaction and finish it */ | ||
| 2109 | err = journal_begin(&th, sb, 1); | ||
| 2110 | if (err) | ||
| 2111 | goto out; | ||
| 2112 | err = journal_end_sync(&th, sb, 1); | ||
| 2113 | if (err) | ||
| 2114 | goto out; | ||
| 2115 | } | ||
| 2116 | err = vfs_quota_on_path(sb, type, format_id, &nd.path); | ||
| 2117 | out: | ||
| 2067 | path_put(&nd.path); | 2118 | path_put(&nd.path); |
| 2068 | return vfs_quota_on(sb, type, format_id, path, 0); | 2119 | return err; |
| 2069 | } | 2120 | } |
| 2070 | 2121 | ||
| 2071 | /* Read data from quotafile - avoid pagecache and such because we cannot afford | 2122 | /* Read data from quotafile - avoid pagecache and such because we cannot afford |
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index d7c4935c1034..bb3cb5b7cdb2 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
| @@ -1250,7 +1250,7 @@ static int reiserfs_check_acl(struct inode *inode, int mask) | |||
| 1250 | return error; | 1250 | return error; |
| 1251 | } | 1251 | } |
| 1252 | 1252 | ||
| 1253 | int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd) | 1253 | int reiserfs_permission(struct inode *inode, int mask) |
| 1254 | { | 1254 | { |
| 1255 | /* | 1255 | /* |
| 1256 | * We don't do permission checks on the internal objects. | 1256 | * We don't do permission checks on the internal objects. |
diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index 5e90a95ad60b..056008db1377 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | #include <linux/reiserfs_xattr.h> | 6 | #include <linux/reiserfs_xattr.h> |
| 7 | #include <asm/uaccess.h> | 7 | #include <asm/uaccess.h> |
| 8 | 8 | ||
| 9 | #define XATTR_SECURITY_PREFIX "security." | ||
| 10 | |||
| 11 | static int | 9 | static int |
| 12 | security_get(struct inode *inode, const char *name, void *buffer, size_t size) | 10 | security_get(struct inode *inode, const char *name, void *buffer, size_t size) |
| 13 | { | 11 | { |
diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c index 024a938ca60f..60abe2bb1f98 100644 --- a/fs/reiserfs/xattr_trusted.c +++ b/fs/reiserfs/xattr_trusted.c | |||
| @@ -7,8 +7,6 @@ | |||
| 7 | #include <linux/reiserfs_xattr.h> | 7 | #include <linux/reiserfs_xattr.h> |
| 8 | #include <asm/uaccess.h> | 8 | #include <asm/uaccess.h> |
| 9 | 9 | ||
| 10 | #define XATTR_TRUSTED_PREFIX "trusted." | ||
| 11 | |||
| 12 | static int | 10 | static int |
| 13 | trusted_get(struct inode *inode, const char *name, void *buffer, size_t size) | 11 | trusted_get(struct inode *inode, const char *name, void *buffer, size_t size) |
| 14 | { | 12 | { |
diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c index 073f39364b11..1384efcb938e 100644 --- a/fs/reiserfs/xattr_user.c +++ b/fs/reiserfs/xattr_user.c | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | # include <linux/reiserfs_acl.h> | 10 | # include <linux/reiserfs_acl.h> |
| 11 | #endif | 11 | #endif |
| 12 | 12 | ||
| 13 | #define XATTR_USER_PREFIX "user." | ||
| 14 | |||
| 15 | static int | 13 | static int |
| 16 | user_get(struct inode *inode, const char *name, void *buffer, size_t size) | 14 | user_get(struct inode *inode, const char *name, void *buffer, size_t size) |
| 17 | { | 15 | { |
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 3f13d491c7c7..60d2f822e87b 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c | |||
| @@ -418,7 +418,8 @@ static int | |||
| 418 | romfs_readpage(struct file *file, struct page * page) | 418 | romfs_readpage(struct file *file, struct page * page) |
| 419 | { | 419 | { |
| 420 | struct inode *inode = page->mapping->host; | 420 | struct inode *inode = page->mapping->host; |
| 421 | loff_t offset, avail, readlen; | 421 | loff_t offset, size; |
| 422 | unsigned long filled; | ||
| 422 | void *buf; | 423 | void *buf; |
| 423 | int result = -EIO; | 424 | int result = -EIO; |
| 424 | 425 | ||
| @@ -430,21 +431,29 @@ romfs_readpage(struct file *file, struct page * page) | |||
| 430 | 431 | ||
| 431 | /* 32 bit warning -- but not for us :) */ | 432 | /* 32 bit warning -- but not for us :) */ |
| 432 | offset = page_offset(page); | 433 | offset = page_offset(page); |
| 433 | if (offset < i_size_read(inode)) { | 434 | size = i_size_read(inode); |
| 434 | avail = inode->i_size-offset; | 435 | filled = 0; |
| 435 | readlen = min_t(unsigned long, avail, PAGE_SIZE); | 436 | result = 0; |
| 436 | if (romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen) == readlen) { | 437 | if (offset < size) { |
| 437 | if (readlen < PAGE_SIZE) { | 438 | unsigned long readlen; |
| 438 | memset(buf + readlen,0,PAGE_SIZE-readlen); | 439 | |
| 439 | } | 440 | size -= offset; |
| 440 | SetPageUptodate(page); | 441 | readlen = size > PAGE_SIZE ? PAGE_SIZE : size; |
| 441 | result = 0; | 442 | |
| 443 | filled = romfs_copyfrom(inode, buf, ROMFS_I(inode)->i_dataoffset+offset, readlen); | ||
| 444 | |||
| 445 | if (filled != readlen) { | ||
| 446 | SetPageError(page); | ||
| 447 | filled = 0; | ||
| 448 | result = -EIO; | ||
| 442 | } | 449 | } |
| 443 | } | 450 | } |
| 444 | if (result) { | 451 | |
| 445 | memset(buf, 0, PAGE_SIZE); | 452 | if (filled < PAGE_SIZE) |
| 446 | SetPageError(page); | 453 | memset(buf + filled, 0, PAGE_SIZE-filled); |
| 447 | } | 454 | |
| 455 | if (!result) | ||
| 456 | SetPageUptodate(page); | ||
| 448 | flush_dcache_page(page); | 457 | flush_dcache_page(page); |
| 449 | 458 | ||
| 450 | unlock_page(page); | 459 | unlock_page(page); |
| @@ -577,7 +586,7 @@ static void romfs_destroy_inode(struct inode *inode) | |||
| 577 | kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); | 586 | kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); |
| 578 | } | 587 | } |
| 579 | 588 | ||
| 580 | static void init_once(struct kmem_cache *cachep, void *foo) | 589 | static void init_once(void *foo) |
| 581 | { | 590 | { |
| 582 | struct romfs_inode_info *ei = foo; | 591 | struct romfs_inode_info *ei = foo; |
| 583 | 592 | ||
diff --git a/fs/seq_file.c b/fs/seq_file.c index 3f54dbd6c49b..bd20f7f5a933 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
| @@ -108,9 +108,9 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
| 108 | goto Done; | 108 | goto Done; |
| 109 | } | 109 | } |
| 110 | /* we need at least one record in buffer */ | 110 | /* we need at least one record in buffer */ |
| 111 | pos = m->index; | ||
| 112 | p = m->op->start(m, &pos); | ||
| 111 | while (1) { | 113 | while (1) { |
| 112 | pos = m->index; | ||
| 113 | p = m->op->start(m, &pos); | ||
| 114 | err = PTR_ERR(p); | 114 | err = PTR_ERR(p); |
| 115 | if (!p || IS_ERR(p)) | 115 | if (!p || IS_ERR(p)) |
| 116 | break; | 116 | break; |
| @@ -119,6 +119,11 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
| 119 | break; | 119 | break; |
| 120 | if (unlikely(err)) | 120 | if (unlikely(err)) |
| 121 | m->count = 0; | 121 | m->count = 0; |
| 122 | if (unlikely(!m->count)) { | ||
| 123 | p = m->op->next(m, p, &pos); | ||
| 124 | m->index = pos; | ||
| 125 | continue; | ||
| 126 | } | ||
| 122 | if (m->count < m->size) | 127 | if (m->count < m->size) |
| 123 | goto Fill; | 128 | goto Fill; |
| 124 | m->op->stop(m, p); | 129 | m->op->stop(m, p); |
| @@ -128,6 +133,8 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
| 128 | goto Enomem; | 133 | goto Enomem; |
| 129 | m->count = 0; | 134 | m->count = 0; |
| 130 | m->version = 0; | 135 | m->version = 0; |
| 136 | pos = m->index; | ||
| 137 | p = m->op->start(m, &pos); | ||
| 131 | } | 138 | } |
| 132 | m->op->stop(m, p); | 139 | m->op->stop(m, p); |
| 133 | m->count = 0; | 140 | m->count = 0; |
| @@ -443,6 +450,20 @@ int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) | |||
| 443 | return -1; | 450 | return -1; |
| 444 | } | 451 | } |
| 445 | 452 | ||
| 453 | int seq_bitmap(struct seq_file *m, unsigned long *bits, unsigned int nr_bits) | ||
| 454 | { | ||
| 455 | size_t len = bitmap_scnprintf_len(nr_bits); | ||
| 456 | |||
| 457 | if (m->count + len < m->size) { | ||
| 458 | bitmap_scnprintf(m->buf + m->count, m->size - m->count, | ||
| 459 | bits, nr_bits); | ||
| 460 | m->count += len; | ||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | m->count = m->size; | ||
| 464 | return -1; | ||
| 465 | } | ||
| 466 | |||
| 446 | static void *single_start(struct seq_file *p, loff_t *pos) | 467 | static void *single_start(struct seq_file *p, loff_t *pos) |
| 447 | { | 468 | { |
| 448 | return NULL + (*pos == 0); | 469 | return NULL + (*pos == 0); |
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c index 8182f0542a21..8c177eb7e344 100644 --- a/fs/smbfs/cache.c +++ b/fs/smbfs/cache.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
| 16 | #include <linux/dirent.h> | ||
| 17 | #include <linux/smb_fs.h> | 16 | #include <linux/smb_fs.h> |
| 18 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
| 19 | #include <linux/net.h> | 18 | #include <linux/net.h> |
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 2294783320cb..e4f8d51a5553 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c | |||
| @@ -408,7 +408,7 @@ smb_file_release(struct inode *inode, struct file * file) | |||
| 408 | * privileges, so we need our own check for this. | 408 | * privileges, so we need our own check for this. |
| 409 | */ | 409 | */ |
| 410 | static int | 410 | static int |
| 411 | smb_file_permission(struct inode *inode, int mask, struct nameidata *nd) | 411 | smb_file_permission(struct inode *inode, int mask) |
| 412 | { | 412 | { |
| 413 | int mode = inode->i_mode; | 413 | int mode = inode->i_mode; |
| 414 | int error = 0; | 414 | int error = 0; |
| @@ -417,7 +417,7 @@ smb_file_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
| 417 | 417 | ||
| 418 | /* Look at user permissions */ | 418 | /* Look at user permissions */ |
| 419 | mode >>= 6; | 419 | mode >>= 6; |
| 420 | if ((mode & 7 & mask) != mask) | 420 | if (mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) |
| 421 | error = -EACCES; | 421 | error = -EACCES; |
| 422 | return error; | 422 | return error; |
| 423 | } | 423 | } |
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 376ef3ee6ed7..3528f40ffb0f 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c | |||
| @@ -67,7 +67,7 @@ static void smb_destroy_inode(struct inode *inode) | |||
| 67 | kmem_cache_free(smb_inode_cachep, SMB_I(inode)); | 67 | kmem_cache_free(smb_inode_cachep, SMB_I(inode)); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | static void init_once(struct kmem_cache *cachep, void *foo) | 70 | static void init_once(void *foo) |
| 71 | { | 71 | { |
| 72 | struct smb_inode_info *ei = (struct smb_inode_info *) foo; | 72 | struct smb_inode_info *ei = (struct smb_inode_info *) foo; |
| 73 | 73 | ||
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index d517a27b7f4b..ee536e8a649a 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
| 17 | #include <linux/fcntl.h> | 17 | #include <linux/fcntl.h> |
| 18 | #include <linux/dcache.h> | 18 | #include <linux/dcache.h> |
| 19 | #include <linux/dirent.h> | ||
| 20 | #include <linux/nls.h> | 19 | #include <linux/nls.h> |
| 21 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 22 | #include <linux/net.h> | 21 | #include <linux/net.h> |
diff --git a/fs/splice.c b/fs/splice.c index 399442179d89..1bbc6f4bb09c 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -371,7 +371,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 371 | * for an in-flight io page | 371 | * for an in-flight io page |
| 372 | */ | 372 | */ |
| 373 | if (flags & SPLICE_F_NONBLOCK) { | 373 | if (flags & SPLICE_F_NONBLOCK) { |
| 374 | if (TestSetPageLocked(page)) { | 374 | if (!trylock_page(page)) { |
| 375 | error = -EAGAIN; | 375 | error = -EAGAIN; |
| 376 | break; | 376 | break; |
| 377 | } | 377 | } |
| @@ -772,7 +772,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, | |||
| 772 | ssize_t ret; | 772 | ssize_t ret; |
| 773 | int err; | 773 | int err; |
| 774 | 774 | ||
| 775 | err = remove_suid(out->f_path.dentry); | 775 | err = file_remove_suid(out); |
| 776 | if (unlikely(err)) | 776 | if (unlikely(err)) |
| 777 | return err; | 777 | return err; |
| 778 | 778 | ||
| @@ -830,7 +830,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
| 830 | ssize_t ret; | 830 | ssize_t ret; |
| 831 | 831 | ||
| 832 | inode_double_lock(inode, pipe->inode); | 832 | inode_double_lock(inode, pipe->inode); |
| 833 | ret = remove_suid(out->f_path.dentry); | 833 | ret = file_remove_suid(out); |
| 834 | if (likely(!ret)) | 834 | if (likely(!ret)) |
| 835 | ret = __splice_from_pipe(pipe, &sd, pipe_to_file); | 835 | ret = __splice_from_pipe(pipe, &sd, pipe_to_file); |
| 836 | inode_double_unlock(inode, pipe->inode); | 836 | inode_double_unlock(inode, pipe->inode); |
| @@ -1161,36 +1161,6 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
| 1161 | } | 1161 | } |
| 1162 | 1162 | ||
| 1163 | /* | 1163 | /* |
| 1164 | * Do a copy-from-user while holding the mmap_semaphore for reading, in a | ||
| 1165 | * manner safe from deadlocking with simultaneous mmap() (grabbing mmap_sem | ||
| 1166 | * for writing) and page faulting on the user memory pointed to by src. | ||
| 1167 | * This assumes that we will very rarely hit the partial != 0 path, or this | ||
| 1168 | * will not be a win. | ||
| 1169 | */ | ||
| 1170 | static int copy_from_user_mmap_sem(void *dst, const void __user *src, size_t n) | ||
| 1171 | { | ||
| 1172 | int partial; | ||
| 1173 | |||
| 1174 | if (!access_ok(VERIFY_READ, src, n)) | ||
| 1175 | return -EFAULT; | ||
| 1176 | |||
| 1177 | pagefault_disable(); | ||
| 1178 | partial = __copy_from_user_inatomic(dst, src, n); | ||
| 1179 | pagefault_enable(); | ||
| 1180 | |||
| 1181 | /* | ||
| 1182 | * Didn't copy everything, drop the mmap_sem and do a faulting copy | ||
| 1183 | */ | ||
| 1184 | if (unlikely(partial)) { | ||
| 1185 | up_read(¤t->mm->mmap_sem); | ||
| 1186 | partial = copy_from_user(dst, src, n); | ||
| 1187 | down_read(¤t->mm->mmap_sem); | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | return partial; | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | /* | ||
| 1194 | * Map an iov into an array of pages and offset/length tupples. With the | 1164 | * Map an iov into an array of pages and offset/length tupples. With the |
| 1195 | * partial_page structure, we can map several non-contiguous ranges into | 1165 | * partial_page structure, we can map several non-contiguous ranges into |
| 1196 | * our ones pages[] map instead of splitting that operation into pieces. | 1166 | * our ones pages[] map instead of splitting that operation into pieces. |
| @@ -1203,8 +1173,6 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
| 1203 | { | 1173 | { |
| 1204 | int buffers = 0, error = 0; | 1174 | int buffers = 0, error = 0; |
| 1205 | 1175 | ||
| 1206 | down_read(¤t->mm->mmap_sem); | ||
| 1207 | |||
| 1208 | while (nr_vecs) { | 1176 | while (nr_vecs) { |
| 1209 | unsigned long off, npages; | 1177 | unsigned long off, npages; |
| 1210 | struct iovec entry; | 1178 | struct iovec entry; |
| @@ -1213,7 +1181,7 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
| 1213 | int i; | 1181 | int i; |
| 1214 | 1182 | ||
| 1215 | error = -EFAULT; | 1183 | error = -EFAULT; |
| 1216 | if (copy_from_user_mmap_sem(&entry, iov, sizeof(entry))) | 1184 | if (copy_from_user(&entry, iov, sizeof(entry))) |
| 1217 | break; | 1185 | break; |
| 1218 | 1186 | ||
| 1219 | base = entry.iov_base; | 1187 | base = entry.iov_base; |
| @@ -1247,9 +1215,8 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
| 1247 | if (npages > PIPE_BUFFERS - buffers) | 1215 | if (npages > PIPE_BUFFERS - buffers) |
| 1248 | npages = PIPE_BUFFERS - buffers; | 1216 | npages = PIPE_BUFFERS - buffers; |
| 1249 | 1217 | ||
| 1250 | error = get_user_pages(current, current->mm, | 1218 | error = get_user_pages_fast((unsigned long)base, npages, |
| 1251 | (unsigned long) base, npages, 0, 0, | 1219 | 0, &pages[buffers]); |
| 1252 | &pages[buffers], NULL); | ||
| 1253 | 1220 | ||
| 1254 | if (unlikely(error <= 0)) | 1221 | if (unlikely(error <= 0)) |
| 1255 | break; | 1222 | break; |
| @@ -1288,8 +1255,6 @@ static int get_iovec_page_array(const struct iovec __user *iov, | |||
| 1288 | iov++; | 1255 | iov++; |
| 1289 | } | 1256 | } |
| 1290 | 1257 | ||
| 1291 | up_read(¤t->mm->mmap_sem); | ||
| 1292 | |||
| 1293 | if (buffers) | 1258 | if (buffers) |
| 1294 | return buffers; | 1259 | return buffers; |
| 1295 | 1260 | ||
| @@ -57,13 +57,13 @@ EXPORT_SYMBOL(vfs_getattr); | |||
| 57 | 57 | ||
| 58 | int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) | 58 | int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) |
| 59 | { | 59 | { |
| 60 | struct nameidata nd; | 60 | struct path path; |
| 61 | int error; | 61 | int error; |
| 62 | 62 | ||
| 63 | error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); | 63 | error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path); |
| 64 | if (!error) { | 64 | if (!error) { |
| 65 | error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat); | 65 | error = vfs_getattr(path.mnt, path.dentry, stat); |
| 66 | path_put(&nd.path); | 66 | path_put(&path); |
| 67 | } | 67 | } |
| 68 | return error; | 68 | return error; |
| 69 | } | 69 | } |
| @@ -77,13 +77,13 @@ EXPORT_SYMBOL(vfs_stat); | |||
| 77 | 77 | ||
| 78 | int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) | 78 | int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) |
| 79 | { | 79 | { |
| 80 | struct nameidata nd; | 80 | struct path path; |
| 81 | int error; | 81 | int error; |
| 82 | 82 | ||
| 83 | error = __user_walk_fd(dfd, name, 0, &nd); | 83 | error = user_path_at(dfd, name, 0, &path); |
| 84 | if (!error) { | 84 | if (!error) { |
| 85 | error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat); | 85 | error = vfs_getattr(path.mnt, path.dentry, stat); |
| 86 | path_put(&nd.path); | 86 | path_put(&path); |
| 87 | } | 87 | } |
| 88 | return error; | 88 | return error; |
| 89 | } | 89 | } |
| @@ -291,29 +291,29 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) | |||
| 291 | return error; | 291 | return error; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | asmlinkage long sys_readlinkat(int dfd, const char __user *path, | 294 | asmlinkage long sys_readlinkat(int dfd, const char __user *pathname, |
| 295 | char __user *buf, int bufsiz) | 295 | char __user *buf, int bufsiz) |
| 296 | { | 296 | { |
| 297 | struct nameidata nd; | 297 | struct path path; |
| 298 | int error; | 298 | int error; |
| 299 | 299 | ||
| 300 | if (bufsiz <= 0) | 300 | if (bufsiz <= 0) |
| 301 | return -EINVAL; | 301 | return -EINVAL; |
| 302 | 302 | ||
| 303 | error = __user_walk_fd(dfd, path, 0, &nd); | 303 | error = user_path_at(dfd, pathname, 0, &path); |
| 304 | if (!error) { | 304 | if (!error) { |
| 305 | struct inode *inode = nd.path.dentry->d_inode; | 305 | struct inode *inode = path.dentry->d_inode; |
| 306 | 306 | ||
| 307 | error = -EINVAL; | 307 | error = -EINVAL; |
| 308 | if (inode->i_op && inode->i_op->readlink) { | 308 | if (inode->i_op && inode->i_op->readlink) { |
| 309 | error = security_inode_readlink(nd.path.dentry); | 309 | error = security_inode_readlink(path.dentry); |
| 310 | if (!error) { | 310 | if (!error) { |
| 311 | touch_atime(nd.path.mnt, nd.path.dentry); | 311 | touch_atime(path.mnt, path.dentry); |
| 312 | error = inode->i_op->readlink(nd.path.dentry, | 312 | error = inode->i_op->readlink(path.dentry, |
| 313 | buf, bufsiz); | 313 | buf, bufsiz); |
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | path_put(&nd.path); | 316 | path_put(&path); |
| 317 | } | 317 | } |
| 318 | return error; | 318 | return error; |
| 319 | } | 319 | } |
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index c1a7efb310bf..aedaeba82ae5 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
| @@ -459,11 +459,8 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd) | |||
| 459 | int ret; | 459 | int ret; |
| 460 | 460 | ||
| 461 | ret = __sysfs_add_one(acxt, sd); | 461 | ret = __sysfs_add_one(acxt, sd); |
| 462 | if (ret == -EEXIST) { | 462 | WARN(ret == -EEXIST, KERN_WARNING "sysfs: duplicate filename '%s' " |
| 463 | printk(KERN_WARNING "sysfs: duplicate filename '%s' " | ||
| 464 | "can not be created\n", sd->s_name); | 463 | "can not be created\n", sd->s_name); |
| 465 | WARN_ON(1); | ||
| 466 | } | ||
| 467 | return ret; | 464 | return ret; |
| 468 | } | 465 | } |
| 469 | 466 | ||
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 3f07893ff896..c9e4e5091da1 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
| @@ -337,9 +337,8 @@ static int sysfs_open_file(struct inode *inode, struct file *file) | |||
| 337 | if (kobj->ktype && kobj->ktype->sysfs_ops) | 337 | if (kobj->ktype && kobj->ktype->sysfs_ops) |
| 338 | ops = kobj->ktype->sysfs_ops; | 338 | ops = kobj->ktype->sysfs_ops; |
| 339 | else { | 339 | else { |
| 340 | printk(KERN_ERR "missing sysfs attribute operations for " | 340 | WARN(1, KERN_ERR "missing sysfs attribute operations for " |
| 341 | "kobject: %s\n", kobject_name(kobj)); | 341 | "kobject: %s\n", kobject_name(kobj)); |
| 342 | WARN_ON(1); | ||
| 343 | goto err_out; | 342 | goto err_out; |
| 344 | } | 343 | } |
| 345 | 344 | ||
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index eeba38417b1d..fe611949a7f7 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c | |||
| @@ -134,9 +134,8 @@ void sysfs_remove_group(struct kobject * kobj, | |||
| 134 | if (grp->name) { | 134 | if (grp->name) { |
| 135 | sd = sysfs_get_dirent(dir_sd, grp->name); | 135 | sd = sysfs_get_dirent(dir_sd, grp->name); |
| 136 | if (!sd) { | 136 | if (!sd) { |
| 137 | printk(KERN_WARNING "sysfs group %p not found for " | 137 | WARN(!sd, KERN_WARNING "sysfs group %p not found for " |
| 138 | "kobject '%s'\n", grp, kobject_name(kobj)); | 138 | "kobject '%s'\n", grp, kobject_name(kobj)); |
| 139 | WARN_ON(!sd); | ||
| 140 | return; | 139 | return; |
| 141 | } | 140 | } |
| 142 | } else | 141 | } else |
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index c5d60de0658f..df0d435baa48 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c | |||
| @@ -326,7 +326,7 @@ static void sysv_destroy_inode(struct inode *inode) | |||
| 326 | kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); | 326 | kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); |
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | static void init_once(struct kmem_cache *cachep, void *p) | 329 | static void init_once(void *p) |
| 330 | { | 330 | { |
| 331 | struct sysv_inode_info *si = (struct sysv_inode_info *)p; | 331 | struct sysv_inode_info *si = (struct sysv_inode_info *)p; |
| 332 | 332 | ||
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index d81fb9ed2b8e..73db464cd08b 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c | |||
| @@ -263,8 +263,8 @@ int ubifs_calc_min_idx_lebs(struct ubifs_info *c) | |||
| 263 | 263 | ||
| 264 | idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx; | 264 | idx_size = c->old_idx_sz + c->budg_idx_growth + c->budg_uncommitted_idx; |
| 265 | 265 | ||
| 266 | /* And make sure we have twice the index size of space reserved */ | 266 | /* And make sure we have thrice the index size of space reserved */ |
| 267 | idx_size <<= 1; | 267 | idx_size = idx_size + (idx_size << 1); |
| 268 | 268 | ||
| 269 | /* | 269 | /* |
| 270 | * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes' | 270 | * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes' |
| @@ -302,18 +302,6 @@ long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs) | |||
| 302 | int subtract_lebs; | 302 | int subtract_lebs; |
| 303 | long long available; | 303 | long long available; |
| 304 | 304 | ||
| 305 | /* | ||
| 306 | * Force the amount available to the total size reported if the used | ||
| 307 | * space is zero. | ||
| 308 | */ | ||
| 309 | if (c->lst.total_used <= UBIFS_INO_NODE_SZ && | ||
| 310 | c->budg_data_growth + c->budg_dd_growth == 0) { | ||
| 311 | /* Do the same calculation as for c->block_cnt */ | ||
| 312 | available = c->main_lebs - 2; | ||
| 313 | available *= c->leb_size - c->dark_wm; | ||
| 314 | return available; | ||
| 315 | } | ||
| 316 | |||
| 317 | available = c->main_bytes - c->lst.total_used; | 305 | available = c->main_bytes - c->lst.total_used; |
| 318 | 306 | ||
| 319 | /* | 307 | /* |
| @@ -388,11 +376,11 @@ static int can_use_rp(struct ubifs_info *c) | |||
| 388 | * This function makes sure UBIFS has enough free eraseblocks for index growth | 376 | * This function makes sure UBIFS has enough free eraseblocks for index growth |
| 389 | * and data. | 377 | * and data. |
| 390 | * | 378 | * |
| 391 | * When budgeting index space, UBIFS reserves twice as more LEBs as the index | 379 | * When budgeting index space, UBIFS reserves thrice as many LEBs as the index |
| 392 | * would take if it was consolidated and written to the flash. This guarantees | 380 | * would take if it was consolidated and written to the flash. This guarantees |
| 393 | * that the "in-the-gaps" commit method always succeeds and UBIFS will always | 381 | * that the "in-the-gaps" commit method always succeeds and UBIFS will always |
| 394 | * be able to commit dirty index. So this function basically adds amount of | 382 | * be able to commit dirty index. So this function basically adds amount of |
| 395 | * budgeted index space to the size of the current index, multiplies this by 2, | 383 | * budgeted index space to the size of the current index, multiplies this by 3, |
| 396 | * and makes sure this does not exceed the amount of free eraseblocks. | 384 | * and makes sure this does not exceed the amount of free eraseblocks. |
| 397 | * | 385 | * |
| 398 | * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables: | 386 | * Notes about @c->min_idx_lebs and @c->lst.idx_lebs variables: |
| @@ -543,8 +531,16 @@ int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req) | |||
| 543 | int err, idx_growth, data_growth, dd_growth; | 531 | int err, idx_growth, data_growth, dd_growth; |
| 544 | struct retries_info ri; | 532 | struct retries_info ri; |
| 545 | 533 | ||
| 534 | ubifs_assert(req->new_page <= 1); | ||
| 535 | ubifs_assert(req->dirtied_page <= 1); | ||
| 536 | ubifs_assert(req->new_dent <= 1); | ||
| 537 | ubifs_assert(req->mod_dent <= 1); | ||
| 538 | ubifs_assert(req->new_ino <= 1); | ||
| 539 | ubifs_assert(req->new_ino_d <= UBIFS_MAX_INO_DATA); | ||
| 546 | ubifs_assert(req->dirtied_ino <= 4); | 540 | ubifs_assert(req->dirtied_ino <= 4); |
| 547 | ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); | 541 | ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); |
| 542 | ubifs_assert(!(req->new_ino_d & 7)); | ||
| 543 | ubifs_assert(!(req->dirtied_ino_d & 7)); | ||
| 548 | 544 | ||
| 549 | data_growth = calc_data_growth(c, req); | 545 | data_growth = calc_data_growth(c, req); |
| 550 | dd_growth = calc_dd_growth(c, req); | 546 | dd_growth = calc_dd_growth(c, req); |
| @@ -618,8 +614,16 @@ again: | |||
| 618 | */ | 614 | */ |
| 619 | void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) | 615 | void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) |
| 620 | { | 616 | { |
| 617 | ubifs_assert(req->new_page <= 1); | ||
| 618 | ubifs_assert(req->dirtied_page <= 1); | ||
| 619 | ubifs_assert(req->new_dent <= 1); | ||
| 620 | ubifs_assert(req->mod_dent <= 1); | ||
| 621 | ubifs_assert(req->new_ino <= 1); | ||
| 622 | ubifs_assert(req->new_ino_d <= UBIFS_MAX_INO_DATA); | ||
| 621 | ubifs_assert(req->dirtied_ino <= 4); | 623 | ubifs_assert(req->dirtied_ino <= 4); |
| 622 | ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); | 624 | ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); |
| 625 | ubifs_assert(!(req->new_ino_d & 7)); | ||
| 626 | ubifs_assert(!(req->dirtied_ino_d & 7)); | ||
| 623 | if (!req->recalculate) { | 627 | if (!req->recalculate) { |
| 624 | ubifs_assert(req->idx_growth >= 0); | 628 | ubifs_assert(req->idx_growth >= 0); |
| 625 | ubifs_assert(req->data_growth >= 0); | 629 | ubifs_assert(req->data_growth >= 0); |
| @@ -647,7 +651,11 @@ void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) | |||
| 647 | 651 | ||
| 648 | ubifs_assert(c->budg_idx_growth >= 0); | 652 | ubifs_assert(c->budg_idx_growth >= 0); |
| 649 | ubifs_assert(c->budg_data_growth >= 0); | 653 | ubifs_assert(c->budg_data_growth >= 0); |
| 654 | ubifs_assert(c->budg_dd_growth >= 0); | ||
| 650 | ubifs_assert(c->min_idx_lebs < c->main_lebs); | 655 | ubifs_assert(c->min_idx_lebs < c->main_lebs); |
| 656 | ubifs_assert(!(c->budg_idx_growth & 7)); | ||
| 657 | ubifs_assert(!(c->budg_data_growth & 7)); | ||
| 658 | ubifs_assert(!(c->budg_dd_growth & 7)); | ||
| 651 | spin_unlock(&c->space_lock); | 659 | spin_unlock(&c->space_lock); |
| 652 | } | 660 | } |
| 653 | 661 | ||
| @@ -686,41 +694,114 @@ void ubifs_convert_page_budget(struct ubifs_info *c) | |||
| 686 | void ubifs_release_dirty_inode_budget(struct ubifs_info *c, | 694 | void ubifs_release_dirty_inode_budget(struct ubifs_info *c, |
| 687 | struct ubifs_inode *ui) | 695 | struct ubifs_inode *ui) |
| 688 | { | 696 | { |
| 689 | struct ubifs_budget_req req = {.dd_growth = c->inode_budget, | 697 | struct ubifs_budget_req req; |
| 690 | .dirtied_ino_d = ui->data_len}; | ||
| 691 | 698 | ||
| 699 | memset(&req, 0, sizeof(struct ubifs_budget_req)); | ||
| 700 | req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8); | ||
| 692 | ubifs_release_budget(c, &req); | 701 | ubifs_release_budget(c, &req); |
| 693 | } | 702 | } |
| 694 | 703 | ||
| 695 | /** | 704 | /** |
| 696 | * ubifs_budg_get_free_space - return amount of free space. | 705 | * ubifs_reported_space - calculate reported free space. |
| 706 | * @c: the UBIFS file-system description object | ||
| 707 | * @free: amount of free space | ||
| 708 | * | ||
| 709 | * This function calculates amount of free space which will be reported to | ||
| 710 | * user-space. User-space application tend to expect that if the file-system | ||
| 711 | * (e.g., via the 'statfs()' call) reports that it has N bytes available, they | ||
| 712 | * are able to write a file of size N. UBIFS attaches node headers to each data | ||
| 713 | * node and it has to write indexind nodes as well. This introduces additional | ||
| 714 | * overhead, and UBIFS it has to report sligtly less free space to meet the | ||
| 715 | * above expectetion. | ||
| 716 | * | ||
| 717 | * This function assumes free space is made up of uncompressed data nodes and | ||
| 718 | * full index nodes (one per data node, tripled because we always allow enough | ||
| 719 | * space to write the index thrice). | ||
| 720 | * | ||
| 721 | * Note, the calculation is pessimistic, which means that most of the time | ||
| 722 | * UBIFS reports less space than it actually has. | ||
| 723 | */ | ||
| 724 | long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free) | ||
| 725 | { | ||
| 726 | int divisor, factor, f; | ||
| 727 | |||
| 728 | /* | ||
| 729 | * Reported space size is @free * X, where X is UBIFS block size | ||
| 730 | * divided by UBIFS block size + all overhead one data block | ||
| 731 | * introduces. The overhead is the node header + indexing overhead. | ||
| 732 | * | ||
| 733 | * Indexing overhead calculations are based on the following formula: | ||
| 734 | * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number | ||
| 735 | * of data nodes, f - fanout. Because effective UBIFS fanout is twice | ||
| 736 | * as less than maximum fanout, we assume that each data node | ||
| 737 | * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes. | ||
| 738 | * Note, the multiplier 3 is because UBIFS reseves thrice as more space | ||
| 739 | * for the index. | ||
| 740 | */ | ||
| 741 | f = c->fanout > 3 ? c->fanout >> 1 : 2; | ||
| 742 | factor = UBIFS_BLOCK_SIZE; | ||
| 743 | divisor = UBIFS_MAX_DATA_NODE_SZ; | ||
| 744 | divisor += (c->max_idx_node_sz * 3) / (f - 1); | ||
| 745 | free *= factor; | ||
| 746 | do_div(free, divisor); | ||
| 747 | return free; | ||
| 748 | } | ||
| 749 | |||
| 750 | /** | ||
| 751 | * ubifs_get_free_space - return amount of free space. | ||
| 697 | * @c: UBIFS file-system description object | 752 | * @c: UBIFS file-system description object |
| 698 | * | 753 | * |
| 699 | * This function returns amount of free space on the file-system. | 754 | * This function calculates amount of free space to report to user-space. |
| 755 | * | ||
| 756 | * Because UBIFS may introduce substantial overhead (the index, node headers, | ||
| 757 | * alighment, wastage at the end of eraseblocks, etc), it cannot report real | ||
| 758 | * amount of free flash space it has (well, because not all dirty space is | ||
| 759 | * reclamable, UBIFS does not actually know the real amount). If UBIFS did so, | ||
| 760 | * it would bread user expectetion about what free space is. Users seem to | ||
| 761 | * accustomed to assume that if the file-system reports N bytes of free space, | ||
| 762 | * they would be able to fit a file of N bytes to the FS. This almost works for | ||
| 763 | * traditional file-systems, because they have way less overhead than UBIFS. | ||
| 764 | * So, to keep users happy, UBIFS tries to take the overhead into account. | ||
| 700 | */ | 765 | */ |
| 701 | long long ubifs_budg_get_free_space(struct ubifs_info *c) | 766 | long long ubifs_get_free_space(struct ubifs_info *c) |
| 702 | { | 767 | { |
| 703 | int min_idx_lebs, rsvd_idx_lebs; | 768 | int min_idx_lebs, rsvd_idx_lebs, lebs; |
| 704 | long long available, outstanding, free; | 769 | long long available, outstanding, free; |
| 705 | 770 | ||
| 706 | /* Do exactly the same calculations as in 'do_budget_space()' */ | ||
| 707 | spin_lock(&c->space_lock); | 771 | spin_lock(&c->space_lock); |
| 708 | min_idx_lebs = ubifs_calc_min_idx_lebs(c); | 772 | min_idx_lebs = ubifs_calc_min_idx_lebs(c); |
| 773 | outstanding = c->budg_data_growth + c->budg_dd_growth; | ||
| 709 | 774 | ||
| 710 | if (min_idx_lebs > c->lst.idx_lebs) | 775 | /* |
| 711 | rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; | 776 | * Force the amount available to the total size reported if the used |
| 712 | else | 777 | * space is zero. |
| 713 | rsvd_idx_lebs = 0; | 778 | */ |
| 714 | 779 | if (c->lst.total_used <= UBIFS_INO_NODE_SZ && !outstanding) { | |
| 715 | if (rsvd_idx_lebs > c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt | ||
| 716 | - c->lst.taken_empty_lebs) { | ||
| 717 | spin_unlock(&c->space_lock); | 780 | spin_unlock(&c->space_lock); |
| 718 | return 0; | 781 | return (long long)c->block_cnt << UBIFS_BLOCK_SHIFT; |
| 719 | } | 782 | } |
| 720 | 783 | ||
| 721 | available = ubifs_calc_available(c, min_idx_lebs); | 784 | available = ubifs_calc_available(c, min_idx_lebs); |
| 722 | outstanding = c->budg_data_growth + c->budg_dd_growth; | 785 | |
| 723 | c->min_idx_lebs = min_idx_lebs; | 786 | /* |
| 787 | * When reporting free space to user-space, UBIFS guarantees that it is | ||
| 788 | * possible to write a file of free space size. This means that for | ||
| 789 | * empty LEBs we may use more precise calculations than | ||
| 790 | * 'ubifs_calc_available()' is using. Namely, we know that in empty | ||
| 791 | * LEBs we would waste only @c->leb_overhead bytes, not @c->dark_wm. | ||
| 792 | * Thus, amend the available space. | ||
| 793 | * | ||
| 794 | * Note, the calculations below are similar to what we have in | ||
| 795 | * 'do_budget_space()', so refer there for comments. | ||
| 796 | */ | ||
| 797 | if (min_idx_lebs > c->lst.idx_lebs) | ||
| 798 | rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; | ||
| 799 | else | ||
| 800 | rsvd_idx_lebs = 0; | ||
| 801 | lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - | ||
| 802 | c->lst.taken_empty_lebs; | ||
| 803 | lebs -= rsvd_idx_lebs; | ||
| 804 | available += lebs * (c->dark_wm - c->leb_overhead); | ||
| 724 | spin_unlock(&c->space_lock); | 805 | spin_unlock(&c->space_lock); |
| 725 | 806 | ||
| 726 | if (available > outstanding) | 807 | if (available > outstanding) |
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c index 3b516316c9b3..0a6aa2cc78f0 100644 --- a/fs/ubifs/commit.c +++ b/fs/ubifs/commit.c | |||
| @@ -74,6 +74,7 @@ static int do_commit(struct ubifs_info *c) | |||
| 74 | goto out_up; | 74 | goto out_up; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | c->cmt_no += 1; | ||
| 77 | err = ubifs_gc_start_commit(c); | 78 | err = ubifs_gc_start_commit(c); |
| 78 | if (err) | 79 | if (err) |
| 79 | goto out_up; | 80 | goto out_up; |
| @@ -115,7 +116,7 @@ static int do_commit(struct ubifs_info *c) | |||
| 115 | goto out; | 116 | goto out; |
| 116 | 117 | ||
| 117 | mutex_lock(&c->mst_mutex); | 118 | mutex_lock(&c->mst_mutex); |
| 118 | c->mst_node->cmt_no = cpu_to_le64(++c->cmt_no); | 119 | c->mst_node->cmt_no = cpu_to_le64(c->cmt_no); |
| 119 | c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum); | 120 | c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum); |
| 120 | c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); | 121 | c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); |
| 121 | c->mst_node->root_offs = cpu_to_le32(zroot.offs); | 122 | c->mst_node->root_offs = cpu_to_le32(zroot.offs); |
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index 4e3aaeba4eca..b9cb77473758 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c | |||
| @@ -568,8 +568,8 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req) | |||
| 568 | void dbg_dump_lstats(const struct ubifs_lp_stats *lst) | 568 | void dbg_dump_lstats(const struct ubifs_lp_stats *lst) |
| 569 | { | 569 | { |
| 570 | spin_lock(&dbg_lock); | 570 | spin_lock(&dbg_lock); |
| 571 | printk(KERN_DEBUG "Lprops statistics: empty_lebs %d, idx_lebs %d\n", | 571 | printk(KERN_DEBUG "(pid %d) Lprops statistics: empty_lebs %d, " |
| 572 | lst->empty_lebs, lst->idx_lebs); | 572 | "idx_lebs %d\n", current->pid, lst->empty_lebs, lst->idx_lebs); |
| 573 | printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, " | 573 | printk(KERN_DEBUG "\ttaken_empty_lebs %d, total_free %lld, " |
| 574 | "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free, | 574 | "total_dirty %lld\n", lst->taken_empty_lebs, lst->total_free, |
| 575 | lst->total_dirty); | 575 | lst->total_dirty); |
| @@ -587,8 +587,8 @@ void dbg_dump_budg(struct ubifs_info *c) | |||
| 587 | struct ubifs_gced_idx_leb *idx_gc; | 587 | struct ubifs_gced_idx_leb *idx_gc; |
| 588 | 588 | ||
| 589 | spin_lock(&dbg_lock); | 589 | spin_lock(&dbg_lock); |
| 590 | printk(KERN_DEBUG "Budgeting info: budg_data_growth %lld, " | 590 | printk(KERN_DEBUG "(pid %d) Budgeting info: budg_data_growth %lld, " |
| 591 | "budg_dd_growth %lld, budg_idx_growth %lld\n", | 591 | "budg_dd_growth %lld, budg_idx_growth %lld\n", current->pid, |
| 592 | c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth); | 592 | c->budg_data_growth, c->budg_dd_growth, c->budg_idx_growth); |
| 593 | printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, " | 593 | printk(KERN_DEBUG "\tdata budget sum %lld, total budget sum %lld, " |
| 594 | "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth, | 594 | "freeable_cnt %d\n", c->budg_data_growth + c->budg_dd_growth, |
| @@ -634,7 +634,7 @@ void dbg_dump_lprops(struct ubifs_info *c) | |||
| 634 | struct ubifs_lprops lp; | 634 | struct ubifs_lprops lp; |
| 635 | struct ubifs_lp_stats lst; | 635 | struct ubifs_lp_stats lst; |
| 636 | 636 | ||
| 637 | printk(KERN_DEBUG "Dumping LEB properties\n"); | 637 | printk(KERN_DEBUG "(pid %d) Dumping LEB properties\n", current->pid); |
| 638 | ubifs_get_lp_stats(c, &lst); | 638 | ubifs_get_lp_stats(c, &lst); |
| 639 | dbg_dump_lstats(&lst); | 639 | dbg_dump_lstats(&lst); |
| 640 | 640 | ||
| @@ -655,7 +655,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum) | |||
| 655 | if (dbg_failure_mode) | 655 | if (dbg_failure_mode) |
| 656 | return; | 656 | return; |
| 657 | 657 | ||
| 658 | printk(KERN_DEBUG "Dumping LEB %d\n", lnum); | 658 | printk(KERN_DEBUG "(pid %d) Dumping LEB %d\n", current->pid, lnum); |
| 659 | 659 | ||
| 660 | sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); | 660 | sleb = ubifs_scan(c, lnum, 0, c->dbg_buf); |
| 661 | if (IS_ERR(sleb)) { | 661 | if (IS_ERR(sleb)) { |
| @@ -720,8 +720,8 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat) | |||
| 720 | { | 720 | { |
| 721 | int i; | 721 | int i; |
| 722 | 722 | ||
| 723 | printk(KERN_DEBUG "Dumping heap cat %d (%d elements)\n", | 723 | printk(KERN_DEBUG "(pid %d) Dumping heap cat %d (%d elements)\n", |
| 724 | cat, heap->cnt); | 724 | current->pid, cat, heap->cnt); |
| 725 | for (i = 0; i < heap->cnt; i++) { | 725 | for (i = 0; i < heap->cnt; i++) { |
| 726 | struct ubifs_lprops *lprops = heap->arr[i]; | 726 | struct ubifs_lprops *lprops = heap->arr[i]; |
| 727 | 727 | ||
| @@ -736,7 +736,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode, | |||
| 736 | { | 736 | { |
| 737 | int i; | 737 | int i; |
| 738 | 738 | ||
| 739 | printk(KERN_DEBUG "Dumping pnode:\n"); | 739 | printk(KERN_DEBUG "(pid %d) Dumping pnode:\n", current->pid); |
| 740 | printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", | 740 | printk(KERN_DEBUG "\taddress %zx parent %zx cnext %zx\n", |
| 741 | (size_t)pnode, (size_t)parent, (size_t)pnode->cnext); | 741 | (size_t)pnode, (size_t)parent, (size_t)pnode->cnext); |
| 742 | printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", | 742 | printk(KERN_DEBUG "\tflags %lu iip %d level %d num %d\n", |
| @@ -755,7 +755,7 @@ void dbg_dump_tnc(struct ubifs_info *c) | |||
| 755 | int level; | 755 | int level; |
| 756 | 756 | ||
| 757 | printk(KERN_DEBUG "\n"); | 757 | printk(KERN_DEBUG "\n"); |
| 758 | printk(KERN_DEBUG "Dumping the TNC tree\n"); | 758 | printk(KERN_DEBUG "(pid %d) Dumping the TNC tree\n", current->pid); |
| 759 | znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); | 759 | znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL); |
| 760 | level = znode->level; | 760 | level = znode->level; |
| 761 | printk(KERN_DEBUG "== Level %d ==\n", level); | 761 | printk(KERN_DEBUG "== Level %d ==\n", level); |
| @@ -2208,16 +2208,17 @@ int dbg_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, | |||
| 2208 | int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, | 2208 | int dbg_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, |
| 2209 | int offset, int len, int dtype) | 2209 | int offset, int len, int dtype) |
| 2210 | { | 2210 | { |
| 2211 | int err; | 2211 | int err, failing; |
| 2212 | 2212 | ||
| 2213 | if (in_failure_mode(desc)) | 2213 | if (in_failure_mode(desc)) |
| 2214 | return -EIO; | 2214 | return -EIO; |
| 2215 | if (do_fail(desc, lnum, 1)) | 2215 | failing = do_fail(desc, lnum, 1); |
| 2216 | if (failing) | ||
| 2216 | cut_data(buf, len); | 2217 | cut_data(buf, len); |
| 2217 | err = ubi_leb_write(desc, lnum, buf, offset, len, dtype); | 2218 | err = ubi_leb_write(desc, lnum, buf, offset, len, dtype); |
| 2218 | if (err) | 2219 | if (err) |
| 2219 | return err; | 2220 | return err; |
| 2220 | if (in_failure_mode(desc)) | 2221 | if (failing) |
| 2221 | return -EIO; | 2222 | return -EIO; |
| 2222 | return 0; | 2223 | return 0; |
| 2223 | } | 2224 | } |
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 3c4f1e93c9e0..50315fc57185 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | #define UBIFS_DBG(op) op | 28 | #define UBIFS_DBG(op) op |
| 29 | 29 | ||
| 30 | #define ubifs_assert(expr) do { \ | 30 | #define ubifs_assert(expr) do { \ |
| 31 | if (unlikely(!(expr))) { \ | 31 | if (unlikely(!(expr))) { \ |
| 32 | printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ | 32 | printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ |
| 33 | __func__, __LINE__, current->pid); \ | 33 | __func__, __LINE__, current->pid); \ |
| @@ -73,50 +73,50 @@ const char *dbg_key_str1(const struct ubifs_info *c, | |||
| 73 | const union ubifs_key *key); | 73 | const union ubifs_key *key); |
| 74 | 74 | ||
| 75 | /* | 75 | /* |
| 76 | * DBGKEY macros require dbg_lock to be held, which it is in the dbg message | 76 | * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message |
| 77 | * macros. | 77 | * macros. |
| 78 | */ | 78 | */ |
| 79 | #define DBGKEY(key) dbg_key_str0(c, (key)) | 79 | #define DBGKEY(key) dbg_key_str0(c, (key)) |
| 80 | #define DBGKEY1(key) dbg_key_str1(c, (key)) | 80 | #define DBGKEY1(key) dbg_key_str1(c, (key)) |
| 81 | 81 | ||
| 82 | /* General messages */ | 82 | /* General messages */ |
| 83 | #define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__) | 83 | #define dbg_gen(fmt, ...) dbg_do_msg(UBIFS_MSG_GEN, fmt, ##__VA_ARGS__) |
| 84 | 84 | ||
| 85 | /* Additional journal messages */ | 85 | /* Additional journal messages */ |
| 86 | #define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__) | 86 | #define dbg_jnl(fmt, ...) dbg_do_msg(UBIFS_MSG_JNL, fmt, ##__VA_ARGS__) |
| 87 | 87 | ||
| 88 | /* Additional TNC messages */ | 88 | /* Additional TNC messages */ |
| 89 | #define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__) | 89 | #define dbg_tnc(fmt, ...) dbg_do_msg(UBIFS_MSG_TNC, fmt, ##__VA_ARGS__) |
| 90 | 90 | ||
| 91 | /* Additional lprops messages */ | 91 | /* Additional lprops messages */ |
| 92 | #define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__) | 92 | #define dbg_lp(fmt, ...) dbg_do_msg(UBIFS_MSG_LP, fmt, ##__VA_ARGS__) |
| 93 | 93 | ||
| 94 | /* Additional LEB find messages */ | 94 | /* Additional LEB find messages */ |
| 95 | #define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__) | 95 | #define dbg_find(fmt, ...) dbg_do_msg(UBIFS_MSG_FIND, fmt, ##__VA_ARGS__) |
| 96 | 96 | ||
| 97 | /* Additional mount messages */ | 97 | /* Additional mount messages */ |
| 98 | #define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__) | 98 | #define dbg_mnt(fmt, ...) dbg_do_msg(UBIFS_MSG_MNT, fmt, ##__VA_ARGS__) |
| 99 | 99 | ||
| 100 | /* Additional I/O messages */ | 100 | /* Additional I/O messages */ |
| 101 | #define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__) | 101 | #define dbg_io(fmt, ...) dbg_do_msg(UBIFS_MSG_IO, fmt, ##__VA_ARGS__) |
| 102 | 102 | ||
| 103 | /* Additional commit messages */ | 103 | /* Additional commit messages */ |
| 104 | #define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__) | 104 | #define dbg_cmt(fmt, ...) dbg_do_msg(UBIFS_MSG_CMT, fmt, ##__VA_ARGS__) |
| 105 | 105 | ||
| 106 | /* Additional budgeting messages */ | 106 | /* Additional budgeting messages */ |
| 107 | #define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__) | 107 | #define dbg_budg(fmt, ...) dbg_do_msg(UBIFS_MSG_BUDG, fmt, ##__VA_ARGS__) |
| 108 | 108 | ||
| 109 | /* Additional log messages */ | 109 | /* Additional log messages */ |
| 110 | #define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__) | 110 | #define dbg_log(fmt, ...) dbg_do_msg(UBIFS_MSG_LOG, fmt, ##__VA_ARGS__) |
| 111 | 111 | ||
| 112 | /* Additional gc messages */ | 112 | /* Additional gc messages */ |
| 113 | #define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__) | 113 | #define dbg_gc(fmt, ...) dbg_do_msg(UBIFS_MSG_GC, fmt, ##__VA_ARGS__) |
| 114 | 114 | ||
| 115 | /* Additional scan messages */ | 115 | /* Additional scan messages */ |
| 116 | #define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__) | 116 | #define dbg_scan(fmt, ...) dbg_do_msg(UBIFS_MSG_SCAN, fmt, ##__VA_ARGS__) |
| 117 | 117 | ||
| 118 | /* Additional recovery messages */ | 118 | /* Additional recovery messages */ |
| 119 | #define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__) | 119 | #define dbg_rcvry(fmt, ...) dbg_do_msg(UBIFS_MSG_RCVRY, fmt, ##__VA_ARGS__) |
| 120 | 120 | ||
| 121 | /* | 121 | /* |
| 122 | * Debugging message type flags (must match msg_type_names in debug.c). | 122 | * Debugging message type flags (must match msg_type_names in debug.c). |
| @@ -239,34 +239,23 @@ typedef int (*dbg_leaf_callback)(struct ubifs_info *c, | |||
| 239 | struct ubifs_zbranch *zbr, void *priv); | 239 | struct ubifs_zbranch *zbr, void *priv); |
| 240 | typedef int (*dbg_znode_callback)(struct ubifs_info *c, | 240 | typedef int (*dbg_znode_callback)(struct ubifs_info *c, |
| 241 | struct ubifs_znode *znode, void *priv); | 241 | struct ubifs_znode *znode, void *priv); |
| 242 | |||
| 243 | int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, | 242 | int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb, |
| 244 | dbg_znode_callback znode_cb, void *priv); | 243 | dbg_znode_callback znode_cb, void *priv); |
| 245 | 244 | ||
| 246 | /* Checking functions */ | 245 | /* Checking functions */ |
| 247 | 246 | ||
| 248 | int dbg_check_lprops(struct ubifs_info *c); | 247 | int dbg_check_lprops(struct ubifs_info *c); |
| 249 | |||
| 250 | int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot); | 248 | int dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot); |
| 251 | int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); | 249 | int dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot); |
| 252 | |||
| 253 | int dbg_check_cats(struct ubifs_info *c); | 250 | int dbg_check_cats(struct ubifs_info *c); |
| 254 | |||
| 255 | int dbg_check_ltab(struct ubifs_info *c); | 251 | int dbg_check_ltab(struct ubifs_info *c); |
| 256 | |||
| 257 | int dbg_check_synced_i_size(struct inode *inode); | 252 | int dbg_check_synced_i_size(struct inode *inode); |
| 258 | |||
| 259 | int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); | 253 | int dbg_check_dir_size(struct ubifs_info *c, const struct inode *dir); |
| 260 | |||
| 261 | int dbg_check_tnc(struct ubifs_info *c, int extra); | 254 | int dbg_check_tnc(struct ubifs_info *c, int extra); |
| 262 | |||
| 263 | int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); | 255 | int dbg_check_idx_size(struct ubifs_info *c, long long idx_size); |
| 264 | |||
| 265 | int dbg_check_filesystem(struct ubifs_info *c); | 256 | int dbg_check_filesystem(struct ubifs_info *c); |
| 266 | |||
| 267 | void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, | 257 | void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat, |
| 268 | int add_pos); | 258 | int add_pos); |
| 269 | |||
| 270 | int dbg_check_lprops(struct ubifs_info *c); | 259 | int dbg_check_lprops(struct ubifs_info *c); |
| 271 | int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, | 260 | int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode, |
| 272 | int row, int col); | 261 | int row, int col); |
| @@ -329,71 +318,77 @@ static inline int dbg_change(struct ubi_volume_desc *desc, int lnum, | |||
| 329 | #else /* !CONFIG_UBIFS_FS_DEBUG */ | 318 | #else /* !CONFIG_UBIFS_FS_DEBUG */ |
| 330 | 319 | ||
| 331 | #define UBIFS_DBG(op) | 320 | #define UBIFS_DBG(op) |
| 332 | #define ubifs_assert(expr) ({}) | 321 | |
| 333 | #define ubifs_assert_cmt_locked(c) | 322 | /* Use "if (0)" to make compiler check arguments even if debugging is off */ |
| 323 | #define ubifs_assert(expr) do { \ | ||
| 324 | if (0 && (expr)) \ | ||
| 325 | printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \ | ||
| 326 | __func__, __LINE__, current->pid); \ | ||
| 327 | } while (0) | ||
| 328 | |||
| 329 | #define dbg_err(fmt, ...) do { \ | ||
| 330 | if (0) \ | ||
| 331 | ubifs_err(fmt, ##__VA_ARGS__); \ | ||
| 332 | } while (0) | ||
| 333 | |||
| 334 | #define dbg_msg(fmt, ...) do { \ | ||
| 335 | if (0) \ | ||
| 336 | printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", \ | ||
| 337 | current->pid, __func__, ##__VA_ARGS__); \ | ||
| 338 | } while (0) | ||
| 339 | |||
| 334 | #define dbg_dump_stack() | 340 | #define dbg_dump_stack() |
| 335 | #define dbg_err(fmt, ...) ({}) | 341 | #define ubifs_assert_cmt_locked(c) |
| 336 | #define dbg_msg(fmt, ...) ({}) | ||
| 337 | #define dbg_key(c, key, fmt, ...) ({}) | ||
| 338 | |||
| 339 | #define dbg_gen(fmt, ...) ({}) | ||
| 340 | #define dbg_jnl(fmt, ...) ({}) | ||
| 341 | #define dbg_tnc(fmt, ...) ({}) | ||
| 342 | #define dbg_lp(fmt, ...) ({}) | ||
| 343 | #define dbg_find(fmt, ...) ({}) | ||
| 344 | #define dbg_mnt(fmt, ...) ({}) | ||
| 345 | #define dbg_io(fmt, ...) ({}) | ||
| 346 | #define dbg_cmt(fmt, ...) ({}) | ||
| 347 | #define dbg_budg(fmt, ...) ({}) | ||
| 348 | #define dbg_log(fmt, ...) ({}) | ||
| 349 | #define dbg_gc(fmt, ...) ({}) | ||
| 350 | #define dbg_scan(fmt, ...) ({}) | ||
| 351 | #define dbg_rcvry(fmt, ...) ({}) | ||
| 352 | |||
| 353 | #define dbg_ntype(type) "" | ||
| 354 | #define dbg_cstate(cmt_state) "" | ||
| 355 | #define dbg_get_key_dump(c, key) ({}) | ||
| 356 | #define dbg_dump_inode(c, inode) ({}) | ||
| 357 | #define dbg_dump_node(c, node) ({}) | ||
| 358 | #define dbg_dump_budget_req(req) ({}) | ||
| 359 | #define dbg_dump_lstats(lst) ({}) | ||
| 360 | #define dbg_dump_budg(c) ({}) | ||
| 361 | #define dbg_dump_lprop(c, lp) ({}) | ||
| 362 | #define dbg_dump_lprops(c) ({}) | ||
| 363 | #define dbg_dump_leb(c, lnum) ({}) | ||
| 364 | #define dbg_dump_znode(c, znode) ({}) | ||
| 365 | #define dbg_dump_heap(c, heap, cat) ({}) | ||
| 366 | #define dbg_dump_pnode(c, pnode, parent, iip) ({}) | ||
| 367 | #define dbg_dump_tnc(c) ({}) | ||
| 368 | #define dbg_dump_index(c) ({}) | ||
| 369 | 342 | ||
| 370 | #define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0 | 343 | #define dbg_gen(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) |
| 344 | #define dbg_jnl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 345 | #define dbg_tnc(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 346 | #define dbg_lp(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 347 | #define dbg_find(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 348 | #define dbg_mnt(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 349 | #define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 350 | #define dbg_cmt(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 351 | #define dbg_budg(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 352 | #define dbg_log(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 353 | #define dbg_gc(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 354 | #define dbg_scan(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 355 | #define dbg_rcvry(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) | ||
| 356 | |||
| 357 | #define DBGKEY(key) ((char *)(key)) | ||
| 358 | #define DBGKEY1(key) ((char *)(key)) | ||
| 359 | |||
| 360 | #define dbg_ntype(type) "" | ||
| 361 | #define dbg_cstate(cmt_state) "" | ||
| 362 | #define dbg_get_key_dump(c, key) ({}) | ||
| 363 | #define dbg_dump_inode(c, inode) ({}) | ||
| 364 | #define dbg_dump_node(c, node) ({}) | ||
| 365 | #define dbg_dump_budget_req(req) ({}) | ||
| 366 | #define dbg_dump_lstats(lst) ({}) | ||
| 367 | #define dbg_dump_budg(c) ({}) | ||
| 368 | #define dbg_dump_lprop(c, lp) ({}) | ||
| 369 | #define dbg_dump_lprops(c) ({}) | ||
| 370 | #define dbg_dump_leb(c, lnum) ({}) | ||
| 371 | #define dbg_dump_znode(c, znode) ({}) | ||
| 372 | #define dbg_dump_heap(c, heap, cat) ({}) | ||
| 373 | #define dbg_dump_pnode(c, pnode, parent, iip) ({}) | ||
| 374 | #define dbg_dump_tnc(c) ({}) | ||
| 375 | #define dbg_dump_index(c) ({}) | ||
| 371 | 376 | ||
| 377 | #define dbg_walk_index(c, leaf_cb, znode_cb, priv) 0 | ||
| 372 | #define dbg_old_index_check_init(c, zroot) 0 | 378 | #define dbg_old_index_check_init(c, zroot) 0 |
| 373 | #define dbg_check_old_index(c, zroot) 0 | 379 | #define dbg_check_old_index(c, zroot) 0 |
| 374 | |||
| 375 | #define dbg_check_cats(c) 0 | 380 | #define dbg_check_cats(c) 0 |
| 376 | |||
| 377 | #define dbg_check_ltab(c) 0 | 381 | #define dbg_check_ltab(c) 0 |
| 378 | |||
| 379 | #define dbg_check_synced_i_size(inode) 0 | 382 | #define dbg_check_synced_i_size(inode) 0 |
| 380 | |||
| 381 | #define dbg_check_dir_size(c, dir) 0 | 383 | #define dbg_check_dir_size(c, dir) 0 |
| 382 | |||
| 383 | #define dbg_check_tnc(c, x) 0 | 384 | #define dbg_check_tnc(c, x) 0 |
| 384 | |||
| 385 | #define dbg_check_idx_size(c, idx_size) 0 | 385 | #define dbg_check_idx_size(c, idx_size) 0 |
| 386 | |||
| 387 | #define dbg_check_filesystem(c) 0 | 386 | #define dbg_check_filesystem(c) 0 |
| 388 | |||
| 389 | #define dbg_check_heap(c, heap, cat, add_pos) ({}) | 387 | #define dbg_check_heap(c, heap, cat, add_pos) ({}) |
| 390 | |||
| 391 | #define dbg_check_lprops(c) 0 | 388 | #define dbg_check_lprops(c) 0 |
| 392 | #define dbg_check_lpt_nodes(c, cnode, row, col) 0 | 389 | #define dbg_check_lpt_nodes(c, cnode, row, col) 0 |
| 393 | |||
| 394 | #define dbg_force_in_the_gaps_enabled 0 | 390 | #define dbg_force_in_the_gaps_enabled 0 |
| 395 | #define dbg_force_in_the_gaps() 0 | 391 | #define dbg_force_in_the_gaps() 0 |
| 396 | |||
| 397 | #define dbg_failure_mode 0 | 392 | #define dbg_failure_mode 0 |
| 398 | #define dbg_failure_mode_registration(c) ({}) | 393 | #define dbg_failure_mode_registration(c) ({}) |
| 399 | #define dbg_failure_mode_deregistration(c) ({}) | 394 | #define dbg_failure_mode_deregistration(c) ({}) |
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index e90374be7d3b..2b267c9a1806 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c | |||
| @@ -165,7 +165,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, | |||
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | inode->i_ino = ++c->highest_inum; | 167 | inode->i_ino = ++c->highest_inum; |
| 168 | inode->i_generation = ++c->vfs_gen; | ||
| 169 | /* | 168 | /* |
| 170 | * The creation sequence number remains with this inode for its | 169 | * The creation sequence number remains with this inode for its |
| 171 | * lifetime. All nodes for this inode have a greater sequence number, | 170 | * lifetime. All nodes for this inode have a greater sequence number, |
| @@ -220,15 +219,7 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 220 | 219 | ||
| 221 | err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name); | 220 | err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name); |
| 222 | if (err) { | 221 | if (err) { |
| 223 | /* | 222 | if (err == -ENOENT) { |
| 224 | * Do not hash the direntry if parent 'i_nlink' is zero, because | ||
| 225 | * this has side-effects - '->delete_inode()' call will not be | ||
| 226 | * called for the parent orphan inode, because 'd_count' of its | ||
| 227 | * direntry will stay 1 (it'll be negative direntry I guess) | ||
| 228 | * and prevent 'iput_final()' until the dentry is destroyed due | ||
| 229 | * to unmount or memory pressure. | ||
| 230 | */ | ||
| 231 | if (err == -ENOENT && dir->i_nlink != 0) { | ||
| 232 | dbg_gen("not found"); | 223 | dbg_gen("not found"); |
| 233 | goto done; | 224 | goto done; |
| 234 | } | 225 | } |
| @@ -525,7 +516,7 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 525 | struct ubifs_inode *dir_ui = ubifs_inode(dir); | 516 | struct ubifs_inode *dir_ui = ubifs_inode(dir); |
| 526 | int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); | 517 | int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); |
| 527 | struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, | 518 | struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, |
| 528 | .dirtied_ino_d = ui->data_len }; | 519 | .dirtied_ino_d = ALIGN(ui->data_len, 8) }; |
| 529 | 520 | ||
| 530 | /* | 521 | /* |
| 531 | * Budget request settings: new direntry, changing the target inode, | 522 | * Budget request settings: new direntry, changing the target inode, |
| @@ -596,7 +587,6 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 596 | if (err) { | 587 | if (err) { |
| 597 | if (err != -ENOSPC) | 588 | if (err != -ENOSPC) |
| 598 | return err; | 589 | return err; |
| 599 | err = 0; | ||
| 600 | budgeted = 0; | 590 | budgeted = 0; |
| 601 | } | 591 | } |
| 602 | 592 | ||
| @@ -727,8 +717,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 727 | struct ubifs_inode *dir_ui = ubifs_inode(dir); | 717 | struct ubifs_inode *dir_ui = ubifs_inode(dir); |
| 728 | struct ubifs_info *c = dir->i_sb->s_fs_info; | 718 | struct ubifs_info *c = dir->i_sb->s_fs_info; |
| 729 | int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); | 719 | int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); |
| 730 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, | 720 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; |
| 731 | .dirtied_ino_d = 1 }; | ||
| 732 | 721 | ||
| 733 | /* | 722 | /* |
| 734 | * Budget request settings: new inode, new direntry and changing parent | 723 | * Budget request settings: new inode, new direntry and changing parent |
| @@ -789,7 +778,8 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, | |||
| 789 | int sz_change = CALC_DENT_SIZE(dentry->d_name.len); | 778 | int sz_change = CALC_DENT_SIZE(dentry->d_name.len); |
| 790 | int err, devlen = 0; | 779 | int err, devlen = 0; |
| 791 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, | 780 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, |
| 792 | .new_ino_d = devlen, .dirtied_ino = 1 }; | 781 | .new_ino_d = ALIGN(devlen, 8), |
| 782 | .dirtied_ino = 1 }; | ||
| 793 | 783 | ||
| 794 | /* | 784 | /* |
| 795 | * Budget request settings: new inode, new direntry and changing parent | 785 | * Budget request settings: new inode, new direntry and changing parent |
| @@ -863,7 +853,8 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 863 | int err, len = strlen(symname); | 853 | int err, len = strlen(symname); |
| 864 | int sz_change = CALC_DENT_SIZE(dentry->d_name.len); | 854 | int sz_change = CALC_DENT_SIZE(dentry->d_name.len); |
| 865 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, | 855 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, |
| 866 | .new_ino_d = len, .dirtied_ino = 1 }; | 856 | .new_ino_d = ALIGN(len, 8), |
| 857 | .dirtied_ino = 1 }; | ||
| 867 | 858 | ||
| 868 | /* | 859 | /* |
| 869 | * Budget request settings: new inode, new direntry and changing parent | 860 | * Budget request settings: new inode, new direntry and changing parent |
| @@ -1012,7 +1003,7 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 1012 | struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, | 1003 | struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, |
| 1013 | .dirtied_ino = 3 }; | 1004 | .dirtied_ino = 3 }; |
| 1014 | struct ubifs_budget_req ino_req = { .dirtied_ino = 1, | 1005 | struct ubifs_budget_req ino_req = { .dirtied_ino = 1, |
| 1015 | .dirtied_ino_d = old_inode_ui->data_len }; | 1006 | .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; |
| 1016 | struct timespec time; | 1007 | struct timespec time; |
| 1017 | 1008 | ||
| 1018 | /* | 1009 | /* |
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 005a3b854d96..3d698e2022b1 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | 53 | ||
| 54 | #include "ubifs.h" | 54 | #include "ubifs.h" |
| 55 | #include <linux/mount.h> | 55 | #include <linux/mount.h> |
| 56 | #include <linux/namei.h> | ||
| 56 | 57 | ||
| 57 | static int read_block(struct inode *inode, void *addr, unsigned int block, | 58 | static int read_block(struct inode *inode, void *addr, unsigned int block, |
| 58 | struct ubifs_data_node *dn) | 59 | struct ubifs_data_node *dn) |
| @@ -792,7 +793,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode, | |||
| 792 | int err; | 793 | int err; |
| 793 | struct ubifs_budget_req req; | 794 | struct ubifs_budget_req req; |
| 794 | loff_t old_size = inode->i_size, new_size = attr->ia_size; | 795 | loff_t old_size = inode->i_size, new_size = attr->ia_size; |
| 795 | int offset = new_size & (UBIFS_BLOCK_SIZE - 1); | 796 | int offset = new_size & (UBIFS_BLOCK_SIZE - 1), budgeted = 1; |
| 796 | struct ubifs_inode *ui = ubifs_inode(inode); | 797 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 797 | 798 | ||
| 798 | dbg_gen("ino %lu, size %lld -> %lld", inode->i_ino, old_size, new_size); | 799 | dbg_gen("ino %lu, size %lld -> %lld", inode->i_ino, old_size, new_size); |
| @@ -810,8 +811,15 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode, | |||
| 810 | /* A funny way to budget for truncation node */ | 811 | /* A funny way to budget for truncation node */ |
| 811 | req.dirtied_ino_d = UBIFS_TRUN_NODE_SZ; | 812 | req.dirtied_ino_d = UBIFS_TRUN_NODE_SZ; |
| 812 | err = ubifs_budget_space(c, &req); | 813 | err = ubifs_budget_space(c, &req); |
| 813 | if (err) | 814 | if (err) { |
| 814 | return err; | 815 | /* |
| 816 | * Treat truncations to zero as deletion and always allow them, | ||
| 817 | * just like we do for '->unlink()'. | ||
| 818 | */ | ||
| 819 | if (new_size || err != -ENOSPC) | ||
| 820 | return err; | ||
| 821 | budgeted = 0; | ||
| 822 | } | ||
| 815 | 823 | ||
| 816 | err = vmtruncate(inode, new_size); | 824 | err = vmtruncate(inode, new_size); |
| 817 | if (err) | 825 | if (err) |
| @@ -868,7 +876,12 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode, | |||
| 868 | err = ubifs_jnl_truncate(c, inode, old_size, new_size); | 876 | err = ubifs_jnl_truncate(c, inode, old_size, new_size); |
| 869 | mutex_unlock(&ui->ui_mutex); | 877 | mutex_unlock(&ui->ui_mutex); |
| 870 | out_budg: | 878 | out_budg: |
| 871 | ubifs_release_budget(c, &req); | 879 | if (budgeted) |
| 880 | ubifs_release_budget(c, &req); | ||
| 881 | else { | ||
| 882 | c->nospace = c->nospace_rp = 0; | ||
| 883 | smp_wmb(); | ||
| 884 | } | ||
| 872 | return err; | 885 | return err; |
| 873 | } | 886 | } |
| 874 | 887 | ||
| @@ -889,7 +902,7 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode, | |||
| 889 | loff_t new_size = attr->ia_size; | 902 | loff_t new_size = attr->ia_size; |
| 890 | struct ubifs_inode *ui = ubifs_inode(inode); | 903 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 891 | struct ubifs_budget_req req = { .dirtied_ino = 1, | 904 | struct ubifs_budget_req req = { .dirtied_ino = 1, |
| 892 | .dirtied_ino_d = ui->data_len }; | 905 | .dirtied_ino_d = ALIGN(ui->data_len, 8) }; |
| 893 | 906 | ||
| 894 | err = ubifs_budget_space(c, &req); | 907 | err = ubifs_budget_space(c, &req); |
| 895 | if (err) | 908 | if (err) |
| @@ -940,7 +953,8 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 940 | struct inode *inode = dentry->d_inode; | 953 | struct inode *inode = dentry->d_inode; |
| 941 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 954 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
| 942 | 955 | ||
| 943 | dbg_gen("ino %lu, ia_valid %#x", inode->i_ino, attr->ia_valid); | 956 | dbg_gen("ino %lu, mode %#x, ia_valid %#x", |
| 957 | inode->i_ino, inode->i_mode, attr->ia_valid); | ||
| 944 | err = inode_change_ok(inode, attr); | 958 | err = inode_change_ok(inode, attr); |
| 945 | if (err) | 959 | if (err) |
| 946 | return err; | 960 | return err; |
| @@ -1050,7 +1064,7 @@ static int update_mctime(struct ubifs_info *c, struct inode *inode) | |||
| 1050 | if (mctime_update_needed(inode, &now)) { | 1064 | if (mctime_update_needed(inode, &now)) { |
| 1051 | int err, release; | 1065 | int err, release; |
| 1052 | struct ubifs_budget_req req = { .dirtied_ino = 1, | 1066 | struct ubifs_budget_req req = { .dirtied_ino = 1, |
| 1053 | .dirtied_ino_d = ui->data_len }; | 1067 | .dirtied_ino_d = ALIGN(ui->data_len, 8) }; |
| 1054 | 1068 | ||
| 1055 | err = ubifs_budget_space(c, &req); | 1069 | err = ubifs_budget_space(c, &req); |
| 1056 | if (err) | 1070 | if (err) |
| @@ -1269,6 +1283,7 @@ struct file_operations ubifs_file_operations = { | |||
| 1269 | .fsync = ubifs_fsync, | 1283 | .fsync = ubifs_fsync, |
| 1270 | .unlocked_ioctl = ubifs_ioctl, | 1284 | .unlocked_ioctl = ubifs_ioctl, |
| 1271 | .splice_read = generic_file_splice_read, | 1285 | .splice_read = generic_file_splice_read, |
| 1286 | .splice_write = generic_file_splice_write, | ||
| 1272 | #ifdef CONFIG_COMPAT | 1287 | #ifdef CONFIG_COMPAT |
| 1273 | .compat_ioctl = ubifs_compat_ioctl, | 1288 | .compat_ioctl = ubifs_compat_ioctl, |
| 1274 | #endif | 1289 | #endif |
diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c index 10394c548367..e045c8b55423 100644 --- a/fs/ubifs/find.c +++ b/fs/ubifs/find.c | |||
| @@ -211,14 +211,8 @@ static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c, | |||
| 211 | * dirty index heap, and it falls-back to LPT scanning if the heaps are empty | 211 | * dirty index heap, and it falls-back to LPT scanning if the heaps are empty |
| 212 | * or do not have an LEB which satisfies the @min_space criteria. | 212 | * or do not have an LEB which satisfies the @min_space criteria. |
| 213 | * | 213 | * |
| 214 | * Note: | 214 | * Note, LEBs which have less than dead watermark of free + dirty space are |
| 215 | * o LEBs which have less than dead watermark of dirty space are never picked | 215 | * never picked by this function. |
| 216 | * by this function; | ||
| 217 | * | ||
| 218 | * Returns zero and the LEB properties of | ||
| 219 | * found dirty LEB in case of success, %-ENOSPC if no dirty LEB was found and a | ||
| 220 | * negative error code in case of other failures. The returned LEB is marked as | ||
| 221 | * "taken". | ||
| 222 | * | 216 | * |
| 223 | * The additional @pick_free argument controls if this function has to return a | 217 | * The additional @pick_free argument controls if this function has to return a |
| 224 | * free or freeable LEB if one is present. For example, GC must to set it to %1, | 218 | * free or freeable LEB if one is present. For example, GC must to set it to %1, |
| @@ -231,6 +225,10 @@ static const struct ubifs_lprops *scan_for_dirty(struct ubifs_info *c, | |||
| 231 | * | 225 | * |
| 232 | * In addition @pick_free is set to %2 by the recovery process in order to | 226 | * In addition @pick_free is set to %2 by the recovery process in order to |
| 233 | * recover gc_lnum in which case an index LEB must not be returned. | 227 | * recover gc_lnum in which case an index LEB must not be returned. |
| 228 | * | ||
| 229 | * This function returns zero and the LEB properties of found dirty LEB in case | ||
| 230 | * of success, %-ENOSPC if no dirty LEB was found and a negative error code in | ||
| 231 | * case of other failures. The returned LEB is marked as "taken". | ||
| 234 | */ | 232 | */ |
| 235 | int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, | 233 | int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, |
| 236 | int min_space, int pick_free) | 234 | int min_space, int pick_free) |
| @@ -245,7 +243,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, | |||
| 245 | int lebs, rsvd_idx_lebs = 0; | 243 | int lebs, rsvd_idx_lebs = 0; |
| 246 | 244 | ||
| 247 | spin_lock(&c->space_lock); | 245 | spin_lock(&c->space_lock); |
| 248 | lebs = c->lst.empty_lebs; | 246 | lebs = c->lst.empty_lebs + c->idx_gc_cnt; |
| 249 | lebs += c->freeable_cnt - c->lst.taken_empty_lebs; | 247 | lebs += c->freeable_cnt - c->lst.taken_empty_lebs; |
| 250 | 248 | ||
| 251 | /* | 249 | /* |
| @@ -290,9 +288,14 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, | |||
| 290 | idx_lp = idx_heap->arr[0]; | 288 | idx_lp = idx_heap->arr[0]; |
| 291 | sum = idx_lp->free + idx_lp->dirty; | 289 | sum = idx_lp->free + idx_lp->dirty; |
| 292 | /* | 290 | /* |
| 293 | * Since we reserve twice as more space for the index than it | 291 | * Since we reserve thrice as much space for the index than it |
| 294 | * actually takes, it does not make sense to pick indexing LEBs | 292 | * actually takes, it does not make sense to pick indexing LEBs |
| 295 | * with less than half LEB of dirty space. | 293 | * with less than, say, half LEB of dirty space. May be half is |
| 294 | * not the optimal boundary - this should be tested and | ||
| 295 | * checked. This boundary should determine how much we use | ||
| 296 | * in-the-gaps to consolidate the index comparing to how much | ||
| 297 | * we use garbage collector to consolidate it. The "half" | ||
| 298 | * criteria just feels to be fine. | ||
| 296 | */ | 299 | */ |
| 297 | if (sum < min_space || sum < c->half_leb_size) | 300 | if (sum < min_space || sum < c->half_leb_size) |
| 298 | idx_lp = NULL; | 301 | idx_lp = NULL; |
| @@ -312,7 +315,7 @@ int ubifs_find_dirty_leb(struct ubifs_info *c, struct ubifs_lprops *ret_lp, | |||
| 312 | lp = idx_lp; | 315 | lp = idx_lp; |
| 313 | 316 | ||
| 314 | if (lp) { | 317 | if (lp) { |
| 315 | ubifs_assert(lp->dirty >= c->dead_wm); | 318 | ubifs_assert(lp->free + lp->dirty >= c->dead_wm); |
| 316 | goto found; | 319 | goto found; |
| 317 | } | 320 | } |
| 318 | 321 | ||
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c index d0f3dac29081..13f1019c859f 100644 --- a/fs/ubifs/gc.c +++ b/fs/ubifs/gc.c | |||
| @@ -344,6 +344,12 @@ int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp) | |||
| 344 | if (err) | 344 | if (err) |
| 345 | goto out; | 345 | goto out; |
| 346 | 346 | ||
| 347 | /* Allow for races with TNC */ | ||
| 348 | c->gced_lnum = lnum; | ||
| 349 | smp_wmb(); | ||
| 350 | c->gc_seq += 1; | ||
| 351 | smp_wmb(); | ||
| 352 | |||
| 347 | if (c->gc_lnum == -1) { | 353 | if (c->gc_lnum == -1) { |
| 348 | c->gc_lnum = lnum; | 354 | c->gc_lnum = lnum; |
| 349 | err = LEB_RETAINED; | 355 | err = LEB_RETAINED; |
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index 3374f91b6709..054363f2b207 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c | |||
| @@ -54,6 +54,20 @@ | |||
| 54 | #include "ubifs.h" | 54 | #include "ubifs.h" |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| 57 | * ubifs_ro_mode - switch UBIFS to read read-only mode. | ||
| 58 | * @c: UBIFS file-system description object | ||
| 59 | * @err: error code which is the reason of switching to R/O mode | ||
| 60 | */ | ||
| 61 | void ubifs_ro_mode(struct ubifs_info *c, int err) | ||
| 62 | { | ||
| 63 | if (!c->ro_media) { | ||
| 64 | c->ro_media = 1; | ||
| 65 | ubifs_warn("switched to read-only mode, error %d", err); | ||
| 66 | dbg_dump_stack(); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | ||
| 57 | * ubifs_check_node - check node. | 71 | * ubifs_check_node - check node. |
| 58 | * @c: UBIFS file-system description object | 72 | * @c: UBIFS file-system description object |
| 59 | * @buf: node to check | 73 | * @buf: node to check |
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 283155abe5f5..22993f867d19 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c | |||
| @@ -447,13 +447,11 @@ static int get_dent_type(int mode) | |||
| 447 | * @ino: buffer in which to pack inode node | 447 | * @ino: buffer in which to pack inode node |
| 448 | * @inode: inode to pack | 448 | * @inode: inode to pack |
| 449 | * @last: indicates the last node of the group | 449 | * @last: indicates the last node of the group |
| 450 | * @last_reference: non-zero if this is a deletion inode | ||
| 451 | */ | 450 | */ |
| 452 | static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino, | 451 | static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino, |
| 453 | const struct inode *inode, int last, | 452 | const struct inode *inode, int last) |
| 454 | int last_reference) | ||
| 455 | { | 453 | { |
| 456 | int data_len = 0; | 454 | int data_len = 0, last_reference = !inode->i_nlink; |
| 457 | struct ubifs_inode *ui = ubifs_inode(inode); | 455 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 458 | 456 | ||
| 459 | ino->ch.node_type = UBIFS_INO_NODE; | 457 | ino->ch.node_type = UBIFS_INO_NODE; |
| @@ -596,9 +594,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, | |||
| 596 | ubifs_prep_grp_node(c, dent, dlen, 0); | 594 | ubifs_prep_grp_node(c, dent, dlen, 0); |
| 597 | 595 | ||
| 598 | ino = (void *)dent + aligned_dlen; | 596 | ino = (void *)dent + aligned_dlen; |
| 599 | pack_inode(c, ino, inode, 0, last_reference); | 597 | pack_inode(c, ino, inode, 0); |
| 600 | ino = (void *)ino + aligned_ilen; | 598 | ino = (void *)ino + aligned_ilen; |
| 601 | pack_inode(c, ino, dir, 1, 0); | 599 | pack_inode(c, ino, dir, 1); |
| 602 | 600 | ||
| 603 | if (last_reference) { | 601 | if (last_reference) { |
| 604 | err = ubifs_add_orphan(c, inode->i_ino); | 602 | err = ubifs_add_orphan(c, inode->i_ino); |
| @@ -606,6 +604,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, | |||
| 606 | release_head(c, BASEHD); | 604 | release_head(c, BASEHD); |
| 607 | goto out_finish; | 605 | goto out_finish; |
| 608 | } | 606 | } |
| 607 | ui->del_cmtno = c->cmt_no; | ||
| 609 | } | 608 | } |
| 610 | 609 | ||
| 611 | err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); | 610 | err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); |
| @@ -750,30 +749,25 @@ out_free: | |||
| 750 | * ubifs_jnl_write_inode - flush inode to the journal. | 749 | * ubifs_jnl_write_inode - flush inode to the journal. |
| 751 | * @c: UBIFS file-system description object | 750 | * @c: UBIFS file-system description object |
| 752 | * @inode: inode to flush | 751 | * @inode: inode to flush |
| 753 | * @deletion: inode has been deleted | ||
| 754 | * | 752 | * |
| 755 | * This function writes inode @inode to the journal. If the inode is | 753 | * This function writes inode @inode to the journal. If the inode is |
| 756 | * synchronous, it also synchronizes the write-buffer. Returns zero in case of | 754 | * synchronous, it also synchronizes the write-buffer. Returns zero in case of |
| 757 | * success and a negative error code in case of failure. | 755 | * success and a negative error code in case of failure. |
| 758 | */ | 756 | */ |
| 759 | int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, | 757 | int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) |
| 760 | int deletion) | ||
| 761 | { | 758 | { |
| 762 | int err, len, lnum, offs, sync = 0; | 759 | int err, lnum, offs; |
| 763 | struct ubifs_ino_node *ino; | 760 | struct ubifs_ino_node *ino; |
| 764 | struct ubifs_inode *ui = ubifs_inode(inode); | 761 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 762 | int sync = 0, len = UBIFS_INO_NODE_SZ, last_reference = !inode->i_nlink; | ||
| 765 | 763 | ||
| 766 | dbg_jnl("ino %lu%s", inode->i_ino, | 764 | dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink); |
| 767 | deletion ? " (last reference)" : ""); | ||
| 768 | if (deletion) | ||
| 769 | ubifs_assert(inode->i_nlink == 0); | ||
| 770 | 765 | ||
| 771 | len = UBIFS_INO_NODE_SZ; | ||
| 772 | /* | 766 | /* |
| 773 | * If the inode is being deleted, do not write the attached data. No | 767 | * If the inode is being deleted, do not write the attached data. No |
| 774 | * need to synchronize the write-buffer either. | 768 | * need to synchronize the write-buffer either. |
| 775 | */ | 769 | */ |
| 776 | if (!deletion) { | 770 | if (!last_reference) { |
| 777 | len += ui->data_len; | 771 | len += ui->data_len; |
| 778 | sync = IS_SYNC(inode); | 772 | sync = IS_SYNC(inode); |
| 779 | } | 773 | } |
| @@ -786,7 +780,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, | |||
| 786 | if (err) | 780 | if (err) |
| 787 | goto out_free; | 781 | goto out_free; |
| 788 | 782 | ||
| 789 | pack_inode(c, ino, inode, 1, deletion); | 783 | pack_inode(c, ino, inode, 1); |
| 790 | err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); | 784 | err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); |
| 791 | if (err) | 785 | if (err) |
| 792 | goto out_release; | 786 | goto out_release; |
| @@ -795,7 +789,7 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, | |||
| 795 | inode->i_ino); | 789 | inode->i_ino); |
| 796 | release_head(c, BASEHD); | 790 | release_head(c, BASEHD); |
| 797 | 791 | ||
| 798 | if (deletion) { | 792 | if (last_reference) { |
| 799 | err = ubifs_tnc_remove_ino(c, inode->i_ino); | 793 | err = ubifs_tnc_remove_ino(c, inode->i_ino); |
| 800 | if (err) | 794 | if (err) |
| 801 | goto out_ro; | 795 | goto out_ro; |
| @@ -828,6 +822,65 @@ out_free: | |||
| 828 | } | 822 | } |
| 829 | 823 | ||
| 830 | /** | 824 | /** |
| 825 | * ubifs_jnl_delete_inode - delete an inode. | ||
| 826 | * @c: UBIFS file-system description object | ||
| 827 | * @inode: inode to delete | ||
| 828 | * | ||
| 829 | * This function deletes inode @inode which includes removing it from orphans, | ||
| 830 | * deleting it from TNC and, in some cases, writing a deletion inode to the | ||
| 831 | * journal. | ||
| 832 | * | ||
| 833 | * When regular file inodes are unlinked or a directory inode is removed, the | ||
| 834 | * 'ubifs_jnl_update()' function writes a corresponding deletion inode and | ||
| 835 | * direntry to the media, and adds the inode to orphans. After this, when the | ||
| 836 | * last reference to this inode has been dropped, this function is called. In | ||
| 837 | * general, it has to write one more deletion inode to the media, because if | ||
| 838 | * a commit happened between 'ubifs_jnl_update()' and | ||
| 839 | * 'ubifs_jnl_delete_inode()', the deletion inode is not in the journal | ||
| 840 | * anymore, and in fact it might not be on the flash anymore, because it might | ||
| 841 | * have been garbage-collected already. And for optimization reasons UBIFS does | ||
| 842 | * not read the orphan area if it has been unmounted cleanly, so it would have | ||
| 843 | * no indication in the journal that there is a deleted inode which has to be | ||
| 844 | * removed from TNC. | ||
| 845 | * | ||
| 846 | * However, if there was no commit between 'ubifs_jnl_update()' and | ||
| 847 | * 'ubifs_jnl_delete_inode()', then there is no need to write the deletion | ||
| 848 | * inode to the media for the second time. And this is quite a typical case. | ||
| 849 | * | ||
| 850 | * This function returns zero in case of success and a negative error code in | ||
| 851 | * case of failure. | ||
| 852 | */ | ||
| 853 | int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode) | ||
| 854 | { | ||
| 855 | int err; | ||
| 856 | struct ubifs_inode *ui = ubifs_inode(inode); | ||
| 857 | |||
| 858 | ubifs_assert(inode->i_nlink == 0); | ||
| 859 | |||
| 860 | if (ui->del_cmtno != c->cmt_no) | ||
| 861 | /* A commit happened for sure */ | ||
| 862 | return ubifs_jnl_write_inode(c, inode); | ||
| 863 | |||
| 864 | down_read(&c->commit_sem); | ||
| 865 | /* | ||
| 866 | * Check commit number again, because the first test has been done | ||
| 867 | * without @c->commit_sem, so a commit might have happened. | ||
| 868 | */ | ||
| 869 | if (ui->del_cmtno != c->cmt_no) { | ||
| 870 | up_read(&c->commit_sem); | ||
| 871 | return ubifs_jnl_write_inode(c, inode); | ||
| 872 | } | ||
| 873 | |||
| 874 | err = ubifs_tnc_remove_ino(c, inode->i_ino); | ||
| 875 | if (err) | ||
| 876 | ubifs_ro_mode(c, err); | ||
| 877 | else | ||
| 878 | ubifs_delete_orphan(c, inode->i_ino); | ||
| 879 | up_read(&c->commit_sem); | ||
| 880 | return err; | ||
| 881 | } | ||
| 882 | |||
| 883 | /** | ||
| 831 | * ubifs_jnl_rename - rename a directory entry. | 884 | * ubifs_jnl_rename - rename a directory entry. |
| 832 | * @c: UBIFS file-system description object | 885 | * @c: UBIFS file-system description object |
| 833 | * @old_dir: parent inode of directory entry to rename | 886 | * @old_dir: parent inode of directory entry to rename |
| @@ -917,16 +970,16 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, | |||
| 917 | 970 | ||
| 918 | p = (void *)dent2 + aligned_dlen2; | 971 | p = (void *)dent2 + aligned_dlen2; |
| 919 | if (new_inode) { | 972 | if (new_inode) { |
| 920 | pack_inode(c, p, new_inode, 0, last_reference); | 973 | pack_inode(c, p, new_inode, 0); |
| 921 | p += ALIGN(ilen, 8); | 974 | p += ALIGN(ilen, 8); |
| 922 | } | 975 | } |
| 923 | 976 | ||
| 924 | if (!move) | 977 | if (!move) |
| 925 | pack_inode(c, p, old_dir, 1, 0); | 978 | pack_inode(c, p, old_dir, 1); |
| 926 | else { | 979 | else { |
| 927 | pack_inode(c, p, old_dir, 0, 0); | 980 | pack_inode(c, p, old_dir, 0); |
| 928 | p += ALIGN(plen, 8); | 981 | p += ALIGN(plen, 8); |
| 929 | pack_inode(c, p, new_dir, 1, 0); | 982 | pack_inode(c, p, new_dir, 1); |
| 930 | } | 983 | } |
| 931 | 984 | ||
| 932 | if (last_reference) { | 985 | if (last_reference) { |
| @@ -935,6 +988,7 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, | |||
| 935 | release_head(c, BASEHD); | 988 | release_head(c, BASEHD); |
| 936 | goto out_finish; | 989 | goto out_finish; |
| 937 | } | 990 | } |
| 991 | new_ui->del_cmtno = c->cmt_no; | ||
| 938 | } | 992 | } |
| 939 | 993 | ||
| 940 | err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); | 994 | err = write_head(c, BASEHD, dent, len, &lnum, &offs, sync); |
| @@ -1131,7 +1185,7 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, | |||
| 1131 | if (err) | 1185 | if (err) |
| 1132 | goto out_free; | 1186 | goto out_free; |
| 1133 | 1187 | ||
| 1134 | pack_inode(c, ino, inode, 0, 0); | 1188 | pack_inode(c, ino, inode, 0); |
| 1135 | ubifs_prep_grp_node(c, trun, UBIFS_TRUN_NODE_SZ, dlen ? 0 : 1); | 1189 | ubifs_prep_grp_node(c, trun, UBIFS_TRUN_NODE_SZ, dlen ? 0 : 1); |
| 1136 | if (dlen) | 1190 | if (dlen) |
| 1137 | ubifs_prep_grp_node(c, dn, dlen, 1); | 1191 | ubifs_prep_grp_node(c, dn, dlen, 1); |
| @@ -1251,9 +1305,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, | |||
| 1251 | ubifs_prep_grp_node(c, xent, xlen, 0); | 1305 | ubifs_prep_grp_node(c, xent, xlen, 0); |
| 1252 | 1306 | ||
| 1253 | ino = (void *)xent + aligned_xlen; | 1307 | ino = (void *)xent + aligned_xlen; |
| 1254 | pack_inode(c, ino, inode, 0, 1); | 1308 | pack_inode(c, ino, inode, 0); |
| 1255 | ino = (void *)ino + UBIFS_INO_NODE_SZ; | 1309 | ino = (void *)ino + UBIFS_INO_NODE_SZ; |
| 1256 | pack_inode(c, ino, host, 1, 0); | 1310 | pack_inode(c, ino, host, 1); |
| 1257 | 1311 | ||
| 1258 | err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); | 1312 | err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); |
| 1259 | if (!sync && !err) | 1313 | if (!sync && !err) |
| @@ -1320,7 +1374,7 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, | |||
| 1320 | const struct inode *host) | 1374 | const struct inode *host) |
| 1321 | { | 1375 | { |
| 1322 | int err, len1, len2, aligned_len, aligned_len1, lnum, offs; | 1376 | int err, len1, len2, aligned_len, aligned_len1, lnum, offs; |
| 1323 | struct ubifs_inode *host_ui = ubifs_inode(inode); | 1377 | struct ubifs_inode *host_ui = ubifs_inode(host); |
| 1324 | struct ubifs_ino_node *ino; | 1378 | struct ubifs_ino_node *ino; |
| 1325 | union ubifs_key key; | 1379 | union ubifs_key key; |
| 1326 | int sync = IS_DIRSYNC(host); | 1380 | int sync = IS_DIRSYNC(host); |
| @@ -1344,8 +1398,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, | |||
| 1344 | if (err) | 1398 | if (err) |
| 1345 | goto out_free; | 1399 | goto out_free; |
| 1346 | 1400 | ||
| 1347 | pack_inode(c, ino, host, 0, 0); | 1401 | pack_inode(c, ino, host, 0); |
| 1348 | pack_inode(c, (void *)ino + aligned_len1, inode, 1, 0); | 1402 | pack_inode(c, (void *)ino + aligned_len1, inode, 1); |
| 1349 | 1403 | ||
| 1350 | err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); | 1404 | err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); |
| 1351 | if (!sync && !err) { | 1405 | if (!sync && !err) { |
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c index 36857b9ed59e..3e0aa7367556 100644 --- a/fs/ubifs/log.c +++ b/fs/ubifs/log.c | |||
| @@ -317,6 +317,8 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) | |||
| 317 | return 0; | 317 | return 0; |
| 318 | 318 | ||
| 319 | out_unlock: | 319 | out_unlock: |
| 320 | if (err != -EAGAIN) | ||
| 321 | ubifs_ro_mode(c, err); | ||
| 320 | mutex_unlock(&c->log_mutex); | 322 | mutex_unlock(&c->log_mutex); |
| 321 | kfree(ref); | 323 | kfree(ref); |
| 322 | kfree(bud); | 324 | kfree(bud); |
| @@ -410,7 +412,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) | |||
| 410 | return -ENOMEM; | 412 | return -ENOMEM; |
| 411 | 413 | ||
| 412 | cs->ch.node_type = UBIFS_CS_NODE; | 414 | cs->ch.node_type = UBIFS_CS_NODE; |
| 413 | cs->cmt_no = cpu_to_le64(c->cmt_no + 1); | 415 | cs->cmt_no = cpu_to_le64(c->cmt_no); |
| 414 | ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); | 416 | ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); |
| 415 | 417 | ||
| 416 | /* | 418 | /* |
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h index 4beccfc256d2..4c12a9215d7f 100644 --- a/fs/ubifs/misc.h +++ b/fs/ubifs/misc.h | |||
| @@ -80,20 +80,6 @@ static inline struct ubifs_inode *ubifs_inode(const struct inode *inode) | |||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| 83 | * ubifs_ro_mode - switch UBIFS to read read-only mode. | ||
| 84 | * @c: UBIFS file-system description object | ||
| 85 | * @err: error code which is the reason of switching to R/O mode | ||
| 86 | */ | ||
| 87 | static inline void ubifs_ro_mode(struct ubifs_info *c, int err) | ||
| 88 | { | ||
| 89 | if (!c->ro_media) { | ||
| 90 | c->ro_media = 1; | ||
| 91 | ubifs_warn("switched to read-only mode, error %d", err); | ||
| 92 | dbg_dump_stack(); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * ubifs_compr_present - check if compressor was compiled in. | 83 | * ubifs_compr_present - check if compressor was compiled in. |
| 98 | * @compr_type: compressor type to check | 84 | * @compr_type: compressor type to check |
| 99 | * | 85 | * |
| @@ -298,38 +284,6 @@ static inline void *ubifs_idx_key(const struct ubifs_info *c, | |||
| 298 | } | 284 | } |
| 299 | 285 | ||
| 300 | /** | 286 | /** |
| 301 | * ubifs_reported_space - calculate reported free space. | ||
| 302 | * @c: the UBIFS file-system description object | ||
| 303 | * @free: amount of free space | ||
| 304 | * | ||
| 305 | * This function calculates amount of free space which will be reported to | ||
| 306 | * user-space. User-space application tend to expect that if the file-system | ||
| 307 | * (e.g., via the 'statfs()' call) reports that it has N bytes available, they | ||
| 308 | * are able to write a file of size N. UBIFS attaches node headers to each data | ||
| 309 | * node and it has to write indexind nodes as well. This introduces additional | ||
| 310 | * overhead, and UBIFS it has to report sligtly less free space to meet the | ||
| 311 | * above expectetion. | ||
| 312 | * | ||
| 313 | * This function assumes free space is made up of uncompressed data nodes and | ||
| 314 | * full index nodes (one per data node, doubled because we always allow enough | ||
| 315 | * space to write the index twice). | ||
| 316 | * | ||
| 317 | * Note, the calculation is pessimistic, which means that most of the time | ||
| 318 | * UBIFS reports less space than it actually has. | ||
| 319 | */ | ||
| 320 | static inline long long ubifs_reported_space(const struct ubifs_info *c, | ||
| 321 | uint64_t free) | ||
| 322 | { | ||
| 323 | int divisor, factor; | ||
| 324 | |||
| 325 | divisor = UBIFS_MAX_DATA_NODE_SZ + (c->max_idx_node_sz << 1); | ||
| 326 | factor = UBIFS_MAX_DATA_NODE_SZ - UBIFS_DATA_NODE_SZ; | ||
| 327 | do_div(free, divisor); | ||
| 328 | |||
| 329 | return free * factor; | ||
| 330 | } | ||
| 331 | |||
| 332 | /** | ||
| 333 | * ubifs_current_time - round current time to time granularity. | 287 | * ubifs_current_time - round current time to time granularity. |
| 334 | * @inode: inode | 288 | * @inode: inode |
| 335 | */ | 289 | */ |
| @@ -339,4 +293,21 @@ static inline struct timespec ubifs_current_time(struct inode *inode) | |||
| 339 | current_fs_time(inode->i_sb) : CURRENT_TIME_SEC; | 293 | current_fs_time(inode->i_sb) : CURRENT_TIME_SEC; |
| 340 | } | 294 | } |
| 341 | 295 | ||
| 296 | /** | ||
| 297 | * ubifs_tnc_lookup - look up a file-system node. | ||
| 298 | * @c: UBIFS file-system description object | ||
| 299 | * @key: node key to lookup | ||
| 300 | * @node: the node is returned here | ||
| 301 | * | ||
| 302 | * This function look up and reads node with key @key. The caller has to make | ||
| 303 | * sure the @node buffer is large enough to fit the node. Returns zero in case | ||
| 304 | * of success, %-ENOENT if the node was not found, and a negative error code in | ||
| 305 | * case of failure. | ||
| 306 | */ | ||
| 307 | static inline int ubifs_tnc_lookup(struct ubifs_info *c, | ||
| 308 | const union ubifs_key *key, void *node) | ||
| 309 | { | ||
| 310 | return ubifs_tnc_locate(c, key, node, NULL, NULL); | ||
| 311 | } | ||
| 312 | |||
| 342 | #endif /* __UBIFS_MISC_H__ */ | 313 | #endif /* __UBIFS_MISC_H__ */ |
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c index 3afeb9242c6a..02d3462f4d3e 100644 --- a/fs/ubifs/orphan.c +++ b/fs/ubifs/orphan.c | |||
| @@ -310,10 +310,10 @@ static int write_orph_node(struct ubifs_info *c, int atomic) | |||
| 310 | c->cmt_orphans -= cnt; | 310 | c->cmt_orphans -= cnt; |
| 311 | spin_unlock(&c->orphan_lock); | 311 | spin_unlock(&c->orphan_lock); |
| 312 | if (c->cmt_orphans) | 312 | if (c->cmt_orphans) |
| 313 | orph->cmt_no = cpu_to_le64(c->cmt_no + 1); | 313 | orph->cmt_no = cpu_to_le64(c->cmt_no); |
| 314 | else | 314 | else |
| 315 | /* Mark the last node of the commit */ | 315 | /* Mark the last node of the commit */ |
| 316 | orph->cmt_no = cpu_to_le64((c->cmt_no + 1) | (1ULL << 63)); | 316 | orph->cmt_no = cpu_to_le64((c->cmt_no) | (1ULL << 63)); |
| 317 | ubifs_assert(c->ohead_offs + len <= c->leb_size); | 317 | ubifs_assert(c->ohead_offs + len <= c->leb_size); |
| 318 | ubifs_assert(c->ohead_lnum >= c->orph_first); | 318 | ubifs_assert(c->ohead_lnum >= c->orph_first); |
| 319 | ubifs_assert(c->ohead_lnum <= c->orph_last); | 319 | ubifs_assert(c->ohead_lnum <= c->orph_last); |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 00eb9c68ad03..7562464ac83f 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -30,7 +30,6 @@ | |||
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/ctype.h> | 32 | #include <linux/ctype.h> |
| 33 | #include <linux/random.h> | ||
| 34 | #include <linux/kthread.h> | 33 | #include <linux/kthread.h> |
| 35 | #include <linux/parser.h> | 34 | #include <linux/parser.h> |
| 36 | #include <linux/seq_file.h> | 35 | #include <linux/seq_file.h> |
| @@ -149,7 +148,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) | |||
| 149 | if (err) | 148 | if (err) |
| 150 | goto out_invalid; | 149 | goto out_invalid; |
| 151 | 150 | ||
| 152 | /* Disable readahead */ | 151 | /* Disable read-ahead */ |
| 153 | inode->i_mapping->backing_dev_info = &c->bdi; | 152 | inode->i_mapping->backing_dev_info = &c->bdi; |
| 154 | 153 | ||
| 155 | switch (inode->i_mode & S_IFMT) { | 154 | switch (inode->i_mode & S_IFMT) { |
| @@ -278,7 +277,7 @@ static void ubifs_destroy_inode(struct inode *inode) | |||
| 278 | */ | 277 | */ |
| 279 | static int ubifs_write_inode(struct inode *inode, int wait) | 278 | static int ubifs_write_inode(struct inode *inode, int wait) |
| 280 | { | 279 | { |
| 281 | int err; | 280 | int err = 0; |
| 282 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 281 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
| 283 | struct ubifs_inode *ui = ubifs_inode(inode); | 282 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 284 | 283 | ||
| @@ -299,10 +298,18 @@ static int ubifs_write_inode(struct inode *inode, int wait) | |||
| 299 | return 0; | 298 | return 0; |
| 300 | } | 299 | } |
| 301 | 300 | ||
| 302 | dbg_gen("inode %lu", inode->i_ino); | 301 | /* |
| 303 | err = ubifs_jnl_write_inode(c, inode, 0); | 302 | * As an optimization, do not write orphan inodes to the media just |
| 304 | if (err) | 303 | * because this is not needed. |
| 305 | ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); | 304 | */ |
| 305 | dbg_gen("inode %lu, mode %#x, nlink %u", | ||
| 306 | inode->i_ino, (int)inode->i_mode, inode->i_nlink); | ||
| 307 | if (inode->i_nlink) { | ||
| 308 | err = ubifs_jnl_write_inode(c, inode); | ||
| 309 | if (err) | ||
| 310 | ubifs_err("can't write inode %lu, error %d", | ||
| 311 | inode->i_ino, err); | ||
| 312 | } | ||
| 306 | 313 | ||
| 307 | ui->dirty = 0; | 314 | ui->dirty = 0; |
| 308 | mutex_unlock(&ui->ui_mutex); | 315 | mutex_unlock(&ui->ui_mutex); |
| @@ -314,8 +321,9 @@ static void ubifs_delete_inode(struct inode *inode) | |||
| 314 | { | 321 | { |
| 315 | int err; | 322 | int err; |
| 316 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 323 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
| 324 | struct ubifs_inode *ui = ubifs_inode(inode); | ||
| 317 | 325 | ||
| 318 | if (ubifs_inode(inode)->xattr) | 326 | if (ui->xattr) |
| 319 | /* | 327 | /* |
| 320 | * Extended attribute inode deletions are fully handled in | 328 | * Extended attribute inode deletions are fully handled in |
| 321 | * 'ubifs_removexattr()'. These inodes are special and have | 329 | * 'ubifs_removexattr()'. These inodes are special and have |
| @@ -323,7 +331,7 @@ static void ubifs_delete_inode(struct inode *inode) | |||
| 323 | */ | 331 | */ |
| 324 | goto out; | 332 | goto out; |
| 325 | 333 | ||
| 326 | dbg_gen("inode %lu", inode->i_ino); | 334 | dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode); |
| 327 | ubifs_assert(!atomic_read(&inode->i_count)); | 335 | ubifs_assert(!atomic_read(&inode->i_count)); |
| 328 | ubifs_assert(inode->i_nlink == 0); | 336 | ubifs_assert(inode->i_nlink == 0); |
| 329 | 337 | ||
| @@ -331,15 +339,19 @@ static void ubifs_delete_inode(struct inode *inode) | |||
| 331 | if (is_bad_inode(inode)) | 339 | if (is_bad_inode(inode)) |
| 332 | goto out; | 340 | goto out; |
| 333 | 341 | ||
| 334 | ubifs_inode(inode)->ui_size = inode->i_size = 0; | 342 | ui->ui_size = inode->i_size = 0; |
| 335 | err = ubifs_jnl_write_inode(c, inode, 1); | 343 | err = ubifs_jnl_delete_inode(c, inode); |
| 336 | if (err) | 344 | if (err) |
| 337 | /* | 345 | /* |
| 338 | * Worst case we have a lost orphan inode wasting space, so a | 346 | * Worst case we have a lost orphan inode wasting space, so a |
| 339 | * simple error message is ok here. | 347 | * simple error message is OK here. |
| 340 | */ | 348 | */ |
| 341 | ubifs_err("can't write inode %lu, error %d", inode->i_ino, err); | 349 | ubifs_err("can't delete inode %lu, error %d", |
| 350 | inode->i_ino, err); | ||
| 351 | |||
| 342 | out: | 352 | out: |
| 353 | if (ui->dirty) | ||
| 354 | ubifs_release_dirty_inode_budget(c, ui); | ||
| 343 | clear_inode(inode); | 355 | clear_inode(inode); |
| 344 | } | 356 | } |
| 345 | 357 | ||
| @@ -358,8 +370,9 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 358 | { | 370 | { |
| 359 | struct ubifs_info *c = dentry->d_sb->s_fs_info; | 371 | struct ubifs_info *c = dentry->d_sb->s_fs_info; |
| 360 | unsigned long long free; | 372 | unsigned long long free; |
| 373 | __le32 *uuid = (__le32 *)c->uuid; | ||
| 361 | 374 | ||
| 362 | free = ubifs_budg_get_free_space(c); | 375 | free = ubifs_get_free_space(c); |
| 363 | dbg_gen("free space %lld bytes (%lld blocks)", | 376 | dbg_gen("free space %lld bytes (%lld blocks)", |
| 364 | free, free >> UBIFS_BLOCK_SHIFT); | 377 | free, free >> UBIFS_BLOCK_SHIFT); |
| 365 | 378 | ||
| @@ -374,7 +387,8 @@ static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 374 | buf->f_files = 0; | 387 | buf->f_files = 0; |
| 375 | buf->f_ffree = 0; | 388 | buf->f_ffree = 0; |
| 376 | buf->f_namelen = UBIFS_MAX_NLEN; | 389 | buf->f_namelen = UBIFS_MAX_NLEN; |
| 377 | 390 | buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]); | |
| 391 | buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]); | ||
| 378 | return 0; | 392 | return 0; |
| 379 | } | 393 | } |
| 380 | 394 | ||
| @@ -518,6 +532,12 @@ static int init_constants_early(struct ubifs_info *c) | |||
| 518 | c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); | 532 | c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); |
| 519 | c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); | 533 | c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); |
| 520 | 534 | ||
| 535 | /* | ||
| 536 | * Calculate how many bytes would be wasted at the end of LEB if it was | ||
| 537 | * fully filled with data nodes of maximum size. This is used in | ||
| 538 | * calculations when reporting free space. | ||
| 539 | */ | ||
| 540 | c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ; | ||
| 521 | return 0; | 541 | return 0; |
| 522 | } | 542 | } |
| 523 | 543 | ||
| @@ -635,13 +655,11 @@ static int init_constants_late(struct ubifs_info *c) | |||
| 635 | * internally because it does not make much sense for UBIFS, but it is | 655 | * internally because it does not make much sense for UBIFS, but it is |
| 636 | * necessary to report something for the 'statfs()' call. | 656 | * necessary to report something for the 'statfs()' call. |
| 637 | * | 657 | * |
| 638 | * Subtract the LEB reserved for GC and the LEB which is reserved for | 658 | * Subtract the LEB reserved for GC, the LEB which is reserved for |
| 639 | * deletions. | 659 | * deletions, and assume only one journal head is available. |
| 640 | * | ||
| 641 | * Review 'ubifs_calc_available()' if changing this calculation. | ||
| 642 | */ | 660 | */ |
| 643 | tmp64 = c->main_lebs - 2; | 661 | tmp64 = c->main_lebs - 2 - c->jhead_cnt + 1; |
| 644 | tmp64 *= (uint64_t)c->leb_size - c->dark_wm; | 662 | tmp64 *= (uint64_t)c->leb_size - c->leb_overhead; |
| 645 | tmp64 = ubifs_reported_space(c, tmp64); | 663 | tmp64 = ubifs_reported_space(c, tmp64); |
| 646 | c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; | 664 | c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; |
| 647 | 665 | ||
| @@ -1122,8 +1140,8 @@ static int mount_ubifs(struct ubifs_info *c) | |||
| 1122 | if (err) | 1140 | if (err) |
| 1123 | goto out_infos; | 1141 | goto out_infos; |
| 1124 | 1142 | ||
| 1125 | ubifs_msg("mounted UBI device %d, volume %d", c->vi.ubi_num, | 1143 | ubifs_msg("mounted UBI device %d, volume %d, name \"%s\"", |
| 1126 | c->vi.vol_id); | 1144 | c->vi.ubi_num, c->vi.vol_id, c->vi.name); |
| 1127 | if (mounted_read_only) | 1145 | if (mounted_read_only) |
| 1128 | ubifs_msg("mounted read-only"); | 1146 | ubifs_msg("mounted read-only"); |
| 1129 | x = (long long)c->main_lebs * c->leb_size; | 1147 | x = (long long)c->main_lebs * c->leb_size; |
| @@ -1469,6 +1487,7 @@ static void ubifs_put_super(struct super_block *sb) | |||
| 1469 | */ | 1487 | */ |
| 1470 | ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); | 1488 | ubifs_assert(atomic_long_read(&c->dirty_pg_cnt) == 0); |
| 1471 | ubifs_assert(c->budg_idx_growth == 0); | 1489 | ubifs_assert(c->budg_idx_growth == 0); |
| 1490 | ubifs_assert(c->budg_dd_growth == 0); | ||
| 1472 | ubifs_assert(c->budg_data_growth == 0); | 1491 | ubifs_assert(c->budg_data_growth == 0); |
| 1473 | 1492 | ||
| 1474 | /* | 1493 | /* |
| @@ -1657,7 +1676,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1657 | INIT_LIST_HEAD(&c->orph_new); | 1676 | INIT_LIST_HEAD(&c->orph_new); |
| 1658 | 1677 | ||
| 1659 | c->highest_inum = UBIFS_FIRST_INO; | 1678 | c->highest_inum = UBIFS_FIRST_INO; |
| 1660 | get_random_bytes(&c->vfs_gen, sizeof(int)); | ||
| 1661 | c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; | 1679 | c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; |
| 1662 | 1680 | ||
| 1663 | ubi_get_volume_info(ubi, &c->vi); | 1681 | ubi_get_volume_info(ubi, &c->vi); |
| @@ -1671,10 +1689,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1671 | } | 1689 | } |
| 1672 | 1690 | ||
| 1673 | /* | 1691 | /* |
| 1674 | * UBIFS provids 'backing_dev_info' in order to disable readahead. For | 1692 | * UBIFS provides 'backing_dev_info' in order to disable read-ahead. For |
| 1675 | * UBIFS, I/O is not deferred, it is done immediately in readpage, | 1693 | * UBIFS, I/O is not deferred, it is done immediately in readpage, |
| 1676 | * which means the user would have to wait not just for their own I/O | 1694 | * which means the user would have to wait not just for their own I/O |
| 1677 | * but the readahead I/O as well i.e. completely pointless. | 1695 | * but the read-ahead I/O as well i.e. completely pointless. |
| 1678 | * | 1696 | * |
| 1679 | * Read-ahead will be disabled because @c->bdi.ra_pages is 0. | 1697 | * Read-ahead will be disabled because @c->bdi.ra_pages is 0. |
| 1680 | */ | 1698 | */ |
| @@ -1841,7 +1859,7 @@ static struct file_system_type ubifs_fs_type = { | |||
| 1841 | /* | 1859 | /* |
| 1842 | * Inode slab cache constructor. | 1860 | * Inode slab cache constructor. |
| 1843 | */ | 1861 | */ |
| 1844 | static void inode_slab_ctor(struct kmem_cache *cachep, void *obj) | 1862 | static void inode_slab_ctor(void *obj) |
| 1845 | { | 1863 | { |
| 1846 | struct ubifs_inode *ui = obj; | 1864 | struct ubifs_inode *ui = obj; |
| 1847 | inode_init_once(&ui->vfs_inode); | 1865 | inode_init_once(&ui->vfs_inode); |
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index e909f4a96443..7da209ab9378 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c | |||
| @@ -506,7 +506,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, | |||
| 506 | if (keys_cmp(c, key, &node_key) != 0) | 506 | if (keys_cmp(c, key, &node_key) != 0) |
| 507 | ret = 0; | 507 | ret = 0; |
| 508 | } | 508 | } |
| 509 | if (ret == 0) | 509 | if (ret == 0 && c->replaying) |
| 510 | dbg_mnt("dangling branch LEB %d:%d len %d, key %s", | 510 | dbg_mnt("dangling branch LEB %d:%d len %d, key %s", |
| 511 | zbr->lnum, zbr->offs, zbr->len, DBGKEY(key)); | 511 | zbr->lnum, zbr->offs, zbr->len, DBGKEY(key)); |
| 512 | return ret; | 512 | return ret; |
| @@ -1382,50 +1382,39 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key, | |||
| 1382 | } | 1382 | } |
| 1383 | 1383 | ||
| 1384 | /** | 1384 | /** |
| 1385 | * ubifs_tnc_lookup - look up a file-system node. | 1385 | * maybe_leb_gced - determine if a LEB may have been garbage collected. |
| 1386 | * @c: UBIFS file-system description object | 1386 | * @c: UBIFS file-system description object |
| 1387 | * @key: node key to lookup | 1387 | * @lnum: LEB number |
| 1388 | * @node: the node is returned here | 1388 | * @gc_seq1: garbage collection sequence number |
| 1389 | * | 1389 | * |
| 1390 | * This function look up and reads node with key @key. The caller has to make | 1390 | * This function determines if @lnum may have been garbage collected since |
| 1391 | * sure the @node buffer is large enough to fit the node. Returns zero in case | 1391 | * sequence number @gc_seq1. If it may have been then %1 is returned, otherwise |
| 1392 | * of success, %-ENOENT if the node was not found, and a negative error code in | 1392 | * %0 is returned. |
| 1393 | * case of failure. | ||
| 1394 | */ | 1393 | */ |
| 1395 | int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key, | 1394 | static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1) |
| 1396 | void *node) | ||
| 1397 | { | 1395 | { |
| 1398 | int found, n, err; | 1396 | int gc_seq2, gced_lnum; |
| 1399 | struct ubifs_znode *znode; | ||
| 1400 | struct ubifs_zbranch zbr, *zt; | ||
| 1401 | 1397 | ||
| 1402 | mutex_lock(&c->tnc_mutex); | 1398 | gced_lnum = c->gced_lnum; |
| 1403 | found = ubifs_lookup_level0(c, key, &znode, &n); | 1399 | smp_rmb(); |
| 1404 | if (!found) { | 1400 | gc_seq2 = c->gc_seq; |
| 1405 | err = -ENOENT; | 1401 | /* Same seq means no GC */ |
| 1406 | goto out; | 1402 | if (gc_seq1 == gc_seq2) |
| 1407 | } else if (found < 0) { | 1403 | return 0; |
| 1408 | err = found; | 1404 | /* Different by more than 1 means we don't know */ |
| 1409 | goto out; | 1405 | if (gc_seq1 + 1 != gc_seq2) |
| 1410 | } | 1406 | return 1; |
| 1411 | zt = &znode->zbranch[n]; | 1407 | /* |
| 1412 | if (is_hash_key(c, key)) { | 1408 | * We have seen the sequence number has increased by 1. Now we need to |
| 1413 | /* | 1409 | * be sure we read the right LEB number, so read it again. |
| 1414 | * In this case the leaf node cache gets used, so we pass the | 1410 | */ |
| 1415 | * address of the zbranch and keep the mutex locked | 1411 | smp_rmb(); |
| 1416 | */ | 1412 | if (gced_lnum != c->gced_lnum) |
| 1417 | err = tnc_read_node_nm(c, zt, node); | 1413 | return 1; |
| 1418 | goto out; | 1414 | /* Finally we can check lnum */ |
| 1419 | } | 1415 | if (gced_lnum == lnum) |
| 1420 | zbr = znode->zbranch[n]; | 1416 | return 1; |
| 1421 | mutex_unlock(&c->tnc_mutex); | 1417 | return 0; |
| 1422 | |||
| 1423 | err = ubifs_tnc_read_node(c, &zbr, node); | ||
| 1424 | return err; | ||
| 1425 | |||
| 1426 | out: | ||
| 1427 | mutex_unlock(&c->tnc_mutex); | ||
| 1428 | return err; | ||
| 1429 | } | 1418 | } |
| 1430 | 1419 | ||
| 1431 | /** | 1420 | /** |
| @@ -1436,16 +1425,19 @@ out: | |||
| 1436 | * @lnum: LEB number is returned here | 1425 | * @lnum: LEB number is returned here |
| 1437 | * @offs: offset is returned here | 1426 | * @offs: offset is returned here |
| 1438 | * | 1427 | * |
| 1439 | * This function is the same as 'ubifs_tnc_lookup()' but it returns the node | 1428 | * This function look up and reads node with key @key. The caller has to make |
| 1440 | * location also. See 'ubifs_tnc_lookup()'. | 1429 | * sure the @node buffer is large enough to fit the node. Returns zero in case |
| 1430 | * of success, %-ENOENT if the node was not found, and a negative error code in | ||
| 1431 | * case of failure. The node location can be returned in @lnum and @offs. | ||
| 1441 | */ | 1432 | */ |
| 1442 | int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, | 1433 | int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, |
| 1443 | void *node, int *lnum, int *offs) | 1434 | void *node, int *lnum, int *offs) |
| 1444 | { | 1435 | { |
| 1445 | int found, n, err; | 1436 | int found, n, err, safely = 0, gc_seq1; |
| 1446 | struct ubifs_znode *znode; | 1437 | struct ubifs_znode *znode; |
| 1447 | struct ubifs_zbranch zbr, *zt; | 1438 | struct ubifs_zbranch zbr, *zt; |
| 1448 | 1439 | ||
| 1440 | again: | ||
| 1449 | mutex_lock(&c->tnc_mutex); | 1441 | mutex_lock(&c->tnc_mutex); |
| 1450 | found = ubifs_lookup_level0(c, key, &znode, &n); | 1442 | found = ubifs_lookup_level0(c, key, &znode, &n); |
| 1451 | if (!found) { | 1443 | if (!found) { |
| @@ -1456,24 +1448,43 @@ int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, | |||
| 1456 | goto out; | 1448 | goto out; |
| 1457 | } | 1449 | } |
| 1458 | zt = &znode->zbranch[n]; | 1450 | zt = &znode->zbranch[n]; |
| 1451 | if (lnum) { | ||
| 1452 | *lnum = zt->lnum; | ||
| 1453 | *offs = zt->offs; | ||
| 1454 | } | ||
| 1459 | if (is_hash_key(c, key)) { | 1455 | if (is_hash_key(c, key)) { |
| 1460 | /* | 1456 | /* |
| 1461 | * In this case the leaf node cache gets used, so we pass the | 1457 | * In this case the leaf node cache gets used, so we pass the |
| 1462 | * address of the zbranch and keep the mutex locked | 1458 | * address of the zbranch and keep the mutex locked |
| 1463 | */ | 1459 | */ |
| 1464 | *lnum = zt->lnum; | ||
| 1465 | *offs = zt->offs; | ||
| 1466 | err = tnc_read_node_nm(c, zt, node); | 1460 | err = tnc_read_node_nm(c, zt, node); |
| 1467 | goto out; | 1461 | goto out; |
| 1468 | } | 1462 | } |
| 1463 | if (safely) { | ||
| 1464 | err = ubifs_tnc_read_node(c, zt, node); | ||
| 1465 | goto out; | ||
| 1466 | } | ||
| 1467 | /* Drop the TNC mutex prematurely and race with garbage collection */ | ||
| 1469 | zbr = znode->zbranch[n]; | 1468 | zbr = znode->zbranch[n]; |
| 1469 | gc_seq1 = c->gc_seq; | ||
| 1470 | mutex_unlock(&c->tnc_mutex); | 1470 | mutex_unlock(&c->tnc_mutex); |
| 1471 | 1471 | ||
| 1472 | *lnum = zbr.lnum; | 1472 | if (ubifs_get_wbuf(c, zbr.lnum)) { |
| 1473 | *offs = zbr.offs; | 1473 | /* We do not GC journal heads */ |
| 1474 | err = ubifs_tnc_read_node(c, &zbr, node); | ||
| 1475 | return err; | ||
| 1476 | } | ||
| 1474 | 1477 | ||
| 1475 | err = ubifs_tnc_read_node(c, &zbr, node); | 1478 | err = fallible_read_node(c, key, &zbr, node); |
| 1476 | return err; | 1479 | if (maybe_leb_gced(c, zbr.lnum, gc_seq1)) { |
| 1480 | /* | ||
| 1481 | * The node may have been GC'ed out from under us so try again | ||
| 1482 | * while keeping the TNC mutex locked. | ||
| 1483 | */ | ||
| 1484 | safely = 1; | ||
| 1485 | goto again; | ||
| 1486 | } | ||
| 1487 | return 0; | ||
| 1477 | 1488 | ||
| 1478 | out: | 1489 | out: |
| 1479 | mutex_unlock(&c->tnc_mutex); | 1490 | mutex_unlock(&c->tnc_mutex); |
| @@ -1498,7 +1509,6 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, | |||
| 1498 | { | 1509 | { |
| 1499 | int found, n, err; | 1510 | int found, n, err; |
| 1500 | struct ubifs_znode *znode; | 1511 | struct ubifs_znode *znode; |
| 1501 | struct ubifs_zbranch zbr; | ||
| 1502 | 1512 | ||
| 1503 | dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key)); | 1513 | dbg_tnc("name '%.*s' key %s", nm->len, nm->name, DBGKEY(key)); |
| 1504 | mutex_lock(&c->tnc_mutex); | 1514 | mutex_lock(&c->tnc_mutex); |
| @@ -1522,11 +1532,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, | |||
| 1522 | goto out_unlock; | 1532 | goto out_unlock; |
| 1523 | } | 1533 | } |
| 1524 | 1534 | ||
| 1525 | zbr = znode->zbranch[n]; | 1535 | err = tnc_read_node_nm(c, &znode->zbranch[n], node); |
| 1526 | mutex_unlock(&c->tnc_mutex); | ||
| 1527 | |||
| 1528 | err = tnc_read_node_nm(c, &zbr, node); | ||
| 1529 | return err; | ||
| 1530 | 1536 | ||
| 1531 | out_unlock: | 1537 | out_unlock: |
| 1532 | mutex_unlock(&c->tnc_mutex); | 1538 | mutex_unlock(&c->tnc_mutex); |
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c index 8117e65ba2e9..8ac76b1c2d55 100644 --- a/fs/ubifs/tnc_commit.c +++ b/fs/ubifs/tnc_commit.c | |||
| @@ -372,26 +372,25 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt) | |||
| 372 | written = layout_leb_in_gaps(c, p); | 372 | written = layout_leb_in_gaps(c, p); |
| 373 | if (written < 0) { | 373 | if (written < 0) { |
| 374 | err = written; | 374 | err = written; |
| 375 | if (err == -ENOSPC) { | 375 | if (err != -ENOSPC) { |
| 376 | if (!dbg_force_in_the_gaps_enabled) { | 376 | kfree(c->gap_lebs); |
| 377 | /* | 377 | c->gap_lebs = NULL; |
| 378 | * Do not print scary warnings if the | 378 | return err; |
| 379 | * debugging option which forces | ||
| 380 | * in-the-gaps is enabled. | ||
| 381 | */ | ||
| 382 | ubifs_err("out of space"); | ||
| 383 | spin_lock(&c->space_lock); | ||
| 384 | dbg_dump_budg(c); | ||
| 385 | spin_unlock(&c->space_lock); | ||
| 386 | dbg_dump_lprops(c); | ||
| 387 | } | ||
| 388 | /* Try to commit anyway */ | ||
| 389 | err = 0; | ||
| 390 | break; | ||
| 391 | } | 379 | } |
| 392 | kfree(c->gap_lebs); | 380 | if (!dbg_force_in_the_gaps_enabled) { |
| 393 | c->gap_lebs = NULL; | 381 | /* |
| 394 | return err; | 382 | * Do not print scary warnings if the debugging |
| 383 | * option which forces in-the-gaps is enabled. | ||
| 384 | */ | ||
| 385 | ubifs_err("out of space"); | ||
| 386 | spin_lock(&c->space_lock); | ||
| 387 | dbg_dump_budg(c); | ||
| 388 | spin_unlock(&c->space_lock); | ||
| 389 | dbg_dump_lprops(c); | ||
| 390 | } | ||
| 391 | /* Try to commit anyway */ | ||
| 392 | err = 0; | ||
| 393 | break; | ||
| 395 | } | 394 | } |
| 396 | p++; | 395 | p++; |
| 397 | cnt -= written; | 396 | cnt -= written; |
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h index 0cc7da9bed47..a9ecbd9af20d 100644 --- a/fs/ubifs/ubifs-media.h +++ b/fs/ubifs/ubifs-media.h | |||
| @@ -87,7 +87,7 @@ | |||
| 87 | #define UBIFS_SK_LEN 8 | 87 | #define UBIFS_SK_LEN 8 |
| 88 | 88 | ||
| 89 | /* Minimum index tree fanout */ | 89 | /* Minimum index tree fanout */ |
| 90 | #define UBIFS_MIN_FANOUT 2 | 90 | #define UBIFS_MIN_FANOUT 3 |
| 91 | 91 | ||
| 92 | /* Maximum number of levels in UBIFS indexing B-tree */ | 92 | /* Maximum number of levels in UBIFS indexing B-tree */ |
| 93 | #define UBIFS_MAX_LEVELS 512 | 93 | #define UBIFS_MAX_LEVELS 512 |
| @@ -228,10 +228,10 @@ enum { | |||
| 228 | /* Minimum number of orphan area logical eraseblocks */ | 228 | /* Minimum number of orphan area logical eraseblocks */ |
| 229 | #define UBIFS_MIN_ORPH_LEBS 1 | 229 | #define UBIFS_MIN_ORPH_LEBS 1 |
| 230 | /* | 230 | /* |
| 231 | * Minimum number of main area logical eraseblocks (buds, 2 for the index, 1 | 231 | * Minimum number of main area logical eraseblocks (buds, 3 for the index, 1 |
| 232 | * for GC, 1 for deletions, and at least 1 for committed data). | 232 | * for GC, 1 for deletions, and at least 1 for committed data). |
| 233 | */ | 233 | */ |
| 234 | #define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 5) | 234 | #define UBIFS_MIN_MAIN_LEBS (UBIFS_MIN_BUD_LEBS + 6) |
| 235 | 235 | ||
| 236 | /* Minimum number of logical eraseblocks */ | 236 | /* Minimum number of logical eraseblocks */ |
| 237 | #define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \ | 237 | #define UBIFS_MIN_LEB_CNT (UBIFS_SB_LEBS + UBIFS_MST_LEBS + \ |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index e4f89f271827..17c620b93eec 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
| @@ -20,8 +20,6 @@ | |||
| 20 | * Adrian Hunter | 20 | * Adrian Hunter |
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | /* Implementation version 0.7 */ | ||
| 24 | |||
| 25 | #ifndef __UBIFS_H__ | 23 | #ifndef __UBIFS_H__ |
| 26 | #define __UBIFS_H__ | 24 | #define __UBIFS_H__ |
| 27 | 25 | ||
| @@ -322,6 +320,8 @@ struct ubifs_gced_idx_leb { | |||
| 322 | * struct ubifs_inode - UBIFS in-memory inode description. | 320 | * struct ubifs_inode - UBIFS in-memory inode description. |
| 323 | * @vfs_inode: VFS inode description object | 321 | * @vfs_inode: VFS inode description object |
| 324 | * @creat_sqnum: sequence number at time of creation | 322 | * @creat_sqnum: sequence number at time of creation |
| 323 | * @del_cmtno: commit number corresponding to the time the inode was deleted, | ||
| 324 | * protected by @c->commit_sem; | ||
| 325 | * @xattr_size: summarized size of all extended attributes in bytes | 325 | * @xattr_size: summarized size of all extended attributes in bytes |
| 326 | * @xattr_cnt: count of extended attributes this inode has | 326 | * @xattr_cnt: count of extended attributes this inode has |
| 327 | * @xattr_names: sum of lengths of all extended attribute names belonging to | 327 | * @xattr_names: sum of lengths of all extended attribute names belonging to |
| @@ -373,6 +373,7 @@ struct ubifs_gced_idx_leb { | |||
| 373 | struct ubifs_inode { | 373 | struct ubifs_inode { |
| 374 | struct inode vfs_inode; | 374 | struct inode vfs_inode; |
| 375 | unsigned long long creat_sqnum; | 375 | unsigned long long creat_sqnum; |
| 376 | unsigned long long del_cmtno; | ||
| 376 | unsigned int xattr_size; | 377 | unsigned int xattr_size; |
| 377 | unsigned int xattr_cnt; | 378 | unsigned int xattr_cnt; |
| 378 | unsigned int xattr_names; | 379 | unsigned int xattr_names; |
| @@ -779,7 +780,7 @@ struct ubifs_compressor { | |||
| 779 | /** | 780 | /** |
| 780 | * struct ubifs_budget_req - budget requirements of an operation. | 781 | * struct ubifs_budget_req - budget requirements of an operation. |
| 781 | * | 782 | * |
| 782 | * @fast: non-zero if the budgeting should try to aquire budget quickly and | 783 | * @fast: non-zero if the budgeting should try to acquire budget quickly and |
| 783 | * should not try to call write-back | 784 | * should not try to call write-back |
| 784 | * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields | 785 | * @recalculate: non-zero if @idx_growth, @data_growth, and @dd_growth fields |
| 785 | * have to be re-calculated | 786 | * have to be re-calculated |
| @@ -805,21 +806,31 @@ struct ubifs_compressor { | |||
| 805 | * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d | 806 | * An inode may contain 4KiB of data at max., thus the widths of @new_ino_d |
| 806 | * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made | 807 | * is 13 bits, and @dirtied_ino_d - 15, because up to 4 inodes may be made |
| 807 | * dirty by the re-name operation. | 808 | * dirty by the re-name operation. |
| 809 | * | ||
| 810 | * Note, UBIFS aligns node lengths to 8-bytes boundary, so the requester has to | ||
| 811 | * make sure the amount of inode data which contribute to @new_ino_d and | ||
| 812 | * @dirtied_ino_d fields are aligned. | ||
| 808 | */ | 813 | */ |
| 809 | struct ubifs_budget_req { | 814 | struct ubifs_budget_req { |
| 810 | unsigned int fast:1; | 815 | unsigned int fast:1; |
| 811 | unsigned int recalculate:1; | 816 | unsigned int recalculate:1; |
| 817 | #ifndef UBIFS_DEBUG | ||
| 812 | unsigned int new_page:1; | 818 | unsigned int new_page:1; |
| 813 | unsigned int dirtied_page:1; | 819 | unsigned int dirtied_page:1; |
| 814 | unsigned int new_dent:1; | 820 | unsigned int new_dent:1; |
| 815 | unsigned int mod_dent:1; | 821 | unsigned int mod_dent:1; |
| 816 | unsigned int new_ino:1; | 822 | unsigned int new_ino:1; |
| 817 | unsigned int new_ino_d:13; | 823 | unsigned int new_ino_d:13; |
| 818 | #ifndef UBIFS_DEBUG | ||
| 819 | unsigned int dirtied_ino:4; | 824 | unsigned int dirtied_ino:4; |
| 820 | unsigned int dirtied_ino_d:15; | 825 | unsigned int dirtied_ino_d:15; |
| 821 | #else | 826 | #else |
| 822 | /* Not bit-fields to check for overflows */ | 827 | /* Not bit-fields to check for overflows */ |
| 828 | unsigned int new_page; | ||
| 829 | unsigned int dirtied_page; | ||
| 830 | unsigned int new_dent; | ||
| 831 | unsigned int mod_dent; | ||
| 832 | unsigned int new_ino; | ||
| 833 | unsigned int new_ino_d; | ||
| 823 | unsigned int dirtied_ino; | 834 | unsigned int dirtied_ino; |
| 824 | unsigned int dirtied_ino_d; | 835 | unsigned int dirtied_ino_d; |
| 825 | #endif | 836 | #endif |
| @@ -860,13 +871,13 @@ struct ubifs_mount_opts { | |||
| 860 | * struct ubifs_info - UBIFS file-system description data structure | 871 | * struct ubifs_info - UBIFS file-system description data structure |
| 861 | * (per-superblock). | 872 | * (per-superblock). |
| 862 | * @vfs_sb: VFS @struct super_block object | 873 | * @vfs_sb: VFS @struct super_block object |
| 863 | * @bdi: backing device info object to make VFS happy and disable readahead | 874 | * @bdi: backing device info object to make VFS happy and disable read-ahead |
| 864 | * | 875 | * |
| 865 | * @highest_inum: highest used inode number | 876 | * @highest_inum: highest used inode number |
| 866 | * @vfs_gen: VFS inode generation counter | ||
| 867 | * @max_sqnum: current global sequence number | 877 | * @max_sqnum: current global sequence number |
| 868 | * @cmt_no: commit number (last successfully completed commit) | 878 | * @cmt_no: commit number of the last successfully completed commit, protected |
| 869 | * @cnt_lock: protects @highest_inum, @vfs_gen, and @max_sqnum counters | 879 | * by @commit_sem |
| 880 | * @cnt_lock: protects @highest_inum and @max_sqnum counters | ||
| 870 | * @fmt_version: UBIFS on-flash format version | 881 | * @fmt_version: UBIFS on-flash format version |
| 871 | * @uuid: UUID from super block | 882 | * @uuid: UUID from super block |
| 872 | * | 883 | * |
| @@ -984,6 +995,9 @@ struct ubifs_mount_opts { | |||
| 984 | * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary | 995 | * @max_idx_node_sz: maximum indexing node aligned on 8-bytes boundary |
| 985 | * @max_inode_sz: maximum possible inode size in bytes | 996 | * @max_inode_sz: maximum possible inode size in bytes |
| 986 | * @max_znode_sz: size of znode in bytes | 997 | * @max_znode_sz: size of znode in bytes |
| 998 | * | ||
| 999 | * @leb_overhead: how many bytes are wasted in an LEB when it is filled with | ||
| 1000 | * data nodes of maximum size - used in free space reporting | ||
| 987 | * @dead_wm: LEB dead space watermark | 1001 | * @dead_wm: LEB dead space watermark |
| 988 | * @dark_wm: LEB dark space watermark | 1002 | * @dark_wm: LEB dark space watermark |
| 989 | * @block_cnt: count of 4KiB blocks on the FS | 1003 | * @block_cnt: count of 4KiB blocks on the FS |
| @@ -1017,6 +1031,8 @@ struct ubifs_mount_opts { | |||
| 1017 | * @sbuf: a buffer of LEB size used by GC and replay for scanning | 1031 | * @sbuf: a buffer of LEB size used by GC and replay for scanning |
| 1018 | * @idx_gc: list of index LEBs that have been garbage collected | 1032 | * @idx_gc: list of index LEBs that have been garbage collected |
| 1019 | * @idx_gc_cnt: number of elements on the idx_gc list | 1033 | * @idx_gc_cnt: number of elements on the idx_gc list |
| 1034 | * @gc_seq: incremented for every non-index LEB garbage collected | ||
| 1035 | * @gced_lnum: last non-index LEB that was garbage collected | ||
| 1020 | * | 1036 | * |
| 1021 | * @infos_list: links all 'ubifs_info' objects | 1037 | * @infos_list: links all 'ubifs_info' objects |
| 1022 | * @umount_mutex: serializes shrinker and un-mount | 1038 | * @umount_mutex: serializes shrinker and un-mount |
| @@ -1103,7 +1119,6 @@ struct ubifs_info { | |||
| 1103 | struct backing_dev_info bdi; | 1119 | struct backing_dev_info bdi; |
| 1104 | 1120 | ||
| 1105 | ino_t highest_inum; | 1121 | ino_t highest_inum; |
| 1106 | unsigned int vfs_gen; | ||
| 1107 | unsigned long long max_sqnum; | 1122 | unsigned long long max_sqnum; |
| 1108 | unsigned long long cmt_no; | 1123 | unsigned long long cmt_no; |
| 1109 | spinlock_t cnt_lock; | 1124 | spinlock_t cnt_lock; |
| @@ -1214,6 +1229,8 @@ struct ubifs_info { | |||
| 1214 | int max_idx_node_sz; | 1229 | int max_idx_node_sz; |
| 1215 | long long max_inode_sz; | 1230 | long long max_inode_sz; |
| 1216 | int max_znode_sz; | 1231 | int max_znode_sz; |
| 1232 | |||
| 1233 | int leb_overhead; | ||
| 1217 | int dead_wm; | 1234 | int dead_wm; |
| 1218 | int dark_wm; | 1235 | int dark_wm; |
| 1219 | int block_cnt; | 1236 | int block_cnt; |
| @@ -1247,6 +1264,8 @@ struct ubifs_info { | |||
| 1247 | void *sbuf; | 1264 | void *sbuf; |
| 1248 | struct list_head idx_gc; | 1265 | struct list_head idx_gc; |
| 1249 | int idx_gc_cnt; | 1266 | int idx_gc_cnt; |
| 1267 | volatile int gc_seq; | ||
| 1268 | volatile int gced_lnum; | ||
| 1250 | 1269 | ||
| 1251 | struct list_head infos_list; | 1270 | struct list_head infos_list; |
| 1252 | struct mutex umount_mutex; | 1271 | struct mutex umount_mutex; |
| @@ -1346,6 +1365,7 @@ extern struct backing_dev_info ubifs_backing_dev_info; | |||
| 1346 | extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; | 1365 | extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; |
| 1347 | 1366 | ||
| 1348 | /* io.c */ | 1367 | /* io.c */ |
| 1368 | void ubifs_ro_mode(struct ubifs_info *c, int err); | ||
| 1349 | int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len); | 1369 | int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len); |
| 1350 | int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, | 1370 | int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, |
| 1351 | int dtype); | 1371 | int dtype); |
| @@ -1399,8 +1419,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, | |||
| 1399 | int deletion, int xent); | 1419 | int deletion, int xent); |
| 1400 | int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, | 1420 | int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, |
| 1401 | const union ubifs_key *key, const void *buf, int len); | 1421 | const union ubifs_key *key, const void *buf, int len); |
| 1402 | int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode, | 1422 | int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode); |
| 1403 | int last_reference); | 1423 | int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode); |
| 1404 | int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, | 1424 | int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, |
| 1405 | const struct dentry *old_dentry, | 1425 | const struct dentry *old_dentry, |
| 1406 | const struct inode *new_dir, | 1426 | const struct inode *new_dir, |
| @@ -1423,9 +1443,10 @@ void ubifs_release_ino_dirty(struct ubifs_info *c, struct inode *inode, | |||
| 1423 | struct ubifs_budget_req *req); | 1443 | struct ubifs_budget_req *req); |
| 1424 | void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, | 1444 | void ubifs_cancel_ino_op(struct ubifs_info *c, struct inode *inode, |
| 1425 | struct ubifs_budget_req *req); | 1445 | struct ubifs_budget_req *req); |
| 1426 | long long ubifs_budg_get_free_space(struct ubifs_info *c); | 1446 | long long ubifs_get_free_space(struct ubifs_info *c); |
| 1427 | int ubifs_calc_min_idx_lebs(struct ubifs_info *c); | 1447 | int ubifs_calc_min_idx_lebs(struct ubifs_info *c); |
| 1428 | void ubifs_convert_page_budget(struct ubifs_info *c); | 1448 | void ubifs_convert_page_budget(struct ubifs_info *c); |
| 1449 | long long ubifs_reported_space(const struct ubifs_info *c, uint64_t free); | ||
| 1429 | long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs); | 1450 | long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs); |
| 1430 | 1451 | ||
| 1431 | /* find.c */ | 1452 | /* find.c */ |
| @@ -1440,8 +1461,6 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c); | |||
| 1440 | /* tnc.c */ | 1461 | /* tnc.c */ |
| 1441 | int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, | 1462 | int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, |
| 1442 | struct ubifs_znode **zn, int *n); | 1463 | struct ubifs_znode **zn, int *n); |
| 1443 | int ubifs_tnc_lookup(struct ubifs_info *c, const union ubifs_key *key, | ||
| 1444 | void *node); | ||
| 1445 | int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, | 1464 | int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, |
| 1446 | void *node, const struct qstr *nm); | 1465 | void *node, const struct qstr *nm); |
| 1447 | int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, | 1466 | int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, |
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 1388a078e1a9..649bec78b645 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c | |||
| @@ -61,7 +61,7 @@ | |||
| 61 | 61 | ||
| 62 | /* | 62 | /* |
| 63 | * Limit the number of extended attributes per inode so that the total size | 63 | * Limit the number of extended attributes per inode so that the total size |
| 64 | * (xattr_size) is guaranteeded to fit in an 'unsigned int'. | 64 | * (@xattr_size) is guaranteeded to fit in an 'unsigned int'. |
| 65 | */ | 65 | */ |
| 66 | #define MAX_XATTRS_PER_INODE 65535 | 66 | #define MAX_XATTRS_PER_INODE 65535 |
| 67 | 67 | ||
| @@ -103,14 +103,14 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, | |||
| 103 | struct inode *inode; | 103 | struct inode *inode; |
| 104 | struct ubifs_inode *ui, *host_ui = ubifs_inode(host); | 104 | struct ubifs_inode *ui, *host_ui = ubifs_inode(host); |
| 105 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, | 105 | struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, |
| 106 | .new_ino_d = size, .dirtied_ino = 1, | 106 | .new_ino_d = ALIGN(size, 8), .dirtied_ino = 1, |
| 107 | .dirtied_ino_d = host_ui->data_len}; | 107 | .dirtied_ino_d = ALIGN(host_ui->data_len, 8) }; |
| 108 | 108 | ||
| 109 | if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) | 109 | if (host_ui->xattr_cnt >= MAX_XATTRS_PER_INODE) |
| 110 | return -ENOSPC; | 110 | return -ENOSPC; |
| 111 | /* | 111 | /* |
| 112 | * Linux limits the maximum size of the extended attribute names list | 112 | * Linux limits the maximum size of the extended attribute names list |
| 113 | * to %XATTR_LIST_MAX. This means we should not allow creating more* | 113 | * to %XATTR_LIST_MAX. This means we should not allow creating more |
| 114 | * extended attributes if the name list becomes larger. This limitation | 114 | * extended attributes if the name list becomes larger. This limitation |
| 115 | * is artificial for UBIFS, though. | 115 | * is artificial for UBIFS, though. |
| 116 | */ | 116 | */ |
| @@ -128,7 +128,6 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, | |||
| 128 | goto out_budg; | 128 | goto out_budg; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | mutex_lock(&host_ui->ui_mutex); | ||
| 132 | /* Re-define all operations to be "nothing" */ | 131 | /* Re-define all operations to be "nothing" */ |
| 133 | inode->i_mapping->a_ops = &none_address_operations; | 132 | inode->i_mapping->a_ops = &none_address_operations; |
| 134 | inode->i_op = &none_inode_operations; | 133 | inode->i_op = &none_inode_operations; |
| @@ -141,23 +140,19 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, | |||
| 141 | ui->data = kmalloc(size, GFP_NOFS); | 140 | ui->data = kmalloc(size, GFP_NOFS); |
| 142 | if (!ui->data) { | 141 | if (!ui->data) { |
| 143 | err = -ENOMEM; | 142 | err = -ENOMEM; |
| 144 | goto out_unlock; | 143 | goto out_free; |
| 145 | } | 144 | } |
| 146 | |||
| 147 | memcpy(ui->data, value, size); | 145 | memcpy(ui->data, value, size); |
| 146 | inode->i_size = ui->ui_size = size; | ||
| 147 | ui->data_len = size; | ||
| 148 | |||
| 149 | mutex_lock(&host_ui->ui_mutex); | ||
| 148 | host->i_ctime = ubifs_current_time(host); | 150 | host->i_ctime = ubifs_current_time(host); |
| 149 | host_ui->xattr_cnt += 1; | 151 | host_ui->xattr_cnt += 1; |
| 150 | host_ui->xattr_size += CALC_DENT_SIZE(nm->len); | 152 | host_ui->xattr_size += CALC_DENT_SIZE(nm->len); |
| 151 | host_ui->xattr_size += CALC_XATTR_BYTES(size); | 153 | host_ui->xattr_size += CALC_XATTR_BYTES(size); |
| 152 | host_ui->xattr_names += nm->len; | 154 | host_ui->xattr_names += nm->len; |
| 153 | 155 | ||
| 154 | /* | ||
| 155 | * We do not use i_size_write() because nobody can race with us as we | ||
| 156 | * are holding host @host->i_mutex - every xattr operation for this | ||
| 157 | * inode is serialized by it. | ||
| 158 | */ | ||
| 159 | inode->i_size = ui->ui_size = size; | ||
| 160 | ui->data_len = size; | ||
| 161 | err = ubifs_jnl_update(c, host, nm, inode, 0, 1); | 156 | err = ubifs_jnl_update(c, host, nm, inode, 0, 1); |
| 162 | if (err) | 157 | if (err) |
| 163 | goto out_cancel; | 158 | goto out_cancel; |
| @@ -172,8 +167,8 @@ out_cancel: | |||
| 172 | host_ui->xattr_cnt -= 1; | 167 | host_ui->xattr_cnt -= 1; |
| 173 | host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); | 168 | host_ui->xattr_size -= CALC_DENT_SIZE(nm->len); |
| 174 | host_ui->xattr_size -= CALC_XATTR_BYTES(size); | 169 | host_ui->xattr_size -= CALC_XATTR_BYTES(size); |
| 175 | out_unlock: | ||
| 176 | mutex_unlock(&host_ui->ui_mutex); | 170 | mutex_unlock(&host_ui->ui_mutex); |
| 171 | out_free: | ||
| 177 | make_bad_inode(inode); | 172 | make_bad_inode(inode); |
| 178 | iput(inode); | 173 | iput(inode); |
| 179 | out_budg: | 174 | out_budg: |
| @@ -200,29 +195,28 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, | |||
| 200 | struct ubifs_inode *host_ui = ubifs_inode(host); | 195 | struct ubifs_inode *host_ui = ubifs_inode(host); |
| 201 | struct ubifs_inode *ui = ubifs_inode(inode); | 196 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 202 | struct ubifs_budget_req req = { .dirtied_ino = 2, | 197 | struct ubifs_budget_req req = { .dirtied_ino = 2, |
| 203 | .dirtied_ino_d = size + host_ui->data_len }; | 198 | .dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) }; |
| 204 | 199 | ||
| 205 | ubifs_assert(ui->data_len == inode->i_size); | 200 | ubifs_assert(ui->data_len == inode->i_size); |
| 206 | err = ubifs_budget_space(c, &req); | 201 | err = ubifs_budget_space(c, &req); |
| 207 | if (err) | 202 | if (err) |
| 208 | return err; | 203 | return err; |
| 209 | 204 | ||
| 210 | mutex_lock(&host_ui->ui_mutex); | ||
| 211 | host->i_ctime = ubifs_current_time(host); | ||
| 212 | host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); | ||
| 213 | host_ui->xattr_size += CALC_XATTR_BYTES(size); | ||
| 214 | |||
| 215 | kfree(ui->data); | 205 | kfree(ui->data); |
| 216 | ui->data = kmalloc(size, GFP_NOFS); | 206 | ui->data = kmalloc(size, GFP_NOFS); |
| 217 | if (!ui->data) { | 207 | if (!ui->data) { |
| 218 | err = -ENOMEM; | 208 | err = -ENOMEM; |
| 219 | goto out_unlock; | 209 | goto out_free; |
| 220 | } | 210 | } |
| 221 | |||
| 222 | memcpy(ui->data, value, size); | 211 | memcpy(ui->data, value, size); |
| 223 | inode->i_size = ui->ui_size = size; | 212 | inode->i_size = ui->ui_size = size; |
| 224 | ui->data_len = size; | 213 | ui->data_len = size; |
| 225 | 214 | ||
| 215 | mutex_lock(&host_ui->ui_mutex); | ||
| 216 | host->i_ctime = ubifs_current_time(host); | ||
| 217 | host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len); | ||
| 218 | host_ui->xattr_size += CALC_XATTR_BYTES(size); | ||
| 219 | |||
| 226 | /* | 220 | /* |
| 227 | * It is important to write the host inode after the xattr inode | 221 | * It is important to write the host inode after the xattr inode |
| 228 | * because if the host inode gets synchronized (via 'fsync()'), then | 222 | * because if the host inode gets synchronized (via 'fsync()'), then |
| @@ -240,9 +234,9 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, | |||
| 240 | out_cancel: | 234 | out_cancel: |
| 241 | host_ui->xattr_size -= CALC_XATTR_BYTES(size); | 235 | host_ui->xattr_size -= CALC_XATTR_BYTES(size); |
| 242 | host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); | 236 | host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len); |
| 243 | make_bad_inode(inode); | ||
| 244 | out_unlock: | ||
| 245 | mutex_unlock(&host_ui->ui_mutex); | 237 | mutex_unlock(&host_ui->ui_mutex); |
| 238 | make_bad_inode(inode); | ||
| 239 | out_free: | ||
| 246 | ubifs_release_budget(c, &req); | 240 | ubifs_release_budget(c, &req); |
| 247 | return err; | 241 | return err; |
| 248 | } | 242 | } |
| @@ -312,6 +306,7 @@ int ubifs_setxattr(struct dentry *dentry, const char *name, | |||
| 312 | 306 | ||
| 313 | dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name, | 307 | dbg_gen("xattr '%s', host ino %lu ('%.*s'), size %zd", name, |
| 314 | host->i_ino, dentry->d_name.len, dentry->d_name.name, size); | 308 | host->i_ino, dentry->d_name.len, dentry->d_name.name, size); |
| 309 | ubifs_assert(mutex_is_locked(&host->i_mutex)); | ||
| 315 | 310 | ||
| 316 | if (size > UBIFS_MAX_INO_DATA) | 311 | if (size > UBIFS_MAX_INO_DATA) |
| 317 | return -ERANGE; | 312 | return -ERANGE; |
| @@ -384,7 +379,6 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, | |||
| 384 | if (!xent) | 379 | if (!xent) |
| 385 | return -ENOMEM; | 380 | return -ENOMEM; |
| 386 | 381 | ||
| 387 | mutex_lock(&host->i_mutex); | ||
| 388 | xent_key_init(c, &key, host->i_ino, &nm); | 382 | xent_key_init(c, &key, host->i_ino, &nm); |
| 389 | err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); | 383 | err = ubifs_tnc_lookup_nm(c, &key, xent, &nm); |
| 390 | if (err) { | 384 | if (err) { |
| @@ -419,7 +413,6 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, | |||
| 419 | out_iput: | 413 | out_iput: |
| 420 | iput(inode); | 414 | iput(inode); |
| 421 | out_unlock: | 415 | out_unlock: |
| 422 | mutex_unlock(&host->i_mutex); | ||
| 423 | kfree(xent); | 416 | kfree(xent); |
| 424 | return err; | 417 | return err; |
| 425 | } | 418 | } |
| @@ -449,8 +442,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
| 449 | return -ERANGE; | 442 | return -ERANGE; |
| 450 | 443 | ||
| 451 | lowest_xent_key(c, &key, host->i_ino); | 444 | lowest_xent_key(c, &key, host->i_ino); |
| 452 | |||
| 453 | mutex_lock(&host->i_mutex); | ||
| 454 | while (1) { | 445 | while (1) { |
| 455 | int type; | 446 | int type; |
| 456 | 447 | ||
| @@ -479,7 +470,6 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
| 479 | pxent = xent; | 470 | pxent = xent; |
| 480 | key_read(c, &xent->key, &key); | 471 | key_read(c, &xent->key, &key); |
| 481 | } | 472 | } |
| 482 | mutex_unlock(&host->i_mutex); | ||
| 483 | 473 | ||
| 484 | kfree(pxent); | 474 | kfree(pxent); |
| 485 | if (err != -ENOENT) { | 475 | if (err != -ENOENT) { |
| @@ -497,8 +487,8 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host, | |||
| 497 | int err; | 487 | int err; |
| 498 | struct ubifs_inode *host_ui = ubifs_inode(host); | 488 | struct ubifs_inode *host_ui = ubifs_inode(host); |
| 499 | struct ubifs_inode *ui = ubifs_inode(inode); | 489 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 500 | struct ubifs_budget_req req = { .dirtied_ino = 1, .mod_dent = 1, | 490 | struct ubifs_budget_req req = { .dirtied_ino = 2, .mod_dent = 1, |
| 501 | .dirtied_ino_d = host_ui->data_len }; | 491 | .dirtied_ino_d = ALIGN(host_ui->data_len, 8) }; |
| 502 | 492 | ||
| 503 | ubifs_assert(ui->data_len == inode->i_size); | 493 | ubifs_assert(ui->data_len == inode->i_size); |
| 504 | 494 | ||
diff --git a/fs/udf/file.c b/fs/udf/file.c index 0ed6e146a0d9..eb91f3b70320 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
| @@ -211,6 +211,7 @@ const struct file_operations udf_file_operations = { | |||
| 211 | .release = udf_release_file, | 211 | .release = udf_release_file, |
| 212 | .fsync = udf_fsync_file, | 212 | .fsync = udf_fsync_file, |
| 213 | .splice_read = generic_file_splice_read, | 213 | .splice_read = generic_file_splice_read, |
| 214 | .llseek = generic_file_llseek, | ||
| 214 | }; | 215 | }; |
| 215 | 216 | ||
| 216 | const struct inode_operations udf_file_inode_operations = { | 217 | const struct inode_operations udf_file_inode_operations = { |
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index eb9cfa23dc3d..a4f2b3ce45b0 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c | |||
| @@ -76,11 +76,24 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) | |||
| 76 | *err = -ENOSPC; | 76 | *err = -ENOSPC; |
| 77 | 77 | ||
| 78 | iinfo = UDF_I(inode); | 78 | iinfo = UDF_I(inode); |
| 79 | iinfo->i_unique = 0; | 79 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) { |
| 80 | iinfo->i_lenExtents = 0; | 80 | iinfo->i_efe = 1; |
| 81 | iinfo->i_next_alloc_block = 0; | 81 | if (UDF_VERS_USE_EXTENDED_FE > sbi->s_udfrev) |
| 82 | iinfo->i_next_alloc_goal = 0; | 82 | sbi->s_udfrev = UDF_VERS_USE_EXTENDED_FE; |
| 83 | iinfo->i_strat4096 = 0; | 83 | iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize - |
| 84 | sizeof(struct extendedFileEntry), | ||
| 85 | GFP_KERNEL); | ||
| 86 | } else { | ||
| 87 | iinfo->i_efe = 0; | ||
| 88 | iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize - | ||
| 89 | sizeof(struct fileEntry), | ||
| 90 | GFP_KERNEL); | ||
| 91 | } | ||
| 92 | if (!iinfo->i_ext.i_data) { | ||
| 93 | iput(inode); | ||
| 94 | *err = -ENOMEM; | ||
| 95 | return NULL; | ||
| 96 | } | ||
| 84 | 97 | ||
| 85 | block = udf_new_block(dir->i_sb, NULL, | 98 | block = udf_new_block(dir->i_sb, NULL, |
| 86 | dinfo->i_location.partitionReferenceNum, | 99 | dinfo->i_location.partitionReferenceNum, |
| @@ -111,6 +124,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) | |||
| 111 | lvhd->uniqueID = cpu_to_le64(uniqueID); | 124 | lvhd->uniqueID = cpu_to_le64(uniqueID); |
| 112 | mark_buffer_dirty(sbi->s_lvid_bh); | 125 | mark_buffer_dirty(sbi->s_lvid_bh); |
| 113 | } | 126 | } |
| 127 | mutex_unlock(&sbi->s_alloc_mutex); | ||
| 114 | inode->i_mode = mode; | 128 | inode->i_mode = mode; |
| 115 | inode->i_uid = current->fsuid; | 129 | inode->i_uid = current->fsuid; |
| 116 | if (dir->i_mode & S_ISGID) { | 130 | if (dir->i_mode & S_ISGID) { |
| @@ -129,25 +143,6 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) | |||
| 129 | iinfo->i_lenEAttr = 0; | 143 | iinfo->i_lenEAttr = 0; |
| 130 | iinfo->i_lenAlloc = 0; | 144 | iinfo->i_lenAlloc = 0; |
| 131 | iinfo->i_use = 0; | 145 | iinfo->i_use = 0; |
| 132 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) { | ||
| 133 | iinfo->i_efe = 1; | ||
| 134 | if (UDF_VERS_USE_EXTENDED_FE > sbi->s_udfrev) | ||
| 135 | sbi->s_udfrev = UDF_VERS_USE_EXTENDED_FE; | ||
| 136 | iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize - | ||
| 137 | sizeof(struct extendedFileEntry), | ||
| 138 | GFP_KERNEL); | ||
| 139 | } else { | ||
| 140 | iinfo->i_efe = 0; | ||
| 141 | iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize - | ||
| 142 | sizeof(struct fileEntry), | ||
| 143 | GFP_KERNEL); | ||
| 144 | } | ||
| 145 | if (!iinfo->i_ext.i_data) { | ||
| 146 | iput(inode); | ||
| 147 | *err = -ENOMEM; | ||
| 148 | mutex_unlock(&sbi->s_alloc_mutex); | ||
| 149 | return NULL; | ||
| 150 | } | ||
| 151 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB)) | 146 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB)) |
| 152 | iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; | 147 | iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; |
| 153 | else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) | 148 | else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) |
| @@ -158,7 +153,6 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) | |||
| 158 | iinfo->i_crtime = current_fs_time(inode->i_sb); | 153 | iinfo->i_crtime = current_fs_time(inode->i_sb); |
| 159 | insert_inode_hash(inode); | 154 | insert_inode_hash(inode); |
| 160 | mark_inode_dirty(inode); | 155 | mark_inode_dirty(inode); |
| 161 | mutex_unlock(&sbi->s_alloc_mutex); | ||
| 162 | 156 | ||
| 163 | if (DQUOT_ALLOC_INODE(inode)) { | 157 | if (DQUOT_ALLOC_INODE(inode)) { |
| 164 | DQUOT_DROP(inode); | 158 | DQUOT_DROP(inode); |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 44cc702f96cc..5698bbf83bbf 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
| @@ -148,7 +148,7 @@ static void udf_destroy_inode(struct inode *inode) | |||
| 148 | kmem_cache_free(udf_inode_cachep, UDF_I(inode)); | 148 | kmem_cache_free(udf_inode_cachep, UDF_I(inode)); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | static void init_once(struct kmem_cache *cachep, void *foo) | 151 | static void init_once(void *foo) |
| 152 | { | 152 | { |
| 153 | struct udf_inode_info *ei = (struct udf_inode_info *)foo; | 153 | struct udf_inode_info *ei = (struct udf_inode_info *)foo; |
| 154 | 154 | ||
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 506f724055c2..3141969b456d 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
| @@ -76,6 +76,7 @@ | |||
| 76 | 76 | ||
| 77 | #include <linux/errno.h> | 77 | #include <linux/errno.h> |
| 78 | #include <linux/fs.h> | 78 | #include <linux/fs.h> |
| 79 | #include <linux/quotaops.h> | ||
| 79 | #include <linux/slab.h> | 80 | #include <linux/slab.h> |
| 80 | #include <linux/time.h> | 81 | #include <linux/time.h> |
| 81 | #include <linux/stat.h> | 82 | #include <linux/stat.h> |
| @@ -1232,7 +1233,7 @@ static int ufs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
| 1232 | { | 1233 | { |
| 1233 | struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb); | 1234 | struct ufs_sb_info *sbi = UFS_SB(vfs->mnt_sb); |
| 1234 | unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; | 1235 | unsigned mval = sbi->s_mount_opt & UFS_MOUNT_UFSTYPE; |
| 1235 | const struct match_token *tp = tokens; | 1236 | struct match_token *tp = tokens; |
| 1236 | 1237 | ||
| 1237 | while (tp->token != Opt_onerror_panic && tp->token != mval) | 1238 | while (tp->token != Opt_onerror_panic && tp->token != mval) |
| 1238 | ++tp; | 1239 | ++tp; |
| @@ -1301,7 +1302,7 @@ static void ufs_destroy_inode(struct inode *inode) | |||
| 1301 | kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); | 1302 | kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); |
| 1302 | } | 1303 | } |
| 1303 | 1304 | ||
| 1304 | static void init_once(struct kmem_cache * cachep, void *foo) | 1305 | static void init_once(void *foo) |
| 1305 | { | 1306 | { |
| 1306 | struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; | 1307 | struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; |
| 1307 | 1308 | ||
diff --git a/fs/utimes.c b/fs/utimes.c index b6b664e7145e..6929e3e91d05 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
| @@ -48,66 +48,22 @@ static bool nsec_valid(long nsec) | |||
| 48 | return nsec >= 0 && nsec <= 999999999; | 48 | return nsec >= 0 && nsec <= 999999999; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | /* If times==NULL, set access and modification to current time, | 51 | static int utimes_common(struct path *path, struct timespec *times) |
| 52 | * must be owner or have write permission. | ||
| 53 | * Else, update from *times, must be owner or super user. | ||
| 54 | */ | ||
| 55 | long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) | ||
| 56 | { | 52 | { |
| 57 | int error; | 53 | int error; |
| 58 | struct nameidata nd; | ||
| 59 | struct dentry *dentry; | ||
| 60 | struct inode *inode; | ||
| 61 | struct iattr newattrs; | 54 | struct iattr newattrs; |
| 62 | struct file *f = NULL; | 55 | struct inode *inode = path->dentry->d_inode; |
| 63 | struct vfsmount *mnt; | ||
| 64 | |||
| 65 | error = -EINVAL; | ||
| 66 | if (times && (!nsec_valid(times[0].tv_nsec) || | ||
| 67 | !nsec_valid(times[1].tv_nsec))) { | ||
| 68 | goto out; | ||
| 69 | } | ||
| 70 | |||
| 71 | if (flags & ~AT_SYMLINK_NOFOLLOW) | ||
| 72 | goto out; | ||
| 73 | |||
| 74 | if (filename == NULL && dfd != AT_FDCWD) { | ||
| 75 | error = -EINVAL; | ||
| 76 | if (flags & AT_SYMLINK_NOFOLLOW) | ||
| 77 | goto out; | ||
| 78 | 56 | ||
| 79 | error = -EBADF; | 57 | error = mnt_want_write(path->mnt); |
| 80 | f = fget(dfd); | ||
| 81 | if (!f) | ||
| 82 | goto out; | ||
| 83 | dentry = f->f_path.dentry; | ||
| 84 | mnt = f->f_path.mnt; | ||
| 85 | } else { | ||
| 86 | error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd); | ||
| 87 | if (error) | ||
| 88 | goto out; | ||
| 89 | |||
| 90 | dentry = nd.path.dentry; | ||
| 91 | mnt = nd.path.mnt; | ||
| 92 | } | ||
| 93 | |||
| 94 | inode = dentry->d_inode; | ||
| 95 | |||
| 96 | error = mnt_want_write(mnt); | ||
| 97 | if (error) | 58 | if (error) |
| 98 | goto dput_and_out; | 59 | goto out; |
| 99 | 60 | ||
| 100 | if (times && times[0].tv_nsec == UTIME_NOW && | 61 | if (times && times[0].tv_nsec == UTIME_NOW && |
| 101 | times[1].tv_nsec == UTIME_NOW) | 62 | times[1].tv_nsec == UTIME_NOW) |
| 102 | times = NULL; | 63 | times = NULL; |
| 103 | 64 | ||
| 104 | /* In most cases, the checks are done in inode_change_ok() */ | ||
| 105 | newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; | 65 | newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; |
| 106 | if (times) { | 66 | if (times) { |
| 107 | error = -EPERM; | ||
| 108 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
| 109 | goto mnt_drop_write_and_out; | ||
| 110 | |||
| 111 | if (times[0].tv_nsec == UTIME_OMIT) | 67 | if (times[0].tv_nsec == UTIME_OMIT) |
| 112 | newattrs.ia_valid &= ~ATTR_ATIME; | 68 | newattrs.ia_valid &= ~ATTR_ATIME; |
| 113 | else if (times[0].tv_nsec != UTIME_NOW) { | 69 | else if (times[0].tv_nsec != UTIME_NOW) { |
| @@ -123,21 +79,13 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
| 123 | newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; | 79 | newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; |
| 124 | newattrs.ia_valid |= ATTR_MTIME_SET; | 80 | newattrs.ia_valid |= ATTR_MTIME_SET; |
| 125 | } | 81 | } |
| 126 | |||
| 127 | /* | 82 | /* |
| 128 | * For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT | 83 | * Tell inode_change_ok(), that this is an explicit time |
| 129 | * cases, we need to make an extra check that is not done by | 84 | * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET |
| 130 | * inode_change_ok(). | 85 | * were used. |
| 131 | */ | 86 | */ |
| 132 | if (((times[0].tv_nsec == UTIME_NOW && | 87 | newattrs.ia_valid |= ATTR_TIMES_SET; |
| 133 | times[1].tv_nsec == UTIME_OMIT) | ||
| 134 | || | ||
| 135 | (times[0].tv_nsec == UTIME_OMIT && | ||
| 136 | times[1].tv_nsec == UTIME_NOW)) | ||
| 137 | && !is_owner_or_cap(inode)) | ||
| 138 | goto mnt_drop_write_and_out; | ||
| 139 | } else { | 88 | } else { |
| 140 | |||
| 141 | /* | 89 | /* |
| 142 | * If times is NULL (or both times are UTIME_NOW), | 90 | * If times is NULL (or both times are UTIME_NOW), |
| 143 | * then we need to check permissions, because | 91 | * then we need to check permissions, because |
| @@ -148,21 +96,76 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
| 148 | goto mnt_drop_write_and_out; | 96 | goto mnt_drop_write_and_out; |
| 149 | 97 | ||
| 150 | if (!is_owner_or_cap(inode)) { | 98 | if (!is_owner_or_cap(inode)) { |
| 151 | error = permission(inode, MAY_WRITE, NULL); | 99 | error = inode_permission(inode, MAY_WRITE); |
| 152 | if (error) | 100 | if (error) |
| 153 | goto mnt_drop_write_and_out; | 101 | goto mnt_drop_write_and_out; |
| 154 | } | 102 | } |
| 155 | } | 103 | } |
| 156 | mutex_lock(&inode->i_mutex); | 104 | mutex_lock(&inode->i_mutex); |
| 157 | error = notify_change(dentry, &newattrs); | 105 | error = notify_change(path->dentry, &newattrs); |
| 158 | mutex_unlock(&inode->i_mutex); | 106 | mutex_unlock(&inode->i_mutex); |
| 107 | |||
| 159 | mnt_drop_write_and_out: | 108 | mnt_drop_write_and_out: |
| 160 | mnt_drop_write(mnt); | 109 | mnt_drop_write(path->mnt); |
| 161 | dput_and_out: | 110 | out: |
| 162 | if (f) | 111 | return error; |
| 163 | fput(f); | 112 | } |
| 164 | else | 113 | |
| 165 | path_put(&nd.path); | 114 | /* |
| 115 | * do_utimes - change times on filename or file descriptor | ||
| 116 | * @dfd: open file descriptor, -1 or AT_FDCWD | ||
| 117 | * @filename: path name or NULL | ||
| 118 | * @times: new times or NULL | ||
| 119 | * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) | ||
| 120 | * | ||
| 121 | * If filename is NULL and dfd refers to an open file, then operate on | ||
| 122 | * the file. Otherwise look up filename, possibly using dfd as a | ||
| 123 | * starting point. | ||
| 124 | * | ||
| 125 | * If times==NULL, set access and modification to current time, | ||
| 126 | * must be owner or have write permission. | ||
| 127 | * Else, update from *times, must be owner or super user. | ||
| 128 | */ | ||
| 129 | long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) | ||
| 130 | { | ||
| 131 | int error = -EINVAL; | ||
| 132 | |||
| 133 | if (times && (!nsec_valid(times[0].tv_nsec) || | ||
| 134 | !nsec_valid(times[1].tv_nsec))) { | ||
| 135 | goto out; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (flags & ~AT_SYMLINK_NOFOLLOW) | ||
| 139 | goto out; | ||
| 140 | |||
| 141 | if (filename == NULL && dfd != AT_FDCWD) { | ||
| 142 | struct file *file; | ||
| 143 | |||
| 144 | if (flags & AT_SYMLINK_NOFOLLOW) | ||
| 145 | goto out; | ||
| 146 | |||
| 147 | file = fget(dfd); | ||
| 148 | error = -EBADF; | ||
| 149 | if (!file) | ||
| 150 | goto out; | ||
| 151 | |||
| 152 | error = utimes_common(&file->f_path, times); | ||
| 153 | fput(file); | ||
| 154 | } else { | ||
| 155 | struct path path; | ||
| 156 | int lookup_flags = 0; | ||
| 157 | |||
| 158 | if (!(flags & AT_SYMLINK_NOFOLLOW)) | ||
| 159 | lookup_flags |= LOOKUP_FOLLOW; | ||
| 160 | |||
| 161 | error = user_path_at(dfd, filename, lookup_flags, &path); | ||
| 162 | if (error) | ||
| 163 | goto out; | ||
| 164 | |||
| 165 | error = utimes_common(&path, times); | ||
| 166 | path_put(&path); | ||
| 167 | } | ||
| 168 | |||
| 166 | out: | 169 | out: |
| 167 | return error; | 170 | return error; |
| 168 | } | 171 | } |
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index b546ba69be82..155c10b4adbd 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c | |||
| @@ -621,7 +621,7 @@ shortname: | |||
| 621 | memcpy(de->name, msdos_name, MSDOS_NAME); | 621 | memcpy(de->name, msdos_name, MSDOS_NAME); |
| 622 | de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; | 622 | de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; |
| 623 | de->lcase = lcase; | 623 | de->lcase = lcase; |
| 624 | fat_date_unix2dos(ts->tv_sec, &time, &date); | 624 | fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); |
| 625 | de->time = de->ctime = time; | 625 | de->time = de->ctime = time; |
| 626 | de->date = de->cdate = de->adate = date; | 626 | de->date = de->cdate = de->adate = date; |
| 627 | de->ctime_cs = 0; | 627 | de->ctime_cs = 0; |
diff --git a/fs/xattr.c b/fs/xattr.c index 4706a8b1f495..468377e66531 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
| @@ -63,7 +63,7 @@ xattr_permission(struct inode *inode, const char *name, int mask) | |||
| 63 | return -EPERM; | 63 | return -EPERM; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | return permission(inode, mask, NULL); | 66 | return inode_permission(inode, mask); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | int | 69 | int |
| @@ -252,40 +252,40 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value, | |||
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | asmlinkage long | 254 | asmlinkage long |
| 255 | sys_setxattr(const char __user *path, const char __user *name, | 255 | sys_setxattr(const char __user *pathname, const char __user *name, |
| 256 | const void __user *value, size_t size, int flags) | 256 | const void __user *value, size_t size, int flags) |
| 257 | { | 257 | { |
| 258 | struct nameidata nd; | 258 | struct path path; |
| 259 | int error; | 259 | int error; |
| 260 | 260 | ||
| 261 | error = user_path_walk(path, &nd); | 261 | error = user_path(pathname, &path); |
| 262 | if (error) | 262 | if (error) |
| 263 | return error; | 263 | return error; |
| 264 | error = mnt_want_write(nd.path.mnt); | 264 | error = mnt_want_write(path.mnt); |
| 265 | if (!error) { | 265 | if (!error) { |
| 266 | error = setxattr(nd.path.dentry, name, value, size, flags); | 266 | error = setxattr(path.dentry, name, value, size, flags); |
| 267 | mnt_drop_write(nd.path.mnt); | 267 | mnt_drop_write(path.mnt); |
| 268 | } | 268 | } |
| 269 | path_put(&nd.path); | 269 | path_put(&path); |
| 270 | return error; | 270 | return error; |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | asmlinkage long | 273 | asmlinkage long |
| 274 | sys_lsetxattr(const char __user *path, const char __user *name, | 274 | sys_lsetxattr(const char __user *pathname, const char __user *name, |
| 275 | const void __user *value, size_t size, int flags) | 275 | const void __user *value, size_t size, int flags) |
| 276 | { | 276 | { |
| 277 | struct nameidata nd; | 277 | struct path path; |
| 278 | int error; | 278 | int error; |
| 279 | 279 | ||
| 280 | error = user_path_walk_link(path, &nd); | 280 | error = user_lpath(pathname, &path); |
| 281 | if (error) | 281 | if (error) |
| 282 | return error; | 282 | return error; |
| 283 | error = mnt_want_write(nd.path.mnt); | 283 | error = mnt_want_write(path.mnt); |
| 284 | if (!error) { | 284 | if (!error) { |
| 285 | error = setxattr(nd.path.dentry, name, value, size, flags); | 285 | error = setxattr(path.dentry, name, value, size, flags); |
| 286 | mnt_drop_write(nd.path.mnt); | 286 | mnt_drop_write(path.mnt); |
| 287 | } | 287 | } |
| 288 | path_put(&nd.path); | 288 | path_put(&path); |
| 289 | return error; | 289 | return error; |
| 290 | } | 290 | } |
| 291 | 291 | ||
| @@ -350,32 +350,32 @@ getxattr(struct dentry *d, const char __user *name, void __user *value, | |||
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | asmlinkage ssize_t | 352 | asmlinkage ssize_t |
| 353 | sys_getxattr(const char __user *path, const char __user *name, | 353 | sys_getxattr(const char __user *pathname, const char __user *name, |
| 354 | void __user *value, size_t size) | 354 | void __user *value, size_t size) |
| 355 | { | 355 | { |
| 356 | struct nameidata nd; | 356 | struct path path; |
| 357 | ssize_t error; | 357 | ssize_t error; |
| 358 | 358 | ||
| 359 | error = user_path_walk(path, &nd); | 359 | error = user_path(pathname, &path); |
| 360 | if (error) | 360 | if (error) |
| 361 | return error; | 361 | return error; |
| 362 | error = getxattr(nd.path.dentry, name, value, size); | 362 | error = getxattr(path.dentry, name, value, size); |
| 363 | path_put(&nd.path); | 363 | path_put(&path); |
| 364 | return error; | 364 | return error; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | asmlinkage ssize_t | 367 | asmlinkage ssize_t |
| 368 | sys_lgetxattr(const char __user *path, const char __user *name, void __user *value, | 368 | sys_lgetxattr(const char __user *pathname, const char __user *name, void __user *value, |
| 369 | size_t size) | 369 | size_t size) |
| 370 | { | 370 | { |
| 371 | struct nameidata nd; | 371 | struct path path; |
| 372 | ssize_t error; | 372 | ssize_t error; |
| 373 | 373 | ||
| 374 | error = user_path_walk_link(path, &nd); | 374 | error = user_lpath(pathname, &path); |
| 375 | if (error) | 375 | if (error) |
| 376 | return error; | 376 | return error; |
| 377 | error = getxattr(nd.path.dentry, name, value, size); | 377 | error = getxattr(path.dentry, name, value, size); |
| 378 | path_put(&nd.path); | 378 | path_put(&path); |
| 379 | return error; | 379 | return error; |
| 380 | } | 380 | } |
| 381 | 381 | ||
| @@ -425,30 +425,30 @@ listxattr(struct dentry *d, char __user *list, size_t size) | |||
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | asmlinkage ssize_t | 427 | asmlinkage ssize_t |
| 428 | sys_listxattr(const char __user *path, char __user *list, size_t size) | 428 | sys_listxattr(const char __user *pathname, char __user *list, size_t size) |
| 429 | { | 429 | { |
| 430 | struct nameidata nd; | 430 | struct path path; |
| 431 | ssize_t error; | 431 | ssize_t error; |
| 432 | 432 | ||
| 433 | error = user_path_walk(path, &nd); | 433 | error = user_path(pathname, &path); |
| 434 | if (error) | 434 | if (error) |
| 435 | return error; | 435 | return error; |
| 436 | error = listxattr(nd.path.dentry, list, size); | 436 | error = listxattr(path.dentry, list, size); |
| 437 | path_put(&nd.path); | 437 | path_put(&path); |
| 438 | return error; | 438 | return error; |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | asmlinkage ssize_t | 441 | asmlinkage ssize_t |
| 442 | sys_llistxattr(const char __user *path, char __user *list, size_t size) | 442 | sys_llistxattr(const char __user *pathname, char __user *list, size_t size) |
| 443 | { | 443 | { |
| 444 | struct nameidata nd; | 444 | struct path path; |
| 445 | ssize_t error; | 445 | ssize_t error; |
| 446 | 446 | ||
| 447 | error = user_path_walk_link(path, &nd); | 447 | error = user_lpath(pathname, &path); |
| 448 | if (error) | 448 | if (error) |
| 449 | return error; | 449 | return error; |
| 450 | error = listxattr(nd.path.dentry, list, size); | 450 | error = listxattr(path.dentry, list, size); |
| 451 | path_put(&nd.path); | 451 | path_put(&path); |
| 452 | return error; | 452 | return error; |
| 453 | } | 453 | } |
| 454 | 454 | ||
| @@ -486,38 +486,38 @@ removexattr(struct dentry *d, const char __user *name) | |||
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | asmlinkage long | 488 | asmlinkage long |
| 489 | sys_removexattr(const char __user *path, const char __user *name) | 489 | sys_removexattr(const char __user *pathname, const char __user *name) |
| 490 | { | 490 | { |
| 491 | struct nameidata nd; | 491 | struct path path; |
| 492 | int error; | 492 | int error; |
| 493 | 493 | ||
| 494 | error = user_path_walk(path, &nd); | 494 | error = user_path(pathname, &path); |
| 495 | if (error) | 495 | if (error) |
| 496 | return error; | 496 | return error; |
| 497 | error = mnt_want_write(nd.path.mnt); | 497 | error = mnt_want_write(path.mnt); |
| 498 | if (!error) { | 498 | if (!error) { |
| 499 | error = removexattr(nd.path.dentry, name); | 499 | error = removexattr(path.dentry, name); |
| 500 | mnt_drop_write(nd.path.mnt); | 500 | mnt_drop_write(path.mnt); |
| 501 | } | 501 | } |
| 502 | path_put(&nd.path); | 502 | path_put(&path); |
| 503 | return error; | 503 | return error; |
| 504 | } | 504 | } |
| 505 | 505 | ||
| 506 | asmlinkage long | 506 | asmlinkage long |
| 507 | sys_lremovexattr(const char __user *path, const char __user *name) | 507 | sys_lremovexattr(const char __user *pathname, const char __user *name) |
| 508 | { | 508 | { |
| 509 | struct nameidata nd; | 509 | struct path path; |
| 510 | int error; | 510 | int error; |
| 511 | 511 | ||
| 512 | error = user_path_walk_link(path, &nd); | 512 | error = user_lpath(pathname, &path); |
| 513 | if (error) | 513 | if (error) |
| 514 | return error; | 514 | return error; |
| 515 | error = mnt_want_write(nd.path.mnt); | 515 | error = mnt_want_write(path.mnt); |
| 516 | if (!error) { | 516 | if (!error) { |
| 517 | error = removexattr(nd.path.dentry, name); | 517 | error = removexattr(path.dentry, name); |
| 518 | mnt_drop_write(nd.path.mnt); | 518 | mnt_drop_write(path.mnt); |
| 519 | } | 519 | } |
| 520 | path_put(&nd.path); | 520 | path_put(&path); |
| 521 | return error; | 521 | return error; |
| 522 | } | 522 | } |
| 523 | 523 | ||
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 36ec614e699a..737c9a425361 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile | |||
| @@ -106,7 +106,8 @@ xfs-y += $(addprefix $(XFS_LINUX)/, \ | |||
| 106 | xfs_iops.o \ | 106 | xfs_iops.o \ |
| 107 | xfs_lrw.o \ | 107 | xfs_lrw.o \ |
| 108 | xfs_super.o \ | 108 | xfs_super.o \ |
| 109 | xfs_vnode.o) | 109 | xfs_vnode.o \ |
| 110 | xfs_xattr.o) | ||
| 110 | 111 | ||
| 111 | # Objects in support/ | 112 | # Objects in support/ |
| 112 | xfs-y += $(addprefix support/, \ | 113 | xfs-y += $(addprefix support/, \ |
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 9b1bb17a0501..1cd3b55ee3d2 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c | |||
| @@ -90,7 +90,7 @@ kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize, | |||
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | void | 92 | void |
| 93 | kmem_free(void *ptr, size_t size) | 93 | kmem_free(const void *ptr) |
| 94 | { | 94 | { |
| 95 | if (!is_vmalloc_addr(ptr)) { | 95 | if (!is_vmalloc_addr(ptr)) { |
| 96 | kfree(ptr); | 96 | kfree(ptr); |
| @@ -100,7 +100,7 @@ kmem_free(void *ptr, size_t size) | |||
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | void * | 102 | void * |
| 103 | kmem_realloc(void *ptr, size_t newsize, size_t oldsize, | 103 | kmem_realloc(const void *ptr, size_t newsize, size_t oldsize, |
| 104 | unsigned int __nocast flags) | 104 | unsigned int __nocast flags) |
| 105 | { | 105 | { |
| 106 | void *new; | 106 | void *new; |
| @@ -110,7 +110,7 @@ kmem_realloc(void *ptr, size_t newsize, size_t oldsize, | |||
| 110 | if (new) | 110 | if (new) |
| 111 | memcpy(new, ptr, | 111 | memcpy(new, ptr, |
| 112 | ((oldsize < newsize) ? oldsize : newsize)); | 112 | ((oldsize < newsize) ? oldsize : newsize)); |
| 113 | kmem_free(ptr, oldsize); | 113 | kmem_free(ptr); |
| 114 | } | 114 | } |
| 115 | return new; | 115 | return new; |
| 116 | } | 116 | } |
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h index 5e9564902976..af6843c7ee4b 100644 --- a/fs/xfs/linux-2.6/kmem.h +++ b/fs/xfs/linux-2.6/kmem.h | |||
| @@ -57,8 +57,8 @@ kmem_flags_convert(unsigned int __nocast flags) | |||
| 57 | extern void *kmem_alloc(size_t, unsigned int __nocast); | 57 | extern void *kmem_alloc(size_t, unsigned int __nocast); |
| 58 | extern void *kmem_zalloc(size_t, unsigned int __nocast); | 58 | extern void *kmem_zalloc(size_t, unsigned int __nocast); |
| 59 | extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast); | 59 | extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast); |
| 60 | extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast); | 60 | extern void *kmem_realloc(const void *, size_t, size_t, unsigned int __nocast); |
| 61 | extern void kmem_free(void *, size_t); | 61 | extern void kmem_free(const void *); |
| 62 | 62 | ||
| 63 | /* | 63 | /* |
| 64 | * Zone interfaces | 64 | * Zone interfaces |
| @@ -79,7 +79,7 @@ kmem_zone_init(int size, char *zone_name) | |||
| 79 | 79 | ||
| 80 | static inline kmem_zone_t * | 80 | static inline kmem_zone_t * |
| 81 | kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, | 81 | kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, |
| 82 | void (*construct)(kmem_zone_t *, void *)) | 82 | void (*construct)(void *)) |
| 83 | { | 83 | { |
| 84 | return kmem_cache_create(zone_name, size, 0, flags, construct); | 84 | return kmem_cache_create(zone_name, size, 0, flags, construct); |
| 85 | } | 85 | } |
diff --git a/fs/xfs/linux-2.6/sema.h b/fs/xfs/linux-2.6/sema.h deleted file mode 100644 index 3abe7e9ceb33..000000000000 --- a/fs/xfs/linux-2.6/sema.h +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | #ifndef __XFS_SUPPORT_SEMA_H__ | ||
| 19 | #define __XFS_SUPPORT_SEMA_H__ | ||
| 20 | |||
| 21 | #include <linux/time.h> | ||
| 22 | #include <linux/wait.h> | ||
| 23 | #include <linux/semaphore.h> | ||
| 24 | #include <asm/atomic.h> | ||
| 25 | |||
| 26 | /* | ||
| 27 | * sema_t structure just maps to struct semaphore in Linux kernel. | ||
| 28 | */ | ||
| 29 | |||
| 30 | typedef struct semaphore sema_t; | ||
| 31 | |||
| 32 | #define initnsema(sp, val, name) sema_init(sp, val) | ||
| 33 | #define psema(sp, b) down(sp) | ||
| 34 | #define vsema(sp) up(sp) | ||
| 35 | #define freesema(sema) do { } while (0) | ||
| 36 | |||
| 37 | static inline int issemalocked(sema_t *sp) | ||
| 38 | { | ||
| 39 | return down_trylock(sp) || (up(sp), 0); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* | ||
| 43 | * Map cpsema (try to get the sema) to down_trylock. We need to switch | ||
| 44 | * the return values since cpsema returns 1 (acquired) 0 (failed) and | ||
| 45 | * down_trylock returns the reverse 0 (acquired) 1 (failed). | ||
| 46 | */ | ||
| 47 | static inline int cpsema(sema_t *sp) | ||
| 48 | { | ||
| 49 | return down_trylock(sp) ? 0 : 1; | ||
| 50 | } | ||
| 51 | |||
| 52 | #endif /* __XFS_SUPPORT_SEMA_H__ */ | ||
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index a55c3b26d840..a44d68eb50b5 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
| @@ -73,7 +73,6 @@ xfs_page_trace( | |||
| 73 | unsigned long pgoff) | 73 | unsigned long pgoff) |
| 74 | { | 74 | { |
| 75 | xfs_inode_t *ip; | 75 | xfs_inode_t *ip; |
| 76 | bhv_vnode_t *vp = vn_from_inode(inode); | ||
| 77 | loff_t isize = i_size_read(inode); | 76 | loff_t isize = i_size_read(inode); |
| 78 | loff_t offset = page_offset(page); | 77 | loff_t offset = page_offset(page); |
| 79 | int delalloc = -1, unmapped = -1, unwritten = -1; | 78 | int delalloc = -1, unmapped = -1, unwritten = -1; |
| @@ -81,7 +80,7 @@ xfs_page_trace( | |||
| 81 | if (page_has_buffers(page)) | 80 | if (page_has_buffers(page)) |
| 82 | xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); | 81 | xfs_count_page_state(page, &delalloc, &unmapped, &unwritten); |
| 83 | 82 | ||
| 84 | ip = xfs_vtoi(vp); | 83 | ip = XFS_I(inode); |
| 85 | if (!ip->i_rwtrace) | 84 | if (!ip->i_rwtrace) |
| 86 | return; | 85 | return; |
| 87 | 86 | ||
| @@ -409,7 +408,6 @@ xfs_start_buffer_writeback( | |||
| 409 | STATIC void | 408 | STATIC void |
| 410 | xfs_start_page_writeback( | 409 | xfs_start_page_writeback( |
| 411 | struct page *page, | 410 | struct page *page, |
| 412 | struct writeback_control *wbc, | ||
| 413 | int clear_dirty, | 411 | int clear_dirty, |
| 414 | int buffers) | 412 | int buffers) |
| 415 | { | 413 | { |
| @@ -676,7 +674,7 @@ xfs_probe_cluster( | |||
| 676 | } else | 674 | } else |
| 677 | pg_offset = PAGE_CACHE_SIZE; | 675 | pg_offset = PAGE_CACHE_SIZE; |
| 678 | 676 | ||
| 679 | if (page->index == tindex && !TestSetPageLocked(page)) { | 677 | if (page->index == tindex && trylock_page(page)) { |
| 680 | pg_len = xfs_probe_page(page, pg_offset, mapped); | 678 | pg_len = xfs_probe_page(page, pg_offset, mapped); |
| 681 | unlock_page(page); | 679 | unlock_page(page); |
| 682 | } | 680 | } |
| @@ -760,7 +758,7 @@ xfs_convert_page( | |||
| 760 | 758 | ||
| 761 | if (page->index != tindex) | 759 | if (page->index != tindex) |
| 762 | goto fail; | 760 | goto fail; |
| 763 | if (TestSetPageLocked(page)) | 761 | if (!trylock_page(page)) |
| 764 | goto fail; | 762 | goto fail; |
| 765 | if (PageWriteback(page)) | 763 | if (PageWriteback(page)) |
| 766 | goto fail_unlock_page; | 764 | goto fail_unlock_page; |
| @@ -858,7 +856,7 @@ xfs_convert_page( | |||
| 858 | done = 1; | 856 | done = 1; |
| 859 | } | 857 | } |
| 860 | } | 858 | } |
| 861 | xfs_start_page_writeback(page, wbc, !page_dirty, count); | 859 | xfs_start_page_writeback(page, !page_dirty, count); |
| 862 | } | 860 | } |
| 863 | 861 | ||
| 864 | return done; | 862 | return done; |
| @@ -1105,7 +1103,7 @@ xfs_page_state_convert( | |||
| 1105 | * that we are writing into for the first time. | 1103 | * that we are writing into for the first time. |
| 1106 | */ | 1104 | */ |
| 1107 | type = IOMAP_NEW; | 1105 | type = IOMAP_NEW; |
| 1108 | if (!test_and_set_bit(BH_Lock, &bh->b_state)) { | 1106 | if (trylock_buffer(bh)) { |
| 1109 | ASSERT(buffer_mapped(bh)); | 1107 | ASSERT(buffer_mapped(bh)); |
| 1110 | if (iomap_valid) | 1108 | if (iomap_valid) |
| 1111 | all_bh = 1; | 1109 | all_bh = 1; |
| @@ -1130,7 +1128,7 @@ xfs_page_state_convert( | |||
| 1130 | SetPageUptodate(page); | 1128 | SetPageUptodate(page); |
| 1131 | 1129 | ||
| 1132 | if (startio) | 1130 | if (startio) |
| 1133 | xfs_start_page_writeback(page, wbc, 1, count); | 1131 | xfs_start_page_writeback(page, 1, count); |
| 1134 | 1132 | ||
| 1135 | if (ioend && iomap_valid) { | 1133 | if (ioend && iomap_valid) { |
| 1136 | offset = (iomap.iomap_offset + iomap.iomap_bsize - 1) >> | 1134 | offset = (iomap.iomap_offset + iomap.iomap_bsize - 1) >> |
| @@ -1340,6 +1338,10 @@ __xfs_get_blocks( | |||
| 1340 | offset = (xfs_off_t)iblock << inode->i_blkbits; | 1338 | offset = (xfs_off_t)iblock << inode->i_blkbits; |
| 1341 | ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); | 1339 | ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); |
| 1342 | size = bh_result->b_size; | 1340 | size = bh_result->b_size; |
| 1341 | |||
| 1342 | if (!create && direct && offset >= i_size_read(inode)) | ||
| 1343 | return 0; | ||
| 1344 | |||
| 1343 | error = xfs_iomap(XFS_I(inode), offset, size, | 1345 | error = xfs_iomap(XFS_I(inode), offset, size, |
| 1344 | create ? flags : BMAPI_READ, &iomap, &niomap); | 1346 | create ? flags : BMAPI_READ, &iomap, &niomap); |
| 1345 | if (error) | 1347 | if (error) |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 98e0e86093b4..986061ae1b9b 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
| @@ -58,7 +58,7 @@ xfs_buf_trace( | |||
| 58 | bp, id, | 58 | bp, id, |
| 59 | (void *)(unsigned long)bp->b_flags, | 59 | (void *)(unsigned long)bp->b_flags, |
| 60 | (void *)(unsigned long)bp->b_hold.counter, | 60 | (void *)(unsigned long)bp->b_hold.counter, |
| 61 | (void *)(unsigned long)bp->b_sema.count.counter, | 61 | (void *)(unsigned long)bp->b_sema.count, |
| 62 | (void *)current, | 62 | (void *)current, |
| 63 | data, ra, | 63 | data, ra, |
| 64 | (void *)(unsigned long)((bp->b_file_offset>>32) & 0xffffffff), | 64 | (void *)(unsigned long)((bp->b_file_offset>>32) & 0xffffffff), |
| @@ -253,7 +253,7 @@ _xfs_buf_initialize( | |||
| 253 | 253 | ||
| 254 | memset(bp, 0, sizeof(xfs_buf_t)); | 254 | memset(bp, 0, sizeof(xfs_buf_t)); |
| 255 | atomic_set(&bp->b_hold, 1); | 255 | atomic_set(&bp->b_hold, 1); |
| 256 | init_MUTEX_LOCKED(&bp->b_iodonesema); | 256 | init_completion(&bp->b_iowait); |
| 257 | INIT_LIST_HEAD(&bp->b_list); | 257 | INIT_LIST_HEAD(&bp->b_list); |
| 258 | INIT_LIST_HEAD(&bp->b_hash_list); | 258 | INIT_LIST_HEAD(&bp->b_hash_list); |
| 259 | init_MUTEX_LOCKED(&bp->b_sema); /* held, no waiters */ | 259 | init_MUTEX_LOCKED(&bp->b_sema); /* held, no waiters */ |
| @@ -310,8 +310,7 @@ _xfs_buf_free_pages( | |||
| 310 | xfs_buf_t *bp) | 310 | xfs_buf_t *bp) |
| 311 | { | 311 | { |
| 312 | if (bp->b_pages != bp->b_page_array) { | 312 | if (bp->b_pages != bp->b_page_array) { |
| 313 | kmem_free(bp->b_pages, | 313 | kmem_free(bp->b_pages); |
| 314 | bp->b_page_count * sizeof(struct page *)); | ||
| 315 | } | 314 | } |
| 316 | } | 315 | } |
| 317 | 316 | ||
| @@ -839,6 +838,7 @@ xfs_buf_rele( | |||
| 839 | return; | 838 | return; |
| 840 | } | 839 | } |
| 841 | 840 | ||
| 841 | ASSERT(atomic_read(&bp->b_hold) > 0); | ||
| 842 | if (atomic_dec_and_lock(&bp->b_hold, &hash->bh_lock)) { | 842 | if (atomic_dec_and_lock(&bp->b_hold, &hash->bh_lock)) { |
| 843 | if (bp->b_relse) { | 843 | if (bp->b_relse) { |
| 844 | atomic_inc(&bp->b_hold); | 844 | atomic_inc(&bp->b_hold); |
| @@ -852,11 +852,6 @@ xfs_buf_rele( | |||
| 852 | spin_unlock(&hash->bh_lock); | 852 | spin_unlock(&hash->bh_lock); |
| 853 | xfs_buf_free(bp); | 853 | xfs_buf_free(bp); |
| 854 | } | 854 | } |
| 855 | } else { | ||
| 856 | /* | ||
| 857 | * Catch reference count leaks | ||
| 858 | */ | ||
| 859 | ASSERT(atomic_read(&bp->b_hold) >= 0); | ||
| 860 | } | 855 | } |
| 861 | } | 856 | } |
| 862 | 857 | ||
| @@ -1038,7 +1033,7 @@ xfs_buf_ioend( | |||
| 1038 | xfs_buf_iodone_work(&bp->b_iodone_work); | 1033 | xfs_buf_iodone_work(&bp->b_iodone_work); |
| 1039 | } | 1034 | } |
| 1040 | } else { | 1035 | } else { |
| 1041 | up(&bp->b_iodonesema); | 1036 | complete(&bp->b_iowait); |
| 1042 | } | 1037 | } |
| 1043 | } | 1038 | } |
| 1044 | 1039 | ||
| @@ -1276,7 +1271,7 @@ xfs_buf_iowait( | |||
| 1276 | XB_TRACE(bp, "iowait", 0); | 1271 | XB_TRACE(bp, "iowait", 0); |
| 1277 | if (atomic_read(&bp->b_io_remaining)) | 1272 | if (atomic_read(&bp->b_io_remaining)) |
| 1278 | blk_run_address_space(bp->b_target->bt_mapping); | 1273 | blk_run_address_space(bp->b_target->bt_mapping); |
| 1279 | down(&bp->b_iodonesema); | 1274 | wait_for_completion(&bp->b_iowait); |
| 1280 | XB_TRACE(bp, "iowaited", (long)bp->b_error); | 1275 | XB_TRACE(bp, "iowaited", (long)bp->b_error); |
| 1281 | return bp->b_error; | 1276 | return bp->b_error; |
| 1282 | } | 1277 | } |
| @@ -1398,7 +1393,7 @@ STATIC void | |||
| 1398 | xfs_free_bufhash( | 1393 | xfs_free_bufhash( |
| 1399 | xfs_buftarg_t *btp) | 1394 | xfs_buftarg_t *btp) |
| 1400 | { | 1395 | { |
| 1401 | kmem_free(btp->bt_hash, (1<<btp->bt_hashshift) * sizeof(xfs_bufhash_t)); | 1396 | kmem_free(btp->bt_hash); |
| 1402 | btp->bt_hash = NULL; | 1397 | btp->bt_hash = NULL; |
| 1403 | } | 1398 | } |
| 1404 | 1399 | ||
| @@ -1428,13 +1423,10 @@ xfs_unregister_buftarg( | |||
| 1428 | 1423 | ||
| 1429 | void | 1424 | void |
| 1430 | xfs_free_buftarg( | 1425 | xfs_free_buftarg( |
| 1431 | xfs_buftarg_t *btp, | 1426 | xfs_buftarg_t *btp) |
| 1432 | int external) | ||
| 1433 | { | 1427 | { |
| 1434 | xfs_flush_buftarg(btp, 1); | 1428 | xfs_flush_buftarg(btp, 1); |
| 1435 | xfs_blkdev_issue_flush(btp); | 1429 | xfs_blkdev_issue_flush(btp); |
| 1436 | if (external) | ||
| 1437 | xfs_blkdev_put(btp->bt_bdev); | ||
| 1438 | xfs_free_bufhash(btp); | 1430 | xfs_free_bufhash(btp); |
| 1439 | iput(btp->bt_mapping->host); | 1431 | iput(btp->bt_mapping->host); |
| 1440 | 1432 | ||
| @@ -1444,7 +1436,7 @@ xfs_free_buftarg( | |||
| 1444 | xfs_unregister_buftarg(btp); | 1436 | xfs_unregister_buftarg(btp); |
| 1445 | kthread_stop(btp->bt_task); | 1437 | kthread_stop(btp->bt_task); |
| 1446 | 1438 | ||
| 1447 | kmem_free(btp, sizeof(*btp)); | 1439 | kmem_free(btp); |
| 1448 | } | 1440 | } |
| 1449 | 1441 | ||
| 1450 | STATIC int | 1442 | STATIC int |
| @@ -1575,7 +1567,7 @@ xfs_alloc_buftarg( | |||
| 1575 | return btp; | 1567 | return btp; |
| 1576 | 1568 | ||
| 1577 | error: | 1569 | error: |
| 1578 | kmem_free(btp, sizeof(*btp)); | 1570 | kmem_free(btp); |
| 1579 | return NULL; | 1571 | return NULL; |
| 1580 | } | 1572 | } |
| 1581 | 1573 | ||
| @@ -1803,7 +1795,7 @@ int __init | |||
| 1803 | xfs_buf_init(void) | 1795 | xfs_buf_init(void) |
| 1804 | { | 1796 | { |
| 1805 | #ifdef XFS_BUF_TRACE | 1797 | #ifdef XFS_BUF_TRACE |
| 1806 | xfs_buf_trace_buf = ktrace_alloc(XFS_BUF_TRACE_SIZE, KM_SLEEP); | 1798 | xfs_buf_trace_buf = ktrace_alloc(XFS_BUF_TRACE_SIZE, KM_NOFS); |
| 1807 | #endif | 1799 | #endif |
| 1808 | 1800 | ||
| 1809 | xfs_buf_zone = kmem_zone_init_flags(sizeof(xfs_buf_t), "xfs_buf", | 1801 | xfs_buf_zone = kmem_zone_init_flags(sizeof(xfs_buf_t), "xfs_buf", |
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index f948ec7ba9a4..fe0109956656 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h | |||
| @@ -157,7 +157,7 @@ typedef struct xfs_buf { | |||
| 157 | xfs_buf_iodone_t b_iodone; /* I/O completion function */ | 157 | xfs_buf_iodone_t b_iodone; /* I/O completion function */ |
| 158 | xfs_buf_relse_t b_relse; /* releasing function */ | 158 | xfs_buf_relse_t b_relse; /* releasing function */ |
| 159 | xfs_buf_bdstrat_t b_strat; /* pre-write function */ | 159 | xfs_buf_bdstrat_t b_strat; /* pre-write function */ |
| 160 | struct semaphore b_iodonesema; /* Semaphore for I/O waiters */ | 160 | struct completion b_iowait; /* queue for I/O waiters */ |
| 161 | void *b_fspriv; | 161 | void *b_fspriv; |
| 162 | void *b_fspriv2; | 162 | void *b_fspriv2; |
| 163 | void *b_fspriv3; | 163 | void *b_fspriv3; |
| @@ -352,7 +352,7 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *); | |||
| 352 | #define XFS_BUF_CPSEMA(bp) (xfs_buf_cond_lock(bp) == 0) | 352 | #define XFS_BUF_CPSEMA(bp) (xfs_buf_cond_lock(bp) == 0) |
| 353 | #define XFS_BUF_VSEMA(bp) xfs_buf_unlock(bp) | 353 | #define XFS_BUF_VSEMA(bp) xfs_buf_unlock(bp) |
| 354 | #define XFS_BUF_PSEMA(bp,x) xfs_buf_lock(bp) | 354 | #define XFS_BUF_PSEMA(bp,x) xfs_buf_lock(bp) |
| 355 | #define XFS_BUF_V_IODONESEMA(bp) up(&bp->b_iodonesema); | 355 | #define XFS_BUF_FINISH_IOWAIT(bp) complete(&bp->b_iowait); |
| 356 | 356 | ||
| 357 | #define XFS_BUF_SET_TARGET(bp, target) ((bp)->b_target = (target)) | 357 | #define XFS_BUF_SET_TARGET(bp, target) ((bp)->b_target = (target)) |
| 358 | #define XFS_BUF_TARGET(bp) ((bp)->b_target) | 358 | #define XFS_BUF_TARGET(bp) ((bp)->b_target) |
| @@ -429,7 +429,7 @@ static inline void xfs_bdwrite(void *mp, xfs_buf_t *bp) | |||
| 429 | * Handling of buftargs. | 429 | * Handling of buftargs. |
| 430 | */ | 430 | */ |
| 431 | extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); | 431 | extern xfs_buftarg_t *xfs_alloc_buftarg(struct block_device *, int); |
| 432 | extern void xfs_free_buftarg(xfs_buftarg_t *, int); | 432 | extern void xfs_free_buftarg(xfs_buftarg_t *); |
| 433 | extern void xfs_wait_buftarg(xfs_buftarg_t *); | 433 | extern void xfs_wait_buftarg(xfs_buftarg_t *); |
| 434 | extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); | 434 | extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int); |
| 435 | extern int xfs_flush_buftarg(xfs_buftarg_t *, int); | 435 | extern int xfs_flush_buftarg(xfs_buftarg_t *, int); |
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index c672b3238b14..24fd598af846 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c | |||
| @@ -139,7 +139,7 @@ xfs_nfs_get_inode( | |||
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 141 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 142 | return ip->i_vnode; | 142 | return VFS_I(ip); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | STATIC struct dentry * | 145 | STATIC struct dentry * |
| @@ -167,7 +167,7 @@ xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid, | |||
| 167 | if (!inode) | 167 | if (!inode) |
| 168 | return NULL; | 168 | return NULL; |
| 169 | if (IS_ERR(inode)) | 169 | if (IS_ERR(inode)) |
| 170 | return ERR_PTR(PTR_ERR(inode)); | 170 | return ERR_CAST(inode); |
| 171 | result = d_alloc_anon(inode); | 171 | result = d_alloc_anon(inode); |
| 172 | if (!result) { | 172 | if (!result) { |
| 173 | iput(inode); | 173 | iput(inode); |
| @@ -198,7 +198,7 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid, | |||
| 198 | if (!inode) | 198 | if (!inode) |
| 199 | return NULL; | 199 | return NULL; |
| 200 | if (IS_ERR(inode)) | 200 | if (IS_ERR(inode)) |
| 201 | return ERR_PTR(PTR_ERR(inode)); | 201 | return ERR_CAST(inode); |
| 202 | result = d_alloc_anon(inode); | 202 | result = d_alloc_anon(inode); |
| 203 | if (!result) { | 203 | if (!result) { |
| 204 | iput(inode); | 204 | iput(inode); |
| @@ -215,13 +215,13 @@ xfs_fs_get_parent( | |||
| 215 | struct xfs_inode *cip; | 215 | struct xfs_inode *cip; |
| 216 | struct dentry *parent; | 216 | struct dentry *parent; |
| 217 | 217 | ||
| 218 | error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip); | 218 | error = xfs_lookup(XFS_I(child->d_inode), &xfs_name_dotdot, &cip, NULL); |
| 219 | if (unlikely(error)) | 219 | if (unlikely(error)) |
| 220 | return ERR_PTR(-error); | 220 | return ERR_PTR(-error); |
| 221 | 221 | ||
| 222 | parent = d_alloc_anon(cip->i_vnode); | 222 | parent = d_alloc_anon(VFS_I(cip)); |
| 223 | if (unlikely(!parent)) { | 223 | if (unlikely(!parent)) { |
| 224 | iput(cip->i_vnode); | 224 | iput(VFS_I(cip)); |
| 225 | return ERR_PTR(-ENOMEM); | 225 | return ERR_PTR(-ENOMEM); |
| 226 | } | 226 | } |
| 227 | return parent; | 227 | return parent; |
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 5f60363b9343..5311c1acdd40 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
| @@ -475,6 +475,7 @@ const struct file_operations xfs_invis_file_operations = { | |||
| 475 | const struct file_operations xfs_dir_file_operations = { | 475 | const struct file_operations xfs_dir_file_operations = { |
| 476 | .read = generic_read_dir, | 476 | .read = generic_read_dir, |
| 477 | .readdir = xfs_file_readdir, | 477 | .readdir = xfs_file_readdir, |
| 478 | .llseek = generic_file_llseek, | ||
| 478 | .unlocked_ioctl = xfs_file_ioctl, | 479 | .unlocked_ioctl = xfs_file_ioctl, |
| 479 | #ifdef CONFIG_COMPAT | 480 | #ifdef CONFIG_COMPAT |
| 480 | .compat_ioctl = xfs_file_compat_ioctl, | 481 | .compat_ioctl = xfs_file_compat_ioctl, |
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c index 1eefe61f0e10..36caa6d957df 100644 --- a/fs/xfs/linux-2.6/xfs_fs_subr.c +++ b/fs/xfs/linux-2.6/xfs_fs_subr.c | |||
| @@ -31,7 +31,7 @@ xfs_tosspages( | |||
| 31 | xfs_off_t last, | 31 | xfs_off_t last, |
| 32 | int fiopt) | 32 | int fiopt) |
| 33 | { | 33 | { |
| 34 | struct address_space *mapping = ip->i_vnode->i_mapping; | 34 | struct address_space *mapping = VFS_I(ip)->i_mapping; |
| 35 | 35 | ||
| 36 | if (mapping->nrpages) | 36 | if (mapping->nrpages) |
| 37 | truncate_inode_pages(mapping, first); | 37 | truncate_inode_pages(mapping, first); |
| @@ -44,7 +44,7 @@ xfs_flushinval_pages( | |||
| 44 | xfs_off_t last, | 44 | xfs_off_t last, |
| 45 | int fiopt) | 45 | int fiopt) |
| 46 | { | 46 | { |
| 47 | struct address_space *mapping = ip->i_vnode->i_mapping; | 47 | struct address_space *mapping = VFS_I(ip)->i_mapping; |
| 48 | int ret = 0; | 48 | int ret = 0; |
| 49 | 49 | ||
| 50 | if (mapping->nrpages) { | 50 | if (mapping->nrpages) { |
| @@ -64,7 +64,7 @@ xfs_flush_pages( | |||
| 64 | uint64_t flags, | 64 | uint64_t flags, |
| 65 | int fiopt) | 65 | int fiopt) |
| 66 | { | 66 | { |
| 67 | struct address_space *mapping = ip->i_vnode->i_mapping; | 67 | struct address_space *mapping = VFS_I(ip)->i_mapping; |
| 68 | int ret = 0; | 68 | int ret = 0; |
| 69 | int ret2; | 69 | int ret2; |
| 70 | 70 | ||
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index a42ba9d71156..48799ba7e3e6 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c | |||
| @@ -48,6 +48,8 @@ | |||
| 48 | #include "xfs_dfrag.h" | 48 | #include "xfs_dfrag.h" |
| 49 | #include "xfs_fsops.h" | 49 | #include "xfs_fsops.h" |
| 50 | #include "xfs_vnodeops.h" | 50 | #include "xfs_vnodeops.h" |
| 51 | #include "xfs_quota.h" | ||
| 52 | #include "xfs_inode_item.h" | ||
| 51 | 53 | ||
| 52 | #include <linux/capability.h> | 54 | #include <linux/capability.h> |
| 53 | #include <linux/dcache.h> | 55 | #include <linux/dcache.h> |
| @@ -84,17 +86,15 @@ xfs_find_handle( | |||
| 84 | switch (cmd) { | 86 | switch (cmd) { |
| 85 | case XFS_IOC_PATH_TO_FSHANDLE: | 87 | case XFS_IOC_PATH_TO_FSHANDLE: |
| 86 | case XFS_IOC_PATH_TO_HANDLE: { | 88 | case XFS_IOC_PATH_TO_HANDLE: { |
| 87 | struct nameidata nd; | 89 | struct path path; |
| 88 | int error; | 90 | int error = user_lpath((const char __user *)hreq.path, &path); |
| 89 | |||
| 90 | error = user_path_walk_link((const char __user *)hreq.path, &nd); | ||
| 91 | if (error) | 91 | if (error) |
| 92 | return error; | 92 | return error; |
| 93 | 93 | ||
| 94 | ASSERT(nd.path.dentry); | 94 | ASSERT(path.dentry); |
| 95 | ASSERT(nd.path.dentry->d_inode); | 95 | ASSERT(path.dentry->d_inode); |
| 96 | inode = igrab(nd.path.dentry->d_inode); | 96 | inode = igrab(path.dentry->d_inode); |
| 97 | path_put(&nd.path); | 97 | path_put(&path); |
| 98 | break; | 98 | break; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| @@ -245,7 +245,7 @@ xfs_vget_fsop_handlereq( | |||
| 245 | 245 | ||
| 246 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 246 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 247 | 247 | ||
| 248 | *inode = XFS_ITOV(ip); | 248 | *inode = VFS_I(ip); |
| 249 | return 0; | 249 | return 0; |
| 250 | } | 250 | } |
| 251 | 251 | ||
| @@ -470,6 +470,12 @@ xfs_attrlist_by_handle( | |||
| 470 | if (al_hreq.buflen > XATTR_LIST_MAX) | 470 | if (al_hreq.buflen > XATTR_LIST_MAX) |
| 471 | return -XFS_ERROR(EINVAL); | 471 | return -XFS_ERROR(EINVAL); |
| 472 | 472 | ||
| 473 | /* | ||
| 474 | * Reject flags, only allow namespaces. | ||
| 475 | */ | ||
| 476 | if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) | ||
| 477 | return -XFS_ERROR(EINVAL); | ||
| 478 | |||
| 473 | error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode); | 479 | error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode); |
| 474 | if (error) | 480 | if (error) |
| 475 | goto out; | 481 | goto out; |
| @@ -589,7 +595,7 @@ xfs_attrmulti_by_handle( | |||
| 589 | goto out; | 595 | goto out; |
| 590 | 596 | ||
| 591 | error = E2BIG; | 597 | error = E2BIG; |
| 592 | size = am_hreq.opcount * sizeof(attr_multiop_t); | 598 | size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); |
| 593 | if (!size || size > 16 * PAGE_SIZE) | 599 | if (!size || size > 16 * PAGE_SIZE) |
| 594 | goto out_vn_rele; | 600 | goto out_vn_rele; |
| 595 | 601 | ||
| @@ -682,9 +688,9 @@ xfs_ioc_space( | |||
| 682 | return -XFS_ERROR(EFAULT); | 688 | return -XFS_ERROR(EFAULT); |
| 683 | 689 | ||
| 684 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 690 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) |
| 685 | attr_flags |= ATTR_NONBLOCK; | 691 | attr_flags |= XFS_ATTR_NONBLOCK; |
| 686 | if (ioflags & IO_INVIS) | 692 | if (ioflags & IO_INVIS) |
| 687 | attr_flags |= ATTR_DMI; | 693 | attr_flags |= XFS_ATTR_DMI; |
| 688 | 694 | ||
| 689 | error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, | 695 | error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, |
| 690 | NULL, attr_flags); | 696 | NULL, attr_flags); |
| @@ -875,6 +881,322 @@ xfs_ioc_fsgetxattr( | |||
| 875 | return 0; | 881 | return 0; |
| 876 | } | 882 | } |
| 877 | 883 | ||
| 884 | STATIC void | ||
| 885 | xfs_set_diflags( | ||
| 886 | struct xfs_inode *ip, | ||
| 887 | unsigned int xflags) | ||
| 888 | { | ||
| 889 | unsigned int di_flags; | ||
| 890 | |||
| 891 | /* can't set PREALLOC this way, just preserve it */ | ||
| 892 | di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); | ||
| 893 | if (xflags & XFS_XFLAG_IMMUTABLE) | ||
| 894 | di_flags |= XFS_DIFLAG_IMMUTABLE; | ||
| 895 | if (xflags & XFS_XFLAG_APPEND) | ||
| 896 | di_flags |= XFS_DIFLAG_APPEND; | ||
| 897 | if (xflags & XFS_XFLAG_SYNC) | ||
| 898 | di_flags |= XFS_DIFLAG_SYNC; | ||
| 899 | if (xflags & XFS_XFLAG_NOATIME) | ||
| 900 | di_flags |= XFS_DIFLAG_NOATIME; | ||
| 901 | if (xflags & XFS_XFLAG_NODUMP) | ||
| 902 | di_flags |= XFS_DIFLAG_NODUMP; | ||
| 903 | if (xflags & XFS_XFLAG_PROJINHERIT) | ||
| 904 | di_flags |= XFS_DIFLAG_PROJINHERIT; | ||
| 905 | if (xflags & XFS_XFLAG_NODEFRAG) | ||
| 906 | di_flags |= XFS_DIFLAG_NODEFRAG; | ||
| 907 | if (xflags & XFS_XFLAG_FILESTREAM) | ||
| 908 | di_flags |= XFS_DIFLAG_FILESTREAM; | ||
| 909 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { | ||
| 910 | if (xflags & XFS_XFLAG_RTINHERIT) | ||
| 911 | di_flags |= XFS_DIFLAG_RTINHERIT; | ||
| 912 | if (xflags & XFS_XFLAG_NOSYMLINKS) | ||
| 913 | di_flags |= XFS_DIFLAG_NOSYMLINKS; | ||
| 914 | if (xflags & XFS_XFLAG_EXTSZINHERIT) | ||
| 915 | di_flags |= XFS_DIFLAG_EXTSZINHERIT; | ||
| 916 | } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { | ||
| 917 | if (xflags & XFS_XFLAG_REALTIME) | ||
| 918 | di_flags |= XFS_DIFLAG_REALTIME; | ||
| 919 | if (xflags & XFS_XFLAG_EXTSIZE) | ||
| 920 | di_flags |= XFS_DIFLAG_EXTSIZE; | ||
| 921 | } | ||
| 922 | |||
| 923 | ip->i_d.di_flags = di_flags; | ||
| 924 | } | ||
| 925 | |||
| 926 | STATIC void | ||
| 927 | xfs_diflags_to_linux( | ||
| 928 | struct xfs_inode *ip) | ||
| 929 | { | ||
| 930 | struct inode *inode = VFS_I(ip); | ||
| 931 | unsigned int xflags = xfs_ip2xflags(ip); | ||
| 932 | |||
| 933 | if (xflags & XFS_XFLAG_IMMUTABLE) | ||
| 934 | inode->i_flags |= S_IMMUTABLE; | ||
| 935 | else | ||
| 936 | inode->i_flags &= ~S_IMMUTABLE; | ||
| 937 | if (xflags & XFS_XFLAG_APPEND) | ||
| 938 | inode->i_flags |= S_APPEND; | ||
| 939 | else | ||
| 940 | inode->i_flags &= ~S_APPEND; | ||
| 941 | if (xflags & XFS_XFLAG_SYNC) | ||
| 942 | inode->i_flags |= S_SYNC; | ||
| 943 | else | ||
| 944 | inode->i_flags &= ~S_SYNC; | ||
| 945 | if (xflags & XFS_XFLAG_NOATIME) | ||
| 946 | inode->i_flags |= S_NOATIME; | ||
| 947 | else | ||
| 948 | inode->i_flags &= ~S_NOATIME; | ||
| 949 | } | ||
| 950 | |||
| 951 | #define FSX_PROJID 1 | ||
| 952 | #define FSX_EXTSIZE 2 | ||
| 953 | #define FSX_XFLAGS 4 | ||
| 954 | #define FSX_NONBLOCK 8 | ||
| 955 | |||
| 956 | STATIC int | ||
| 957 | xfs_ioctl_setattr( | ||
| 958 | xfs_inode_t *ip, | ||
| 959 | struct fsxattr *fa, | ||
| 960 | int mask) | ||
| 961 | { | ||
| 962 | struct xfs_mount *mp = ip->i_mount; | ||
| 963 | struct xfs_trans *tp; | ||
| 964 | unsigned int lock_flags = 0; | ||
| 965 | struct xfs_dquot *udqp = NULL, *gdqp = NULL; | ||
| 966 | struct xfs_dquot *olddquot = NULL; | ||
| 967 | int code; | ||
| 968 | |||
| 969 | xfs_itrace_entry(ip); | ||
| 970 | |||
| 971 | if (mp->m_flags & XFS_MOUNT_RDONLY) | ||
| 972 | return XFS_ERROR(EROFS); | ||
| 973 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 974 | return XFS_ERROR(EIO); | ||
| 975 | |||
| 976 | /* | ||
| 977 | * If disk quotas is on, we make sure that the dquots do exist on disk, | ||
| 978 | * before we start any other transactions. Trying to do this later | ||
| 979 | * is messy. We don't care to take a readlock to look at the ids | ||
| 980 | * in inode here, because we can't hold it across the trans_reserve. | ||
| 981 | * If the IDs do change before we take the ilock, we're covered | ||
| 982 | * because the i_*dquot fields will get updated anyway. | ||
| 983 | */ | ||
| 984 | if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) { | ||
| 985 | code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid, | ||
| 986 | ip->i_d.di_gid, fa->fsx_projid, | ||
| 987 | XFS_QMOPT_PQUOTA, &udqp, &gdqp); | ||
| 988 | if (code) | ||
| 989 | return code; | ||
| 990 | } | ||
| 991 | |||
| 992 | /* | ||
| 993 | * For the other attributes, we acquire the inode lock and | ||
| 994 | * first do an error checking pass. | ||
| 995 | */ | ||
| 996 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | ||
| 997 | code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); | ||
| 998 | if (code) | ||
| 999 | goto error_return; | ||
| 1000 | |||
| 1001 | lock_flags = XFS_ILOCK_EXCL; | ||
| 1002 | xfs_ilock(ip, lock_flags); | ||
| 1003 | |||
| 1004 | /* | ||
| 1005 | * CAP_FOWNER overrides the following restrictions: | ||
| 1006 | * | ||
| 1007 | * The user ID of the calling process must be equal | ||
| 1008 | * to the file owner ID, except in cases where the | ||
| 1009 | * CAP_FSETID capability is applicable. | ||
| 1010 | */ | ||
| 1011 | if (current->fsuid != ip->i_d.di_uid && !capable(CAP_FOWNER)) { | ||
| 1012 | code = XFS_ERROR(EPERM); | ||
| 1013 | goto error_return; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | /* | ||
| 1017 | * Do a quota reservation only if projid is actually going to change. | ||
| 1018 | */ | ||
| 1019 | if (mask & FSX_PROJID) { | ||
| 1020 | if (XFS_IS_PQUOTA_ON(mp) && | ||
| 1021 | ip->i_d.di_projid != fa->fsx_projid) { | ||
| 1022 | ASSERT(tp); | ||
| 1023 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, | ||
| 1024 | capable(CAP_FOWNER) ? | ||
| 1025 | XFS_QMOPT_FORCE_RES : 0); | ||
| 1026 | if (code) /* out of quota */ | ||
| 1027 | goto error_return; | ||
| 1028 | } | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | if (mask & FSX_EXTSIZE) { | ||
| 1032 | /* | ||
| 1033 | * Can't change extent size if any extents are allocated. | ||
| 1034 | */ | ||
| 1035 | if (ip->i_d.di_nextents && | ||
| 1036 | ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != | ||
| 1037 | fa->fsx_extsize)) { | ||
| 1038 | code = XFS_ERROR(EINVAL); /* EFBIG? */ | ||
| 1039 | goto error_return; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | /* | ||
| 1043 | * Extent size must be a multiple of the appropriate block | ||
| 1044 | * size, if set at all. | ||
| 1045 | */ | ||
| 1046 | if (fa->fsx_extsize != 0) { | ||
| 1047 | xfs_extlen_t size; | ||
| 1048 | |||
| 1049 | if (XFS_IS_REALTIME_INODE(ip) || | ||
| 1050 | ((mask & FSX_XFLAGS) && | ||
| 1051 | (fa->fsx_xflags & XFS_XFLAG_REALTIME))) { | ||
| 1052 | size = mp->m_sb.sb_rextsize << | ||
| 1053 | mp->m_sb.sb_blocklog; | ||
| 1054 | } else { | ||
| 1055 | size = mp->m_sb.sb_blocksize; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | if (fa->fsx_extsize % size) { | ||
| 1059 | code = XFS_ERROR(EINVAL); | ||
| 1060 | goto error_return; | ||
| 1061 | } | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | |||
| 1066 | if (mask & FSX_XFLAGS) { | ||
| 1067 | /* | ||
| 1068 | * Can't change realtime flag if any extents are allocated. | ||
| 1069 | */ | ||
| 1070 | if ((ip->i_d.di_nextents || ip->i_delayed_blks) && | ||
| 1071 | (XFS_IS_REALTIME_INODE(ip)) != | ||
| 1072 | (fa->fsx_xflags & XFS_XFLAG_REALTIME)) { | ||
| 1073 | code = XFS_ERROR(EINVAL); /* EFBIG? */ | ||
| 1074 | goto error_return; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | /* | ||
| 1078 | * If realtime flag is set then must have realtime data. | ||
| 1079 | */ | ||
| 1080 | if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) { | ||
| 1081 | if ((mp->m_sb.sb_rblocks == 0) || | ||
| 1082 | (mp->m_sb.sb_rextsize == 0) || | ||
| 1083 | (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { | ||
| 1084 | code = XFS_ERROR(EINVAL); | ||
| 1085 | goto error_return; | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | /* | ||
| 1090 | * Can't modify an immutable/append-only file unless | ||
| 1091 | * we have appropriate permission. | ||
| 1092 | */ | ||
| 1093 | if ((ip->i_d.di_flags & | ||
| 1094 | (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) || | ||
| 1095 | (fa->fsx_xflags & | ||
| 1096 | (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) && | ||
| 1097 | !capable(CAP_LINUX_IMMUTABLE)) { | ||
| 1098 | code = XFS_ERROR(EPERM); | ||
| 1099 | goto error_return; | ||
| 1100 | } | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | xfs_trans_ijoin(tp, ip, lock_flags); | ||
| 1104 | xfs_trans_ihold(tp, ip); | ||
| 1105 | |||
| 1106 | /* | ||
| 1107 | * Change file ownership. Must be the owner or privileged. | ||
| 1108 | * If the system was configured with the "restricted_chown" | ||
| 1109 | * option, the owner is not permitted to give away the file, | ||
| 1110 | * and can change the group id only to a group of which he | ||
| 1111 | * or she is a member. | ||
| 1112 | */ | ||
| 1113 | if (mask & FSX_PROJID) { | ||
| 1114 | /* | ||
| 1115 | * CAP_FSETID overrides the following restrictions: | ||
| 1116 | * | ||
| 1117 | * The set-user-ID and set-group-ID bits of a file will be | ||
| 1118 | * cleared upon successful return from chown() | ||
| 1119 | */ | ||
| 1120 | if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) && | ||
| 1121 | !capable(CAP_FSETID)) | ||
| 1122 | ip->i_d.di_mode &= ~(S_ISUID|S_ISGID); | ||
| 1123 | |||
| 1124 | /* | ||
| 1125 | * Change the ownerships and register quota modifications | ||
| 1126 | * in the transaction. | ||
| 1127 | */ | ||
| 1128 | if (ip->i_d.di_projid != fa->fsx_projid) { | ||
| 1129 | if (XFS_IS_PQUOTA_ON(mp)) { | ||
| 1130 | olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip, | ||
| 1131 | &ip->i_gdquot, gdqp); | ||
| 1132 | } | ||
| 1133 | ip->i_d.di_projid = fa->fsx_projid; | ||
| 1134 | |||
| 1135 | /* | ||
| 1136 | * We may have to rev the inode as well as | ||
| 1137 | * the superblock version number since projids didn't | ||
| 1138 | * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. | ||
| 1139 | */ | ||
| 1140 | if (ip->i_d.di_version == XFS_DINODE_VERSION_1) | ||
| 1141 | xfs_bump_ino_vers2(tp, ip); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | } | ||
| 1145 | |||
| 1146 | if (mask & FSX_EXTSIZE) | ||
| 1147 | ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; | ||
| 1148 | if (mask & FSX_XFLAGS) { | ||
| 1149 | xfs_set_diflags(ip, fa->fsx_xflags); | ||
| 1150 | xfs_diflags_to_linux(ip); | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 1154 | xfs_ichgtime(ip, XFS_ICHGTIME_CHG); | ||
| 1155 | |||
| 1156 | XFS_STATS_INC(xs_ig_attrchg); | ||
| 1157 | |||
| 1158 | /* | ||
| 1159 | * If this is a synchronous mount, make sure that the | ||
| 1160 | * transaction goes to disk before returning to the user. | ||
| 1161 | * This is slightly sub-optimal in that truncates require | ||
| 1162 | * two sync transactions instead of one for wsync filesystems. | ||
| 1163 | * One for the truncate and one for the timestamps since we | ||
| 1164 | * don't want to change the timestamps unless we're sure the | ||
| 1165 | * truncate worked. Truncates are less than 1% of the laddis | ||
| 1166 | * mix so this probably isn't worth the trouble to optimize. | ||
| 1167 | */ | ||
| 1168 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
| 1169 | xfs_trans_set_sync(tp); | ||
| 1170 | code = xfs_trans_commit(tp, 0); | ||
| 1171 | xfs_iunlock(ip, lock_flags); | ||
| 1172 | |||
| 1173 | /* | ||
| 1174 | * Release any dquot(s) the inode had kept before chown. | ||
| 1175 | */ | ||
| 1176 | XFS_QM_DQRELE(mp, olddquot); | ||
| 1177 | XFS_QM_DQRELE(mp, udqp); | ||
| 1178 | XFS_QM_DQRELE(mp, gdqp); | ||
| 1179 | |||
| 1180 | if (code) | ||
| 1181 | return code; | ||
| 1182 | |||
| 1183 | if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) { | ||
| 1184 | XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL, | ||
| 1185 | NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0, | ||
| 1186 | (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0); | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | return 0; | ||
| 1190 | |||
| 1191 | error_return: | ||
| 1192 | XFS_QM_DQRELE(mp, udqp); | ||
| 1193 | XFS_QM_DQRELE(mp, gdqp); | ||
| 1194 | xfs_trans_cancel(tp, 0); | ||
| 1195 | if (lock_flags) | ||
| 1196 | xfs_iunlock(ip, lock_flags); | ||
| 1197 | return code; | ||
| 1198 | } | ||
| 1199 | |||
| 878 | STATIC int | 1200 | STATIC int |
| 879 | xfs_ioc_fssetxattr( | 1201 | xfs_ioc_fssetxattr( |
| 880 | xfs_inode_t *ip, | 1202 | xfs_inode_t *ip, |
| @@ -882,31 +1204,16 @@ xfs_ioc_fssetxattr( | |||
| 882 | void __user *arg) | 1204 | void __user *arg) |
| 883 | { | 1205 | { |
| 884 | struct fsxattr fa; | 1206 | struct fsxattr fa; |
| 885 | struct bhv_vattr *vattr; | 1207 | unsigned int mask; |
| 886 | int error; | ||
| 887 | int attr_flags; | ||
| 888 | 1208 | ||
| 889 | if (copy_from_user(&fa, arg, sizeof(fa))) | 1209 | if (copy_from_user(&fa, arg, sizeof(fa))) |
| 890 | return -EFAULT; | 1210 | return -EFAULT; |
| 891 | 1211 | ||
| 892 | vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); | 1212 | mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID; |
| 893 | if (unlikely(!vattr)) | ||
| 894 | return -ENOMEM; | ||
| 895 | |||
| 896 | attr_flags = 0; | ||
| 897 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 1213 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) |
| 898 | attr_flags |= ATTR_NONBLOCK; | 1214 | mask |= FSX_NONBLOCK; |
| 899 | |||
| 900 | vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; | ||
| 901 | vattr->va_xflags = fa.fsx_xflags; | ||
| 902 | vattr->va_extsize = fa.fsx_extsize; | ||
| 903 | vattr->va_projid = fa.fsx_projid; | ||
| 904 | 1215 | ||
| 905 | error = -xfs_setattr(ip, vattr, attr_flags, NULL); | 1216 | return -xfs_ioctl_setattr(ip, &fa, mask); |
| 906 | if (!error) | ||
| 907 | vn_revalidate(XFS_ITOV(ip)); /* update flags */ | ||
| 908 | kfree(vattr); | ||
| 909 | return 0; | ||
| 910 | } | 1217 | } |
| 911 | 1218 | ||
| 912 | STATIC int | 1219 | STATIC int |
| @@ -928,10 +1235,9 @@ xfs_ioc_setxflags( | |||
| 928 | struct file *filp, | 1235 | struct file *filp, |
| 929 | void __user *arg) | 1236 | void __user *arg) |
| 930 | { | 1237 | { |
| 931 | struct bhv_vattr *vattr; | 1238 | struct fsxattr fa; |
| 932 | unsigned int flags; | 1239 | unsigned int flags; |
| 933 | int attr_flags; | 1240 | unsigned int mask; |
| 934 | int error; | ||
| 935 | 1241 | ||
| 936 | if (copy_from_user(&flags, arg, sizeof(flags))) | 1242 | if (copy_from_user(&flags, arg, sizeof(flags))) |
| 937 | return -EFAULT; | 1243 | return -EFAULT; |
| @@ -941,22 +1247,12 @@ xfs_ioc_setxflags( | |||
| 941 | FS_SYNC_FL)) | 1247 | FS_SYNC_FL)) |
| 942 | return -EOPNOTSUPP; | 1248 | return -EOPNOTSUPP; |
| 943 | 1249 | ||
| 944 | vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); | 1250 | mask = FSX_XFLAGS; |
| 945 | if (unlikely(!vattr)) | ||
| 946 | return -ENOMEM; | ||
| 947 | |||
| 948 | attr_flags = 0; | ||
| 949 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | 1251 | if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) |
| 950 | attr_flags |= ATTR_NONBLOCK; | 1252 | mask |= FSX_NONBLOCK; |
| 951 | 1253 | fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); | |
| 952 | vattr->va_mask = XFS_AT_XFLAGS; | ||
| 953 | vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); | ||
| 954 | 1254 | ||
| 955 | error = -xfs_setattr(ip, vattr, attr_flags, NULL); | 1255 | return -xfs_ioctl_setattr(ip, &fa, mask); |
| 956 | if (likely(!error)) | ||
| 957 | vn_revalidate(XFS_ITOV(ip)); /* update flags */ | ||
| 958 | kfree(vattr); | ||
| 959 | return error; | ||
| 960 | } | 1256 | } |
| 961 | 1257 | ||
| 962 | STATIC int | 1258 | STATIC int |
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 2bf287ef5489..095d271f3434 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
| @@ -62,7 +62,7 @@ void | |||
| 62 | xfs_synchronize_atime( | 62 | xfs_synchronize_atime( |
| 63 | xfs_inode_t *ip) | 63 | xfs_inode_t *ip) |
| 64 | { | 64 | { |
| 65 | struct inode *inode = ip->i_vnode; | 65 | struct inode *inode = VFS_I(ip); |
| 66 | 66 | ||
| 67 | if (inode) { | 67 | if (inode) { |
| 68 | ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec; | 68 | ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec; |
| @@ -79,7 +79,7 @@ void | |||
| 79 | xfs_mark_inode_dirty_sync( | 79 | xfs_mark_inode_dirty_sync( |
| 80 | xfs_inode_t *ip) | 80 | xfs_inode_t *ip) |
| 81 | { | 81 | { |
| 82 | struct inode *inode = ip->i_vnode; | 82 | struct inode *inode = VFS_I(ip); |
| 83 | 83 | ||
| 84 | if (inode) | 84 | if (inode) |
| 85 | mark_inode_dirty_sync(inode); | 85 | mark_inode_dirty_sync(inode); |
| @@ -89,36 +89,31 @@ xfs_mark_inode_dirty_sync( | |||
| 89 | * Change the requested timestamp in the given inode. | 89 | * Change the requested timestamp in the given inode. |
| 90 | * We don't lock across timestamp updates, and we don't log them but | 90 | * We don't lock across timestamp updates, and we don't log them but |
| 91 | * we do record the fact that there is dirty information in core. | 91 | * we do record the fact that there is dirty information in core. |
| 92 | * | ||
| 93 | * NOTE -- callers MUST combine XFS_ICHGTIME_MOD or XFS_ICHGTIME_CHG | ||
| 94 | * with XFS_ICHGTIME_ACC to be sure that access time | ||
| 95 | * update will take. Calling first with XFS_ICHGTIME_ACC | ||
| 96 | * and then XFS_ICHGTIME_MOD may fail to modify the access | ||
| 97 | * timestamp if the filesystem is mounted noacctm. | ||
| 98 | */ | 92 | */ |
| 99 | void | 93 | void |
| 100 | xfs_ichgtime( | 94 | xfs_ichgtime( |
| 101 | xfs_inode_t *ip, | 95 | xfs_inode_t *ip, |
| 102 | int flags) | 96 | int flags) |
| 103 | { | 97 | { |
| 104 | struct inode *inode = vn_to_inode(XFS_ITOV(ip)); | 98 | struct inode *inode = VFS_I(ip); |
| 105 | timespec_t tv; | 99 | timespec_t tv; |
| 100 | int sync_it = 0; | ||
| 101 | |||
| 102 | tv = current_fs_time(inode->i_sb); | ||
| 106 | 103 | ||
| 107 | nanotime(&tv); | 104 | if ((flags & XFS_ICHGTIME_MOD) && |
| 108 | if (flags & XFS_ICHGTIME_MOD) { | 105 | !timespec_equal(&inode->i_mtime, &tv)) { |
| 109 | inode->i_mtime = tv; | 106 | inode->i_mtime = tv; |
| 110 | ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; | 107 | ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; |
| 111 | ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; | 108 | ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; |
| 109 | sync_it = 1; | ||
| 112 | } | 110 | } |
| 113 | if (flags & XFS_ICHGTIME_ACC) { | 111 | if ((flags & XFS_ICHGTIME_CHG) && |
| 114 | inode->i_atime = tv; | 112 | !timespec_equal(&inode->i_ctime, &tv)) { |
| 115 | ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec; | ||
| 116 | ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec; | ||
| 117 | } | ||
| 118 | if (flags & XFS_ICHGTIME_CHG) { | ||
| 119 | inode->i_ctime = tv; | 113 | inode->i_ctime = tv; |
| 120 | ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec; | 114 | ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec; |
| 121 | ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec; | 115 | ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec; |
| 116 | sync_it = 1; | ||
| 122 | } | 117 | } |
| 123 | 118 | ||
| 124 | /* | 119 | /* |
| @@ -130,72 +125,11 @@ xfs_ichgtime( | |||
| 130 | * ensure that the compiler does not reorder the update | 125 | * ensure that the compiler does not reorder the update |
| 131 | * of i_update_core above the timestamp updates above. | 126 | * of i_update_core above the timestamp updates above. |
| 132 | */ | 127 | */ |
| 133 | SYNCHRONIZE(); | 128 | if (sync_it) { |
| 134 | ip->i_update_core = 1; | 129 | SYNCHRONIZE(); |
| 135 | if (!(inode->i_state & I_NEW)) | 130 | ip->i_update_core = 1; |
| 136 | mark_inode_dirty_sync(inode); | 131 | mark_inode_dirty_sync(inode); |
| 137 | } | ||
| 138 | |||
| 139 | /* | ||
| 140 | * Variant on the above which avoids querying the system clock | ||
| 141 | * in situations where we know the Linux inode timestamps have | ||
| 142 | * just been updated (and so we can update our inode cheaply). | ||
| 143 | */ | ||
| 144 | void | ||
| 145 | xfs_ichgtime_fast( | ||
| 146 | xfs_inode_t *ip, | ||
| 147 | struct inode *inode, | ||
| 148 | int flags) | ||
| 149 | { | ||
| 150 | timespec_t *tvp; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * Atime updates for read() & friends are handled lazily now, and | ||
| 154 | * explicit updates must go through xfs_ichgtime() | ||
| 155 | */ | ||
| 156 | ASSERT((flags & XFS_ICHGTIME_ACC) == 0); | ||
| 157 | |||
| 158 | if (flags & XFS_ICHGTIME_MOD) { | ||
| 159 | tvp = &inode->i_mtime; | ||
| 160 | ip->i_d.di_mtime.t_sec = (__int32_t)tvp->tv_sec; | ||
| 161 | ip->i_d.di_mtime.t_nsec = (__int32_t)tvp->tv_nsec; | ||
| 162 | } | ||
| 163 | if (flags & XFS_ICHGTIME_CHG) { | ||
| 164 | tvp = &inode->i_ctime; | ||
| 165 | ip->i_d.di_ctime.t_sec = (__int32_t)tvp->tv_sec; | ||
| 166 | ip->i_d.di_ctime.t_nsec = (__int32_t)tvp->tv_nsec; | ||
| 167 | } | 132 | } |
| 168 | |||
| 169 | /* | ||
| 170 | * We update the i_update_core field _after_ changing | ||
| 171 | * the timestamps in order to coordinate properly with | ||
| 172 | * xfs_iflush() so that we don't lose timestamp updates. | ||
| 173 | * This keeps us from having to hold the inode lock | ||
| 174 | * while doing this. We use the SYNCHRONIZE macro to | ||
| 175 | * ensure that the compiler does not reorder the update | ||
| 176 | * of i_update_core above the timestamp updates above. | ||
| 177 | */ | ||
| 178 | SYNCHRONIZE(); | ||
| 179 | ip->i_update_core = 1; | ||
| 180 | if (!(inode->i_state & I_NEW)) | ||
| 181 | mark_inode_dirty_sync(inode); | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | /* | ||
| 186 | * Pull the link count and size up from the xfs inode to the linux inode | ||
| 187 | */ | ||
| 188 | STATIC void | ||
| 189 | xfs_validate_fields( | ||
| 190 | struct inode *inode) | ||
| 191 | { | ||
| 192 | struct xfs_inode *ip = XFS_I(inode); | ||
| 193 | loff_t size; | ||
| 194 | |||
| 195 | /* we're under i_sem so i_size can't change under us */ | ||
| 196 | size = XFS_ISIZE(ip); | ||
| 197 | if (i_size_read(inode) != size) | ||
| 198 | i_size_write(inode, size); | ||
| 199 | } | 133 | } |
| 200 | 134 | ||
| 201 | /* | 135 | /* |
| @@ -245,8 +179,7 @@ STATIC void | |||
| 245 | xfs_cleanup_inode( | 179 | xfs_cleanup_inode( |
| 246 | struct inode *dir, | 180 | struct inode *dir, |
| 247 | struct inode *inode, | 181 | struct inode *inode, |
| 248 | struct dentry *dentry, | 182 | struct dentry *dentry) |
| 249 | int mode) | ||
| 250 | { | 183 | { |
| 251 | struct xfs_name teardown; | 184 | struct xfs_name teardown; |
| 252 | 185 | ||
| @@ -257,10 +190,7 @@ xfs_cleanup_inode( | |||
| 257 | */ | 190 | */ |
| 258 | xfs_dentry_to_name(&teardown, dentry); | 191 | xfs_dentry_to_name(&teardown, dentry); |
| 259 | 192 | ||
| 260 | if (S_ISDIR(mode)) | 193 | xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); |
| 261 | xfs_rmdir(XFS_I(dir), &teardown, XFS_I(inode)); | ||
| 262 | else | ||
| 263 | xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); | ||
| 264 | iput(inode); | 194 | iput(inode); |
| 265 | } | 195 | } |
| 266 | 196 | ||
| @@ -275,7 +205,7 @@ xfs_vn_mknod( | |||
| 275 | struct xfs_inode *ip = NULL; | 205 | struct xfs_inode *ip = NULL; |
| 276 | xfs_acl_t *default_acl = NULL; | 206 | xfs_acl_t *default_acl = NULL; |
| 277 | struct xfs_name name; | 207 | struct xfs_name name; |
| 278 | attrexists_t test_default_acl = _ACL_DEFAULT_EXISTS; | 208 | int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS; |
| 279 | int error; | 209 | int error; |
| 280 | 210 | ||
| 281 | /* | 211 | /* |
| @@ -320,7 +250,7 @@ xfs_vn_mknod( | |||
| 320 | if (unlikely(error)) | 250 | if (unlikely(error)) |
| 321 | goto out_free_acl; | 251 | goto out_free_acl; |
| 322 | 252 | ||
| 323 | inode = ip->i_vnode; | 253 | inode = VFS_I(ip); |
| 324 | 254 | ||
| 325 | error = xfs_init_security(inode, dir); | 255 | error = xfs_init_security(inode, dir); |
| 326 | if (unlikely(error)) | 256 | if (unlikely(error)) |
| @@ -335,14 +265,11 @@ xfs_vn_mknod( | |||
| 335 | } | 265 | } |
| 336 | 266 | ||
| 337 | 267 | ||
| 338 | if (S_ISDIR(mode)) | ||
| 339 | xfs_validate_fields(inode); | ||
| 340 | d_instantiate(dentry, inode); | 268 | d_instantiate(dentry, inode); |
| 341 | xfs_validate_fields(dir); | ||
| 342 | return -error; | 269 | return -error; |
| 343 | 270 | ||
| 344 | out_cleanup_inode: | 271 | out_cleanup_inode: |
| 345 | xfs_cleanup_inode(dir, inode, dentry, mode); | 272 | xfs_cleanup_inode(dir, inode, dentry); |
| 346 | out_free_acl: | 273 | out_free_acl: |
| 347 | if (default_acl) | 274 | if (default_acl) |
| 348 | _ACL_FREE(default_acl); | 275 | _ACL_FREE(default_acl); |
| @@ -382,7 +309,7 @@ xfs_vn_lookup( | |||
| 382 | return ERR_PTR(-ENAMETOOLONG); | 309 | return ERR_PTR(-ENAMETOOLONG); |
| 383 | 310 | ||
| 384 | xfs_dentry_to_name(&name, dentry); | 311 | xfs_dentry_to_name(&name, dentry); |
| 385 | error = xfs_lookup(XFS_I(dir), &name, &cip); | 312 | error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); |
| 386 | if (unlikely(error)) { | 313 | if (unlikely(error)) { |
| 387 | if (unlikely(error != ENOENT)) | 314 | if (unlikely(error != ENOENT)) |
| 388 | return ERR_PTR(-error); | 315 | return ERR_PTR(-error); |
| @@ -390,7 +317,47 @@ xfs_vn_lookup( | |||
| 390 | return NULL; | 317 | return NULL; |
| 391 | } | 318 | } |
| 392 | 319 | ||
| 393 | return d_splice_alias(cip->i_vnode, dentry); | 320 | return d_splice_alias(VFS_I(cip), dentry); |
| 321 | } | ||
| 322 | |||
| 323 | STATIC struct dentry * | ||
| 324 | xfs_vn_ci_lookup( | ||
| 325 | struct inode *dir, | ||
| 326 | struct dentry *dentry, | ||
| 327 | struct nameidata *nd) | ||
| 328 | { | ||
| 329 | struct xfs_inode *ip; | ||
| 330 | struct xfs_name xname; | ||
| 331 | struct xfs_name ci_name; | ||
| 332 | struct qstr dname; | ||
| 333 | int error; | ||
| 334 | |||
| 335 | if (dentry->d_name.len >= MAXNAMELEN) | ||
| 336 | return ERR_PTR(-ENAMETOOLONG); | ||
| 337 | |||
| 338 | xfs_dentry_to_name(&xname, dentry); | ||
| 339 | error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); | ||
| 340 | if (unlikely(error)) { | ||
| 341 | if (unlikely(error != ENOENT)) | ||
| 342 | return ERR_PTR(-error); | ||
| 343 | /* | ||
| 344 | * call d_add(dentry, NULL) here when d_drop_negative_children | ||
| 345 | * is called in xfs_vn_mknod (ie. allow negative dentries | ||
| 346 | * with CI filesystems). | ||
| 347 | */ | ||
| 348 | return NULL; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* if exact match, just splice and exit */ | ||
| 352 | if (!ci_name.name) | ||
| 353 | return d_splice_alias(VFS_I(ip), dentry); | ||
| 354 | |||
| 355 | /* else case-insensitive match... */ | ||
| 356 | dname.name = ci_name.name; | ||
| 357 | dname.len = ci_name.len; | ||
| 358 | dentry = d_add_ci(dentry, VFS_I(ip), &dname); | ||
| 359 | kmem_free(ci_name.name); | ||
| 360 | return dentry; | ||
| 394 | } | 361 | } |
| 395 | 362 | ||
| 396 | STATIC int | 363 | STATIC int |
| @@ -414,7 +381,6 @@ xfs_vn_link( | |||
| 414 | } | 381 | } |
| 415 | 382 | ||
| 416 | xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED); | 383 | xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED); |
| 417 | xfs_validate_fields(inode); | ||
| 418 | d_instantiate(dentry, inode); | 384 | d_instantiate(dentry, inode); |
| 419 | return 0; | 385 | return 0; |
| 420 | } | 386 | } |
| @@ -424,19 +390,23 @@ xfs_vn_unlink( | |||
| 424 | struct inode *dir, | 390 | struct inode *dir, |
| 425 | struct dentry *dentry) | 391 | struct dentry *dentry) |
| 426 | { | 392 | { |
| 427 | struct inode *inode; | ||
| 428 | struct xfs_name name; | 393 | struct xfs_name name; |
| 429 | int error; | 394 | int error; |
| 430 | 395 | ||
| 431 | inode = dentry->d_inode; | ||
| 432 | xfs_dentry_to_name(&name, dentry); | 396 | xfs_dentry_to_name(&name, dentry); |
| 433 | 397 | ||
| 434 | error = xfs_remove(XFS_I(dir), &name, XFS_I(inode)); | 398 | error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode)); |
| 435 | if (likely(!error)) { | 399 | if (error) |
| 436 | xfs_validate_fields(dir); /* size needs update */ | 400 | return error; |
| 437 | xfs_validate_fields(inode); | 401 | |
| 438 | } | 402 | /* |
| 439 | return -error; | 403 | * With unlink, the VFS makes the dentry "negative": no inode, |
| 404 | * but still hashed. This is incompatible with case-insensitive | ||
| 405 | * mode, so invalidate (unhash) the dentry in CI-mode. | ||
| 406 | */ | ||
| 407 | if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) | ||
| 408 | d_invalidate(dentry); | ||
| 409 | return 0; | ||
| 440 | } | 410 | } |
| 441 | 411 | ||
| 442 | STATIC int | 412 | STATIC int |
| @@ -459,43 +429,22 @@ xfs_vn_symlink( | |||
| 459 | if (unlikely(error)) | 429 | if (unlikely(error)) |
| 460 | goto out; | 430 | goto out; |
| 461 | 431 | ||
| 462 | inode = cip->i_vnode; | 432 | inode = VFS_I(cip); |
| 463 | 433 | ||
| 464 | error = xfs_init_security(inode, dir); | 434 | error = xfs_init_security(inode, dir); |
| 465 | if (unlikely(error)) | 435 | if (unlikely(error)) |
| 466 | goto out_cleanup_inode; | 436 | goto out_cleanup_inode; |
| 467 | 437 | ||
| 468 | d_instantiate(dentry, inode); | 438 | d_instantiate(dentry, inode); |
| 469 | xfs_validate_fields(dir); | ||
| 470 | xfs_validate_fields(inode); | ||
| 471 | return 0; | 439 | return 0; |
| 472 | 440 | ||
| 473 | out_cleanup_inode: | 441 | out_cleanup_inode: |
| 474 | xfs_cleanup_inode(dir, inode, dentry, 0); | 442 | xfs_cleanup_inode(dir, inode, dentry); |
| 475 | out: | 443 | out: |
| 476 | return -error; | 444 | return -error; |
| 477 | } | 445 | } |
| 478 | 446 | ||
| 479 | STATIC int | 447 | STATIC int |
| 480 | xfs_vn_rmdir( | ||
| 481 | struct inode *dir, | ||
| 482 | struct dentry *dentry) | ||
| 483 | { | ||
| 484 | struct inode *inode = dentry->d_inode; | ||
| 485 | struct xfs_name name; | ||
| 486 | int error; | ||
| 487 | |||
| 488 | xfs_dentry_to_name(&name, dentry); | ||
| 489 | |||
| 490 | error = xfs_rmdir(XFS_I(dir), &name, XFS_I(inode)); | ||
| 491 | if (likely(!error)) { | ||
| 492 | xfs_validate_fields(inode); | ||
| 493 | xfs_validate_fields(dir); | ||
| 494 | } | ||
| 495 | return -error; | ||
| 496 | } | ||
| 497 | |||
| 498 | STATIC int | ||
| 499 | xfs_vn_rename( | 448 | xfs_vn_rename( |
| 500 | struct inode *odir, | 449 | struct inode *odir, |
| 501 | struct dentry *odentry, | 450 | struct dentry *odentry, |
| @@ -505,22 +454,13 @@ xfs_vn_rename( | |||
| 505 | struct inode *new_inode = ndentry->d_inode; | 454 | struct inode *new_inode = ndentry->d_inode; |
| 506 | struct xfs_name oname; | 455 | struct xfs_name oname; |
| 507 | struct xfs_name nname; | 456 | struct xfs_name nname; |
| 508 | int error; | ||
| 509 | 457 | ||
| 510 | xfs_dentry_to_name(&oname, odentry); | 458 | xfs_dentry_to_name(&oname, odentry); |
| 511 | xfs_dentry_to_name(&nname, ndentry); | 459 | xfs_dentry_to_name(&nname, ndentry); |
| 512 | 460 | ||
| 513 | error = xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), | 461 | return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode), |
| 514 | XFS_I(ndir), &nname, new_inode ? | 462 | XFS_I(ndir), &nname, new_inode ? |
| 515 | XFS_I(new_inode) : NULL); | 463 | XFS_I(new_inode) : NULL); |
| 516 | if (likely(!error)) { | ||
| 517 | if (new_inode) | ||
| 518 | xfs_validate_fields(new_inode); | ||
| 519 | xfs_validate_fields(odir); | ||
| 520 | if (ndir != odir) | ||
| 521 | xfs_validate_fields(ndir); | ||
| 522 | } | ||
| 523 | return -error; | ||
| 524 | } | 464 | } |
| 525 | 465 | ||
| 526 | /* | 466 | /* |
| @@ -589,8 +529,7 @@ xfs_check_acl( | |||
| 589 | STATIC int | 529 | STATIC int |
| 590 | xfs_vn_permission( | 530 | xfs_vn_permission( |
| 591 | struct inode *inode, | 531 | struct inode *inode, |
| 592 | int mask, | 532 | int mask) |
| 593 | struct nameidata *nd) | ||
| 594 | { | 533 | { |
| 595 | return generic_permission(inode, mask, xfs_check_acl); | 534 | return generic_permission(inode, mask, xfs_check_acl); |
| 596 | } | 535 | } |
| @@ -660,57 +599,9 @@ xfs_vn_getattr( | |||
| 660 | STATIC int | 599 | STATIC int |
| 661 | xfs_vn_setattr( | 600 | xfs_vn_setattr( |
| 662 | struct dentry *dentry, | 601 | struct dentry *dentry, |
| 663 | struct iattr *attr) | 602 | struct iattr *iattr) |
| 664 | { | 603 | { |
| 665 | struct inode *inode = dentry->d_inode; | 604 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0, NULL); |
| 666 | unsigned int ia_valid = attr->ia_valid; | ||
| 667 | bhv_vattr_t vattr = { 0 }; | ||
| 668 | int flags = 0; | ||
| 669 | int error; | ||
| 670 | |||
| 671 | if (ia_valid & ATTR_UID) { | ||
| 672 | vattr.va_mask |= XFS_AT_UID; | ||
| 673 | vattr.va_uid = attr->ia_uid; | ||
| 674 | } | ||
| 675 | if (ia_valid & ATTR_GID) { | ||
| 676 | vattr.va_mask |= XFS_AT_GID; | ||
| 677 | vattr.va_gid = attr->ia_gid; | ||
| 678 | } | ||
| 679 | if (ia_valid & ATTR_SIZE) { | ||
| 680 | vattr.va_mask |= XFS_AT_SIZE; | ||
| 681 | vattr.va_size = attr->ia_size; | ||
| 682 | } | ||
| 683 | if (ia_valid & ATTR_ATIME) { | ||
| 684 | vattr.va_mask |= XFS_AT_ATIME; | ||
| 685 | vattr.va_atime = attr->ia_atime; | ||
| 686 | inode->i_atime = attr->ia_atime; | ||
| 687 | } | ||
| 688 | if (ia_valid & ATTR_MTIME) { | ||
| 689 | vattr.va_mask |= XFS_AT_MTIME; | ||
| 690 | vattr.va_mtime = attr->ia_mtime; | ||
| 691 | } | ||
| 692 | if (ia_valid & ATTR_CTIME) { | ||
| 693 | vattr.va_mask |= XFS_AT_CTIME; | ||
| 694 | vattr.va_ctime = attr->ia_ctime; | ||
| 695 | } | ||
| 696 | if (ia_valid & ATTR_MODE) { | ||
| 697 | vattr.va_mask |= XFS_AT_MODE; | ||
| 698 | vattr.va_mode = attr->ia_mode; | ||
| 699 | if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) | ||
| 700 | inode->i_mode &= ~S_ISGID; | ||
| 701 | } | ||
| 702 | |||
| 703 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) | ||
| 704 | flags |= ATTR_UTIME; | ||
| 705 | #ifdef ATTR_NO_BLOCK | ||
| 706 | if ((ia_valid & ATTR_NO_BLOCK)) | ||
| 707 | flags |= ATTR_NONBLOCK; | ||
| 708 | #endif | ||
| 709 | |||
| 710 | error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL); | ||
| 711 | if (likely(!error)) | ||
| 712 | vn_revalidate(vn_from_inode(inode)); | ||
| 713 | return -error; | ||
| 714 | } | 605 | } |
| 715 | 606 | ||
| 716 | /* | 607 | /* |
| @@ -728,109 +619,6 @@ xfs_vn_truncate( | |||
| 728 | WARN_ON(error); | 619 | WARN_ON(error); |
| 729 | } | 620 | } |
| 730 | 621 | ||
| 731 | STATIC int | ||
| 732 | xfs_vn_setxattr( | ||
| 733 | struct dentry *dentry, | ||
| 734 | const char *name, | ||
| 735 | const void *data, | ||
| 736 | size_t size, | ||
| 737 | int flags) | ||
| 738 | { | ||
| 739 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); | ||
| 740 | char *attr = (char *)name; | ||
| 741 | attrnames_t *namesp; | ||
| 742 | int xflags = 0; | ||
| 743 | int error; | ||
| 744 | |||
| 745 | namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); | ||
| 746 | if (!namesp) | ||
| 747 | return -EOPNOTSUPP; | ||
| 748 | attr += namesp->attr_namelen; | ||
| 749 | error = namesp->attr_capable(vp, NULL); | ||
| 750 | if (error) | ||
| 751 | return error; | ||
| 752 | |||
| 753 | /* Convert Linux syscall to XFS internal ATTR flags */ | ||
| 754 | if (flags & XATTR_CREATE) | ||
| 755 | xflags |= ATTR_CREATE; | ||
| 756 | if (flags & XATTR_REPLACE) | ||
| 757 | xflags |= ATTR_REPLACE; | ||
| 758 | xflags |= namesp->attr_flag; | ||
| 759 | return namesp->attr_set(vp, attr, (void *)data, size, xflags); | ||
| 760 | } | ||
| 761 | |||
| 762 | STATIC ssize_t | ||
| 763 | xfs_vn_getxattr( | ||
| 764 | struct dentry *dentry, | ||
| 765 | const char *name, | ||
| 766 | void *data, | ||
| 767 | size_t size) | ||
| 768 | { | ||
| 769 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); | ||
| 770 | char *attr = (char *)name; | ||
| 771 | attrnames_t *namesp; | ||
| 772 | int xflags = 0; | ||
| 773 | ssize_t error; | ||
| 774 | |||
| 775 | namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); | ||
| 776 | if (!namesp) | ||
| 777 | return -EOPNOTSUPP; | ||
| 778 | attr += namesp->attr_namelen; | ||
| 779 | error = namesp->attr_capable(vp, NULL); | ||
| 780 | if (error) | ||
| 781 | return error; | ||
| 782 | |||
| 783 | /* Convert Linux syscall to XFS internal ATTR flags */ | ||
| 784 | if (!size) { | ||
| 785 | xflags |= ATTR_KERNOVAL; | ||
| 786 | data = NULL; | ||
| 787 | } | ||
| 788 | xflags |= namesp->attr_flag; | ||
| 789 | return namesp->attr_get(vp, attr, (void *)data, size, xflags); | ||
| 790 | } | ||
| 791 | |||
| 792 | STATIC ssize_t | ||
| 793 | xfs_vn_listxattr( | ||
| 794 | struct dentry *dentry, | ||
| 795 | char *data, | ||
| 796 | size_t size) | ||
| 797 | { | ||
| 798 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); | ||
| 799 | int error, xflags = ATTR_KERNAMELS; | ||
| 800 | ssize_t result; | ||
| 801 | |||
| 802 | if (!size) | ||
| 803 | xflags |= ATTR_KERNOVAL; | ||
| 804 | xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS; | ||
| 805 | |||
| 806 | error = attr_generic_list(vp, data, size, xflags, &result); | ||
| 807 | if (error < 0) | ||
| 808 | return error; | ||
| 809 | return result; | ||
| 810 | } | ||
| 811 | |||
| 812 | STATIC int | ||
| 813 | xfs_vn_removexattr( | ||
| 814 | struct dentry *dentry, | ||
| 815 | const char *name) | ||
| 816 | { | ||
| 817 | bhv_vnode_t *vp = vn_from_inode(dentry->d_inode); | ||
| 818 | char *attr = (char *)name; | ||
| 819 | attrnames_t *namesp; | ||
| 820 | int xflags = 0; | ||
| 821 | int error; | ||
| 822 | |||
| 823 | namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT); | ||
| 824 | if (!namesp) | ||
| 825 | return -EOPNOTSUPP; | ||
| 826 | attr += namesp->attr_namelen; | ||
| 827 | error = namesp->attr_capable(vp, NULL); | ||
| 828 | if (error) | ||
| 829 | return error; | ||
| 830 | xflags |= namesp->attr_flag; | ||
| 831 | return namesp->attr_remove(vp, attr, xflags); | ||
| 832 | } | ||
| 833 | |||
| 834 | STATIC long | 622 | STATIC long |
| 835 | xfs_vn_fallocate( | 623 | xfs_vn_fallocate( |
| 836 | struct inode *inode, | 624 | struct inode *inode, |
| @@ -854,18 +642,18 @@ xfs_vn_fallocate( | |||
| 854 | 642 | ||
| 855 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 643 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
| 856 | error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, | 644 | error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, |
| 857 | 0, NULL, ATTR_NOLOCK); | 645 | 0, NULL, XFS_ATTR_NOLOCK); |
| 858 | if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && | 646 | if (!error && !(mode & FALLOC_FL_KEEP_SIZE) && |
| 859 | offset + len > i_size_read(inode)) | 647 | offset + len > i_size_read(inode)) |
| 860 | new_size = offset + len; | 648 | new_size = offset + len; |
| 861 | 649 | ||
| 862 | /* Change file size if needed */ | 650 | /* Change file size if needed */ |
| 863 | if (new_size) { | 651 | if (new_size) { |
| 864 | bhv_vattr_t va; | 652 | struct iattr iattr; |
| 865 | 653 | ||
| 866 | va.va_mask = XFS_AT_SIZE; | 654 | iattr.ia_valid = ATTR_SIZE; |
| 867 | va.va_size = new_size; | 655 | iattr.ia_size = new_size; |
| 868 | error = xfs_setattr(ip, &va, ATTR_NOLOCK, NULL); | 656 | error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK, NULL); |
| 869 | } | 657 | } |
| 870 | 658 | ||
| 871 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 659 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
| @@ -873,46 +661,172 @@ out_error: | |||
| 873 | return error; | 661 | return error; |
| 874 | } | 662 | } |
| 875 | 663 | ||
| 876 | const struct inode_operations xfs_inode_operations = { | 664 | static const struct inode_operations xfs_inode_operations = { |
| 877 | .permission = xfs_vn_permission, | 665 | .permission = xfs_vn_permission, |
| 878 | .truncate = xfs_vn_truncate, | 666 | .truncate = xfs_vn_truncate, |
| 879 | .getattr = xfs_vn_getattr, | 667 | .getattr = xfs_vn_getattr, |
| 880 | .setattr = xfs_vn_setattr, | 668 | .setattr = xfs_vn_setattr, |
| 881 | .setxattr = xfs_vn_setxattr, | 669 | .setxattr = generic_setxattr, |
| 882 | .getxattr = xfs_vn_getxattr, | 670 | .getxattr = generic_getxattr, |
| 671 | .removexattr = generic_removexattr, | ||
| 883 | .listxattr = xfs_vn_listxattr, | 672 | .listxattr = xfs_vn_listxattr, |
| 884 | .removexattr = xfs_vn_removexattr, | ||
| 885 | .fallocate = xfs_vn_fallocate, | 673 | .fallocate = xfs_vn_fallocate, |
| 886 | }; | 674 | }; |
| 887 | 675 | ||
| 888 | const struct inode_operations xfs_dir_inode_operations = { | 676 | static const struct inode_operations xfs_dir_inode_operations = { |
| 889 | .create = xfs_vn_create, | 677 | .create = xfs_vn_create, |
| 890 | .lookup = xfs_vn_lookup, | 678 | .lookup = xfs_vn_lookup, |
| 891 | .link = xfs_vn_link, | 679 | .link = xfs_vn_link, |
| 892 | .unlink = xfs_vn_unlink, | 680 | .unlink = xfs_vn_unlink, |
| 893 | .symlink = xfs_vn_symlink, | 681 | .symlink = xfs_vn_symlink, |
| 894 | .mkdir = xfs_vn_mkdir, | 682 | .mkdir = xfs_vn_mkdir, |
| 895 | .rmdir = xfs_vn_rmdir, | 683 | /* |
| 684 | * Yes, XFS uses the same method for rmdir and unlink. | ||
| 685 | * | ||
| 686 | * There are some subtile differences deeper in the code, | ||
| 687 | * but we use S_ISDIR to check for those. | ||
| 688 | */ | ||
| 689 | .rmdir = xfs_vn_unlink, | ||
| 896 | .mknod = xfs_vn_mknod, | 690 | .mknod = xfs_vn_mknod, |
| 897 | .rename = xfs_vn_rename, | 691 | .rename = xfs_vn_rename, |
| 898 | .permission = xfs_vn_permission, | 692 | .permission = xfs_vn_permission, |
| 899 | .getattr = xfs_vn_getattr, | 693 | .getattr = xfs_vn_getattr, |
| 900 | .setattr = xfs_vn_setattr, | 694 | .setattr = xfs_vn_setattr, |
| 901 | .setxattr = xfs_vn_setxattr, | 695 | .setxattr = generic_setxattr, |
| 902 | .getxattr = xfs_vn_getxattr, | 696 | .getxattr = generic_getxattr, |
| 697 | .removexattr = generic_removexattr, | ||
| 903 | .listxattr = xfs_vn_listxattr, | 698 | .listxattr = xfs_vn_listxattr, |
| 904 | .removexattr = xfs_vn_removexattr, | ||
| 905 | }; | 699 | }; |
| 906 | 700 | ||
| 907 | const struct inode_operations xfs_symlink_inode_operations = { | 701 | static const struct inode_operations xfs_dir_ci_inode_operations = { |
| 702 | .create = xfs_vn_create, | ||
| 703 | .lookup = xfs_vn_ci_lookup, | ||
| 704 | .link = xfs_vn_link, | ||
| 705 | .unlink = xfs_vn_unlink, | ||
| 706 | .symlink = xfs_vn_symlink, | ||
| 707 | .mkdir = xfs_vn_mkdir, | ||
| 708 | /* | ||
| 709 | * Yes, XFS uses the same method for rmdir and unlink. | ||
| 710 | * | ||
| 711 | * There are some subtile differences deeper in the code, | ||
| 712 | * but we use S_ISDIR to check for those. | ||
| 713 | */ | ||
| 714 | .rmdir = xfs_vn_unlink, | ||
| 715 | .mknod = xfs_vn_mknod, | ||
| 716 | .rename = xfs_vn_rename, | ||
| 717 | .permission = xfs_vn_permission, | ||
| 718 | .getattr = xfs_vn_getattr, | ||
| 719 | .setattr = xfs_vn_setattr, | ||
| 720 | .setxattr = generic_setxattr, | ||
| 721 | .getxattr = generic_getxattr, | ||
| 722 | .removexattr = generic_removexattr, | ||
| 723 | .listxattr = xfs_vn_listxattr, | ||
| 724 | }; | ||
| 725 | |||
| 726 | static const struct inode_operations xfs_symlink_inode_operations = { | ||
| 908 | .readlink = generic_readlink, | 727 | .readlink = generic_readlink, |
| 909 | .follow_link = xfs_vn_follow_link, | 728 | .follow_link = xfs_vn_follow_link, |
| 910 | .put_link = xfs_vn_put_link, | 729 | .put_link = xfs_vn_put_link, |
| 911 | .permission = xfs_vn_permission, | 730 | .permission = xfs_vn_permission, |
| 912 | .getattr = xfs_vn_getattr, | 731 | .getattr = xfs_vn_getattr, |
| 913 | .setattr = xfs_vn_setattr, | 732 | .setattr = xfs_vn_setattr, |
| 914 | .setxattr = xfs_vn_setxattr, | 733 | .setxattr = generic_setxattr, |
| 915 | .getxattr = xfs_vn_getxattr, | 734 | .getxattr = generic_getxattr, |
| 735 | .removexattr = generic_removexattr, | ||
| 916 | .listxattr = xfs_vn_listxattr, | 736 | .listxattr = xfs_vn_listxattr, |
| 917 | .removexattr = xfs_vn_removexattr, | ||
| 918 | }; | 737 | }; |
| 738 | |||
| 739 | STATIC void | ||
| 740 | xfs_diflags_to_iflags( | ||
| 741 | struct inode *inode, | ||
| 742 | struct xfs_inode *ip) | ||
| 743 | { | ||
| 744 | if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) | ||
| 745 | inode->i_flags |= S_IMMUTABLE; | ||
| 746 | else | ||
| 747 | inode->i_flags &= ~S_IMMUTABLE; | ||
| 748 | if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) | ||
| 749 | inode->i_flags |= S_APPEND; | ||
| 750 | else | ||
| 751 | inode->i_flags &= ~S_APPEND; | ||
| 752 | if (ip->i_d.di_flags & XFS_DIFLAG_SYNC) | ||
| 753 | inode->i_flags |= S_SYNC; | ||
| 754 | else | ||
| 755 | inode->i_flags &= ~S_SYNC; | ||
| 756 | if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME) | ||
| 757 | inode->i_flags |= S_NOATIME; | ||
| 758 | else | ||
| 759 | inode->i_flags &= ~S_NOATIME; | ||
| 760 | } | ||
| 761 | |||
| 762 | /* | ||
| 763 | * Initialize the Linux inode, set up the operation vectors and | ||
| 764 | * unlock the inode. | ||
| 765 | * | ||
| 766 | * When reading existing inodes from disk this is called directly | ||
| 767 | * from xfs_iget, when creating a new inode it is called from | ||
| 768 | * xfs_ialloc after setting up the inode. | ||
| 769 | */ | ||
| 770 | void | ||
| 771 | xfs_setup_inode( | ||
| 772 | struct xfs_inode *ip) | ||
| 773 | { | ||
| 774 | struct inode *inode = ip->i_vnode; | ||
| 775 | |||
| 776 | inode->i_mode = ip->i_d.di_mode; | ||
| 777 | inode->i_nlink = ip->i_d.di_nlink; | ||
| 778 | inode->i_uid = ip->i_d.di_uid; | ||
| 779 | inode->i_gid = ip->i_d.di_gid; | ||
| 780 | |||
| 781 | switch (inode->i_mode & S_IFMT) { | ||
| 782 | case S_IFBLK: | ||
| 783 | case S_IFCHR: | ||
| 784 | inode->i_rdev = | ||
| 785 | MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, | ||
| 786 | sysv_minor(ip->i_df.if_u2.if_rdev)); | ||
| 787 | break; | ||
| 788 | default: | ||
| 789 | inode->i_rdev = 0; | ||
| 790 | break; | ||
| 791 | } | ||
| 792 | |||
| 793 | inode->i_generation = ip->i_d.di_gen; | ||
| 794 | i_size_write(inode, ip->i_d.di_size); | ||
| 795 | inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; | ||
| 796 | inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; | ||
| 797 | inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; | ||
| 798 | inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; | ||
| 799 | inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; | ||
| 800 | inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; | ||
| 801 | xfs_diflags_to_iflags(inode, ip); | ||
| 802 | xfs_iflags_clear(ip, XFS_IMODIFIED); | ||
| 803 | |||
| 804 | switch (inode->i_mode & S_IFMT) { | ||
| 805 | case S_IFREG: | ||
| 806 | inode->i_op = &xfs_inode_operations; | ||
| 807 | inode->i_fop = &xfs_file_operations; | ||
| 808 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
| 809 | break; | ||
| 810 | case S_IFDIR: | ||
| 811 | if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) | ||
| 812 | inode->i_op = &xfs_dir_ci_inode_operations; | ||
| 813 | else | ||
| 814 | inode->i_op = &xfs_dir_inode_operations; | ||
| 815 | inode->i_fop = &xfs_dir_file_operations; | ||
| 816 | break; | ||
| 817 | case S_IFLNK: | ||
| 818 | inode->i_op = &xfs_symlink_inode_operations; | ||
| 819 | if (!(ip->i_df.if_flags & XFS_IFINLINE)) | ||
| 820 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
| 821 | break; | ||
| 822 | default: | ||
| 823 | inode->i_op = &xfs_inode_operations; | ||
| 824 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | ||
| 825 | break; | ||
| 826 | } | ||
| 827 | |||
| 828 | xfs_iflags_clear(ip, XFS_INEW); | ||
| 829 | barrier(); | ||
| 830 | |||
| 831 | unlock_new_inode(inode); | ||
| 832 | } | ||
diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h index 14d0deb7afff..8b1a1e31dc21 100644 --- a/fs/xfs/linux-2.6/xfs_iops.h +++ b/fs/xfs/linux-2.6/xfs_iops.h | |||
| @@ -18,23 +18,14 @@ | |||
| 18 | #ifndef __XFS_IOPS_H__ | 18 | #ifndef __XFS_IOPS_H__ |
| 19 | #define __XFS_IOPS_H__ | 19 | #define __XFS_IOPS_H__ |
| 20 | 20 | ||
| 21 | extern const struct inode_operations xfs_inode_operations; | 21 | struct xfs_inode; |
| 22 | extern const struct inode_operations xfs_dir_inode_operations; | ||
| 23 | extern const struct inode_operations xfs_symlink_inode_operations; | ||
| 24 | 22 | ||
| 25 | extern const struct file_operations xfs_file_operations; | 23 | extern const struct file_operations xfs_file_operations; |
| 26 | extern const struct file_operations xfs_dir_file_operations; | 24 | extern const struct file_operations xfs_dir_file_operations; |
| 27 | extern const struct file_operations xfs_invis_file_operations; | 25 | extern const struct file_operations xfs_invis_file_operations; |
| 28 | 26 | ||
| 27 | extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size); | ||
| 29 | 28 | ||
| 30 | struct xfs_inode; | 29 | extern void xfs_setup_inode(struct xfs_inode *); |
| 31 | extern void xfs_ichgtime(struct xfs_inode *, int); | ||
| 32 | extern void xfs_ichgtime_fast(struct xfs_inode *, struct inode *, int); | ||
| 33 | |||
| 34 | #define xfs_vtoi(vp) \ | ||
| 35 | ((struct xfs_inode *)vn_to_inode(vp)->i_private) | ||
| 36 | |||
| 37 | #define XFS_I(inode) \ | ||
| 38 | ((struct xfs_inode *)(inode)->i_private) | ||
| 39 | 30 | ||
| 40 | #endif /* __XFS_IOPS_H__ */ | 31 | #endif /* __XFS_IOPS_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 4edc46915b57..cc0f7b3a9795 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h | |||
| @@ -45,13 +45,13 @@ | |||
| 45 | #include <mrlock.h> | 45 | #include <mrlock.h> |
| 46 | #include <sv.h> | 46 | #include <sv.h> |
| 47 | #include <mutex.h> | 47 | #include <mutex.h> |
| 48 | #include <sema.h> | ||
| 49 | #include <time.h> | 48 | #include <time.h> |
| 50 | 49 | ||
| 51 | #include <support/ktrace.h> | 50 | #include <support/ktrace.h> |
| 52 | #include <support/debug.h> | 51 | #include <support/debug.h> |
| 53 | #include <support/uuid.h> | 52 | #include <support/uuid.h> |
| 54 | 53 | ||
| 54 | #include <linux/semaphore.h> | ||
| 55 | #include <linux/mm.h> | 55 | #include <linux/mm.h> |
| 56 | #include <linux/kernel.h> | 56 | #include <linux/kernel.h> |
| 57 | #include <linux/blkdev.h> | 57 | #include <linux/blkdev.h> |
| @@ -76,6 +76,7 @@ | |||
| 76 | #include <linux/log2.h> | 76 | #include <linux/log2.h> |
| 77 | #include <linux/spinlock.h> | 77 | #include <linux/spinlock.h> |
| 78 | #include <linux/random.h> | 78 | #include <linux/random.h> |
| 79 | #include <linux/ctype.h> | ||
| 79 | 80 | ||
| 80 | #include <asm/page.h> | 81 | #include <asm/page.h> |
| 81 | #include <asm/div64.h> | 82 | #include <asm/div64.h> |
| @@ -125,8 +126,6 @@ | |||
| 125 | 126 | ||
| 126 | #define current_cpu() (raw_smp_processor_id()) | 127 | #define current_cpu() (raw_smp_processor_id()) |
| 127 | #define current_pid() (current->pid) | 128 | #define current_pid() (current->pid) |
| 128 | #define current_fsuid(cred) (current->fsuid) | ||
| 129 | #define current_fsgid(cred) (current->fsgid) | ||
| 130 | #define current_test_flags(f) (current->flags & (f)) | 129 | #define current_test_flags(f) (current->flags & (f)) |
| 131 | #define current_set_flags_nested(sp, f) \ | 130 | #define current_set_flags_nested(sp, f) \ |
| 132 | (*(sp) = current->flags, current->flags |= (f)) | 131 | (*(sp) = current->flags, current->flags |= (f)) |
| @@ -179,7 +178,7 @@ | |||
| 179 | #define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) | 178 | #define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) |
| 180 | #define xfs_stack_trace() dump_stack() | 179 | #define xfs_stack_trace() dump_stack() |
| 181 | #define xfs_itruncate_data(ip, off) \ | 180 | #define xfs_itruncate_data(ip, off) \ |
| 182 | (-vmtruncate(vn_to_inode(XFS_ITOV(ip)), (off))) | 181 | (-vmtruncate(VFS_I(ip), (off))) |
| 183 | 182 | ||
| 184 | 183 | ||
| 185 | /* Move the kernel do_div definition off to one side */ | 184 | /* Move the kernel do_div definition off to one side */ |
| @@ -299,4 +298,11 @@ static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y) | |||
| 299 | return x; | 298 | return x; |
| 300 | } | 299 | } |
| 301 | 300 | ||
| 301 | /* ARM old ABI has some weird alignment/padding */ | ||
| 302 | #if defined(__arm__) && !defined(__ARM_EABI__) | ||
| 303 | #define __arch_pack __attribute__((packed)) | ||
| 304 | #else | ||
| 305 | #define __arch_pack | ||
| 306 | #endif | ||
| 307 | |||
| 302 | #endif /* __XFS_LINUX__ */ | 308 | #endif /* __XFS_LINUX__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 5e3b57516ec7..1957e5357d04 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
| @@ -137,7 +137,7 @@ xfs_iozero( | |||
| 137 | struct address_space *mapping; | 137 | struct address_space *mapping; |
| 138 | int status; | 138 | int status; |
| 139 | 139 | ||
| 140 | mapping = ip->i_vnode->i_mapping; | 140 | mapping = VFS_I(ip)->i_mapping; |
| 141 | do { | 141 | do { |
| 142 | unsigned offset, bytes; | 142 | unsigned offset, bytes; |
| 143 | void *fsdata; | 143 | void *fsdata; |
| @@ -674,9 +674,7 @@ start: | |||
| 674 | */ | 674 | */ |
| 675 | if (likely(!(ioflags & IO_INVIS) && | 675 | if (likely(!(ioflags & IO_INVIS) && |
| 676 | !mnt_want_write(file->f_path.mnt))) { | 676 | !mnt_want_write(file->f_path.mnt))) { |
| 677 | file_update_time(file); | 677 | xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 678 | xfs_ichgtime_fast(xip, inode, | ||
| 679 | XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
| 680 | mnt_drop_write(file->f_path.mnt); | 678 | mnt_drop_write(file->f_path.mnt); |
| 681 | } | 679 | } |
| 682 | 680 | ||
| @@ -711,7 +709,7 @@ start: | |||
| 711 | !capable(CAP_FSETID)) { | 709 | !capable(CAP_FSETID)) { |
| 712 | error = xfs_write_clear_setuid(xip); | 710 | error = xfs_write_clear_setuid(xip); |
| 713 | if (likely(!error)) | 711 | if (likely(!error)) |
| 714 | error = -remove_suid(file->f_path.dentry); | 712 | error = -file_remove_suid(file); |
| 715 | if (unlikely(error)) { | 713 | if (unlikely(error)) { |
| 716 | goto out_unlock_internal; | 714 | goto out_unlock_internal; |
| 717 | } | 715 | } |
diff --git a/fs/xfs/linux-2.6/xfs_stats.c b/fs/xfs/linux-2.6/xfs_stats.c index e480b6102051..3d5b67c075c7 100644 --- a/fs/xfs/linux-2.6/xfs_stats.c +++ b/fs/xfs/linux-2.6/xfs_stats.c | |||
| @@ -98,12 +98,21 @@ xfs_read_xfsstats( | |||
| 98 | return len; | 98 | return len; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void | 101 | int |
| 102 | xfs_init_procfs(void) | 102 | xfs_init_procfs(void) |
| 103 | { | 103 | { |
| 104 | if (!proc_mkdir("fs/xfs", NULL)) | 104 | if (!proc_mkdir("fs/xfs", NULL)) |
| 105 | return; | 105 | goto out; |
| 106 | create_proc_read_entry("fs/xfs/stat", 0, NULL, xfs_read_xfsstats, NULL); | 106 | |
| 107 | if (!create_proc_read_entry("fs/xfs/stat", 0, NULL, | ||
| 108 | xfs_read_xfsstats, NULL)) | ||
| 109 | goto out_remove_entry; | ||
| 110 | return 0; | ||
| 111 | |||
| 112 | out_remove_entry: | ||
| 113 | remove_proc_entry("fs/xfs", NULL); | ||
| 114 | out: | ||
| 115 | return -ENOMEM; | ||
| 107 | } | 116 | } |
| 108 | 117 | ||
| 109 | void | 118 | void |
diff --git a/fs/xfs/linux-2.6/xfs_stats.h b/fs/xfs/linux-2.6/xfs_stats.h index afd0b0d5fdb2..e83820febc9f 100644 --- a/fs/xfs/linux-2.6/xfs_stats.h +++ b/fs/xfs/linux-2.6/xfs_stats.h | |||
| @@ -134,7 +134,7 @@ DECLARE_PER_CPU(struct xfsstats, xfsstats); | |||
| 134 | #define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--) | 134 | #define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--) |
| 135 | #define XFS_STATS_ADD(v, inc) (per_cpu(xfsstats, current_cpu()).v += (inc)) | 135 | #define XFS_STATS_ADD(v, inc) (per_cpu(xfsstats, current_cpu()).v += (inc)) |
| 136 | 136 | ||
| 137 | extern void xfs_init_procfs(void); | 137 | extern int xfs_init_procfs(void); |
| 138 | extern void xfs_cleanup_procfs(void); | 138 | extern void xfs_cleanup_procfs(void); |
| 139 | 139 | ||
| 140 | 140 | ||
| @@ -144,8 +144,14 @@ extern void xfs_cleanup_procfs(void); | |||
| 144 | # define XFS_STATS_DEC(count) | 144 | # define XFS_STATS_DEC(count) |
| 145 | # define XFS_STATS_ADD(count, inc) | 145 | # define XFS_STATS_ADD(count, inc) |
| 146 | 146 | ||
| 147 | static inline void xfs_init_procfs(void) { }; | 147 | static inline int xfs_init_procfs(void) |
| 148 | static inline void xfs_cleanup_procfs(void) { }; | 148 | { |
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | static inline void xfs_cleanup_procfs(void) | ||
| 153 | { | ||
| 154 | } | ||
| 149 | 155 | ||
| 150 | #endif /* !CONFIG_PROC_FS */ | 156 | #endif /* !CONFIG_PROC_FS */ |
| 151 | 157 | ||
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 742b2c7852c1..18d3c8487835 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -52,6 +52,12 @@ | |||
| 52 | #include "xfs_version.h" | 52 | #include "xfs_version.h" |
| 53 | #include "xfs_log_priv.h" | 53 | #include "xfs_log_priv.h" |
| 54 | #include "xfs_trans_priv.h" | 54 | #include "xfs_trans_priv.h" |
| 55 | #include "xfs_filestream.h" | ||
| 56 | #include "xfs_da_btree.h" | ||
| 57 | #include "xfs_dir2_trace.h" | ||
| 58 | #include "xfs_extfree_item.h" | ||
| 59 | #include "xfs_mru_cache.h" | ||
| 60 | #include "xfs_inode_item.h" | ||
| 55 | 61 | ||
| 56 | #include <linux/namei.h> | 62 | #include <linux/namei.h> |
| 57 | #include <linux/init.h> | 63 | #include <linux/init.h> |
| @@ -60,6 +66,7 @@ | |||
| 60 | #include <linux/writeback.h> | 66 | #include <linux/writeback.h> |
| 61 | #include <linux/kthread.h> | 67 | #include <linux/kthread.h> |
| 62 | #include <linux/freezer.h> | 68 | #include <linux/freezer.h> |
| 69 | #include <linux/parser.h> | ||
| 63 | 70 | ||
| 64 | static struct quotactl_ops xfs_quotactl_operations; | 71 | static struct quotactl_ops xfs_quotactl_operations; |
| 65 | static struct super_operations xfs_super_operations; | 72 | static struct super_operations xfs_super_operations; |
| @@ -74,7 +81,10 @@ xfs_args_allocate( | |||
| 74 | { | 81 | { |
| 75 | struct xfs_mount_args *args; | 82 | struct xfs_mount_args *args; |
| 76 | 83 | ||
| 77 | args = kmem_zalloc(sizeof(struct xfs_mount_args), KM_SLEEP); | 84 | args = kzalloc(sizeof(struct xfs_mount_args), GFP_KERNEL); |
| 85 | if (!args) | ||
| 86 | return NULL; | ||
| 87 | |||
| 78 | args->logbufs = args->logbufsize = -1; | 88 | args->logbufs = args->logbufsize = -1; |
| 79 | strncpy(args->fsname, sb->s_id, MAXNAMELEN); | 89 | strncpy(args->fsname, sb->s_id, MAXNAMELEN); |
| 80 | 90 | ||
| @@ -138,6 +148,23 @@ xfs_args_allocate( | |||
| 138 | #define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ | 148 | #define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ |
| 139 | #define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ | 149 | #define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ |
| 140 | 150 | ||
| 151 | /* | ||
| 152 | * Table driven mount option parser. | ||
| 153 | * | ||
| 154 | * Currently only used for remount, but it will be used for mount | ||
| 155 | * in the future, too. | ||
| 156 | */ | ||
| 157 | enum { | ||
| 158 | Opt_barrier, Opt_nobarrier, Opt_err | ||
| 159 | }; | ||
| 160 | |||
| 161 | static match_table_t tokens = { | ||
| 162 | {Opt_barrier, "barrier"}, | ||
| 163 | {Opt_nobarrier, "nobarrier"}, | ||
| 164 | {Opt_err, NULL} | ||
| 165 | }; | ||
| 166 | |||
| 167 | |||
| 141 | STATIC unsigned long | 168 | STATIC unsigned long |
| 142 | suffix_strtoul(char *s, char **endp, unsigned int base) | 169 | suffix_strtoul(char *s, char **endp, unsigned int base) |
| 143 | { | 170 | { |
| @@ -314,6 +341,7 @@ xfs_parseargs( | |||
| 314 | args->flags |= XFSMNT_ATTR2; | 341 | args->flags |= XFSMNT_ATTR2; |
| 315 | } else if (!strcmp(this_char, MNTOPT_NOATTR2)) { | 342 | } else if (!strcmp(this_char, MNTOPT_NOATTR2)) { |
| 316 | args->flags &= ~XFSMNT_ATTR2; | 343 | args->flags &= ~XFSMNT_ATTR2; |
| 344 | args->flags |= XFSMNT_NOATTR2; | ||
| 317 | } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) { | 345 | } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) { |
| 318 | args->flags2 |= XFSMNT2_FILESTREAMS; | 346 | args->flags2 |= XFSMNT2_FILESTREAMS; |
| 319 | } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) { | 347 | } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) { |
| @@ -553,115 +581,6 @@ xfs_max_file_offset( | |||
| 553 | return (((__uint64_t)pagefactor) << bitshift) - 1; | 581 | return (((__uint64_t)pagefactor) << bitshift) - 1; |
| 554 | } | 582 | } |
| 555 | 583 | ||
| 556 | STATIC_INLINE void | ||
| 557 | xfs_set_inodeops( | ||
| 558 | struct inode *inode) | ||
| 559 | { | ||
| 560 | switch (inode->i_mode & S_IFMT) { | ||
| 561 | case S_IFREG: | ||
| 562 | inode->i_op = &xfs_inode_operations; | ||
| 563 | inode->i_fop = &xfs_file_operations; | ||
| 564 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
| 565 | break; | ||
| 566 | case S_IFDIR: | ||
| 567 | inode->i_op = &xfs_dir_inode_operations; | ||
| 568 | inode->i_fop = &xfs_dir_file_operations; | ||
| 569 | break; | ||
| 570 | case S_IFLNK: | ||
| 571 | inode->i_op = &xfs_symlink_inode_operations; | ||
| 572 | if (!(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE)) | ||
| 573 | inode->i_mapping->a_ops = &xfs_address_space_operations; | ||
| 574 | break; | ||
| 575 | default: | ||
| 576 | inode->i_op = &xfs_inode_operations; | ||
| 577 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | ||
| 578 | break; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | STATIC_INLINE void | ||
| 583 | xfs_revalidate_inode( | ||
| 584 | xfs_mount_t *mp, | ||
| 585 | bhv_vnode_t *vp, | ||
| 586 | xfs_inode_t *ip) | ||
| 587 | { | ||
| 588 | struct inode *inode = vn_to_inode(vp); | ||
| 589 | |||
| 590 | inode->i_mode = ip->i_d.di_mode; | ||
| 591 | inode->i_nlink = ip->i_d.di_nlink; | ||
| 592 | inode->i_uid = ip->i_d.di_uid; | ||
| 593 | inode->i_gid = ip->i_d.di_gid; | ||
| 594 | |||
| 595 | switch (inode->i_mode & S_IFMT) { | ||
| 596 | case S_IFBLK: | ||
| 597 | case S_IFCHR: | ||
| 598 | inode->i_rdev = | ||
| 599 | MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, | ||
| 600 | sysv_minor(ip->i_df.if_u2.if_rdev)); | ||
| 601 | break; | ||
| 602 | default: | ||
| 603 | inode->i_rdev = 0; | ||
| 604 | break; | ||
| 605 | } | ||
| 606 | |||
| 607 | inode->i_generation = ip->i_d.di_gen; | ||
| 608 | i_size_write(inode, ip->i_d.di_size); | ||
| 609 | inode->i_atime.tv_sec = ip->i_d.di_atime.t_sec; | ||
| 610 | inode->i_atime.tv_nsec = ip->i_d.di_atime.t_nsec; | ||
| 611 | inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; | ||
| 612 | inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; | ||
| 613 | inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; | ||
| 614 | inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; | ||
| 615 | if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) | ||
| 616 | inode->i_flags |= S_IMMUTABLE; | ||
| 617 | else | ||
| 618 | inode->i_flags &= ~S_IMMUTABLE; | ||
| 619 | if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) | ||
| 620 | inode->i_flags |= S_APPEND; | ||
| 621 | else | ||
| 622 | inode->i_flags &= ~S_APPEND; | ||
| 623 | if (ip->i_d.di_flags & XFS_DIFLAG_SYNC) | ||
| 624 | inode->i_flags |= S_SYNC; | ||
| 625 | else | ||
| 626 | inode->i_flags &= ~S_SYNC; | ||
| 627 | if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME) | ||
| 628 | inode->i_flags |= S_NOATIME; | ||
| 629 | else | ||
| 630 | inode->i_flags &= ~S_NOATIME; | ||
| 631 | xfs_iflags_clear(ip, XFS_IMODIFIED); | ||
| 632 | } | ||
| 633 | |||
| 634 | void | ||
| 635 | xfs_initialize_vnode( | ||
| 636 | struct xfs_mount *mp, | ||
| 637 | bhv_vnode_t *vp, | ||
| 638 | struct xfs_inode *ip) | ||
| 639 | { | ||
| 640 | struct inode *inode = vn_to_inode(vp); | ||
| 641 | |||
| 642 | if (!ip->i_vnode) { | ||
| 643 | ip->i_vnode = vp; | ||
| 644 | inode->i_private = ip; | ||
| 645 | } | ||
| 646 | |||
| 647 | /* | ||
| 648 | * We need to set the ops vectors, and unlock the inode, but if | ||
| 649 | * we have been called during the new inode create process, it is | ||
| 650 | * too early to fill in the Linux inode. We will get called a | ||
| 651 | * second time once the inode is properly set up, and then we can | ||
| 652 | * finish our work. | ||
| 653 | */ | ||
| 654 | if (ip->i_d.di_mode != 0 && (inode->i_state & I_NEW)) { | ||
| 655 | xfs_revalidate_inode(mp, vp, ip); | ||
| 656 | xfs_set_inodeops(inode); | ||
| 657 | |||
| 658 | xfs_iflags_clear(ip, XFS_INEW); | ||
| 659 | barrier(); | ||
| 660 | |||
| 661 | unlock_new_inode(inode); | ||
| 662 | } | ||
| 663 | } | ||
| 664 | |||
| 665 | int | 584 | int |
| 666 | xfs_blkdev_get( | 585 | xfs_blkdev_get( |
| 667 | xfs_mount_t *mp, | 586 | xfs_mount_t *mp, |
| @@ -733,14 +652,6 @@ xfs_mountfs_check_barriers(xfs_mount_t *mp) | |||
| 733 | return; | 652 | return; |
| 734 | } | 653 | } |
| 735 | 654 | ||
| 736 | if (mp->m_ddev_targp->bt_bdev->bd_disk->queue->ordered == | ||
| 737 | QUEUE_ORDERED_NONE) { | ||
| 738 | xfs_fs_cmn_err(CE_NOTE, mp, | ||
| 739 | "Disabling barriers, not supported by the underlying device"); | ||
| 740 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | ||
| 741 | return; | ||
| 742 | } | ||
| 743 | |||
| 744 | if (xfs_readonly_buftarg(mp->m_ddev_targp)) { | 655 | if (xfs_readonly_buftarg(mp->m_ddev_targp)) { |
| 745 | xfs_fs_cmn_err(CE_NOTE, mp, | 656 | xfs_fs_cmn_err(CE_NOTE, mp, |
| 746 | "Disabling barriers, underlying device is readonly"); | 657 | "Disabling barriers, underlying device is readonly"); |
| @@ -764,6 +675,139 @@ xfs_blkdev_issue_flush( | |||
| 764 | blkdev_issue_flush(buftarg->bt_bdev, NULL); | 675 | blkdev_issue_flush(buftarg->bt_bdev, NULL); |
| 765 | } | 676 | } |
| 766 | 677 | ||
| 678 | STATIC void | ||
| 679 | xfs_close_devices( | ||
| 680 | struct xfs_mount *mp) | ||
| 681 | { | ||
| 682 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { | ||
| 683 | struct block_device *logdev = mp->m_logdev_targp->bt_bdev; | ||
| 684 | xfs_free_buftarg(mp->m_logdev_targp); | ||
| 685 | xfs_blkdev_put(logdev); | ||
| 686 | } | ||
| 687 | if (mp->m_rtdev_targp) { | ||
| 688 | struct block_device *rtdev = mp->m_rtdev_targp->bt_bdev; | ||
| 689 | xfs_free_buftarg(mp->m_rtdev_targp); | ||
| 690 | xfs_blkdev_put(rtdev); | ||
| 691 | } | ||
| 692 | xfs_free_buftarg(mp->m_ddev_targp); | ||
| 693 | } | ||
| 694 | |||
| 695 | /* | ||
| 696 | * The file system configurations are: | ||
| 697 | * (1) device (partition) with data and internal log | ||
| 698 | * (2) logical volume with data and log subvolumes. | ||
| 699 | * (3) logical volume with data, log, and realtime subvolumes. | ||
| 700 | * | ||
| 701 | * We only have to handle opening the log and realtime volumes here if | ||
| 702 | * they are present. The data subvolume has already been opened by | ||
| 703 | * get_sb_bdev() and is stored in sb->s_bdev. | ||
| 704 | */ | ||
| 705 | STATIC int | ||
| 706 | xfs_open_devices( | ||
| 707 | struct xfs_mount *mp, | ||
| 708 | struct xfs_mount_args *args) | ||
| 709 | { | ||
| 710 | struct block_device *ddev = mp->m_super->s_bdev; | ||
| 711 | struct block_device *logdev = NULL, *rtdev = NULL; | ||
| 712 | int error; | ||
| 713 | |||
| 714 | /* | ||
| 715 | * Open real time and log devices - order is important. | ||
| 716 | */ | ||
| 717 | if (args->logname[0]) { | ||
| 718 | error = xfs_blkdev_get(mp, args->logname, &logdev); | ||
| 719 | if (error) | ||
| 720 | goto out; | ||
| 721 | } | ||
| 722 | |||
| 723 | if (args->rtname[0]) { | ||
| 724 | error = xfs_blkdev_get(mp, args->rtname, &rtdev); | ||
| 725 | if (error) | ||
| 726 | goto out_close_logdev; | ||
| 727 | |||
| 728 | if (rtdev == ddev || rtdev == logdev) { | ||
| 729 | cmn_err(CE_WARN, | ||
| 730 | "XFS: Cannot mount filesystem with identical rtdev and ddev/logdev."); | ||
| 731 | error = EINVAL; | ||
| 732 | goto out_close_rtdev; | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | /* | ||
| 737 | * Setup xfs_mount buffer target pointers | ||
| 738 | */ | ||
| 739 | error = ENOMEM; | ||
| 740 | mp->m_ddev_targp = xfs_alloc_buftarg(ddev, 0); | ||
| 741 | if (!mp->m_ddev_targp) | ||
| 742 | goto out_close_rtdev; | ||
| 743 | |||
| 744 | if (rtdev) { | ||
| 745 | mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1); | ||
| 746 | if (!mp->m_rtdev_targp) | ||
| 747 | goto out_free_ddev_targ; | ||
| 748 | } | ||
| 749 | |||
| 750 | if (logdev && logdev != ddev) { | ||
| 751 | mp->m_logdev_targp = xfs_alloc_buftarg(logdev, 1); | ||
| 752 | if (!mp->m_logdev_targp) | ||
| 753 | goto out_free_rtdev_targ; | ||
| 754 | } else { | ||
| 755 | mp->m_logdev_targp = mp->m_ddev_targp; | ||
| 756 | } | ||
| 757 | |||
| 758 | return 0; | ||
| 759 | |||
| 760 | out_free_rtdev_targ: | ||
| 761 | if (mp->m_rtdev_targp) | ||
| 762 | xfs_free_buftarg(mp->m_rtdev_targp); | ||
| 763 | out_free_ddev_targ: | ||
| 764 | xfs_free_buftarg(mp->m_ddev_targp); | ||
| 765 | out_close_rtdev: | ||
| 766 | if (rtdev) | ||
| 767 | xfs_blkdev_put(rtdev); | ||
| 768 | out_close_logdev: | ||
| 769 | if (logdev && logdev != ddev) | ||
| 770 | xfs_blkdev_put(logdev); | ||
| 771 | out: | ||
| 772 | return error; | ||
| 773 | } | ||
| 774 | |||
| 775 | /* | ||
| 776 | * Setup xfs_mount buffer target pointers based on superblock | ||
| 777 | */ | ||
| 778 | STATIC int | ||
| 779 | xfs_setup_devices( | ||
| 780 | struct xfs_mount *mp) | ||
| 781 | { | ||
| 782 | int error; | ||
| 783 | |||
| 784 | error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize, | ||
| 785 | mp->m_sb.sb_sectsize); | ||
| 786 | if (error) | ||
| 787 | return error; | ||
| 788 | |||
| 789 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { | ||
| 790 | unsigned int log_sector_size = BBSIZE; | ||
| 791 | |||
| 792 | if (xfs_sb_version_hassector(&mp->m_sb)) | ||
| 793 | log_sector_size = mp->m_sb.sb_logsectsize; | ||
| 794 | error = xfs_setsize_buftarg(mp->m_logdev_targp, | ||
| 795 | mp->m_sb.sb_blocksize, | ||
| 796 | log_sector_size); | ||
| 797 | if (error) | ||
| 798 | return error; | ||
| 799 | } | ||
| 800 | if (mp->m_rtdev_targp) { | ||
| 801 | error = xfs_setsize_buftarg(mp->m_rtdev_targp, | ||
| 802 | mp->m_sb.sb_blocksize, | ||
| 803 | mp->m_sb.sb_sectsize); | ||
| 804 | if (error) | ||
| 805 | return error; | ||
| 806 | } | ||
| 807 | |||
| 808 | return 0; | ||
| 809 | } | ||
| 810 | |||
| 767 | /* | 811 | /* |
| 768 | * XFS AIL push thread support | 812 | * XFS AIL push thread support |
| 769 | */ | 813 | */ |
| @@ -826,63 +870,21 @@ STATIC struct inode * | |||
| 826 | xfs_fs_alloc_inode( | 870 | xfs_fs_alloc_inode( |
| 827 | struct super_block *sb) | 871 | struct super_block *sb) |
| 828 | { | 872 | { |
| 829 | bhv_vnode_t *vp; | 873 | return kmem_zone_alloc(xfs_vnode_zone, KM_SLEEP); |
| 830 | |||
| 831 | vp = kmem_zone_alloc(xfs_vnode_zone, KM_SLEEP); | ||
| 832 | if (unlikely(!vp)) | ||
| 833 | return NULL; | ||
| 834 | return vn_to_inode(vp); | ||
| 835 | } | 874 | } |
| 836 | 875 | ||
| 837 | STATIC void | 876 | STATIC void |
| 838 | xfs_fs_destroy_inode( | 877 | xfs_fs_destroy_inode( |
| 839 | struct inode *inode) | 878 | struct inode *inode) |
| 840 | { | 879 | { |
| 841 | kmem_zone_free(xfs_vnode_zone, vn_from_inode(inode)); | 880 | kmem_zone_free(xfs_vnode_zone, inode); |
| 842 | } | 881 | } |
| 843 | 882 | ||
| 844 | STATIC void | 883 | STATIC void |
| 845 | xfs_fs_inode_init_once( | 884 | xfs_fs_inode_init_once( |
| 846 | kmem_zone_t *zonep, | ||
| 847 | void *vnode) | 885 | void *vnode) |
| 848 | { | 886 | { |
| 849 | inode_init_once(vn_to_inode((bhv_vnode_t *)vnode)); | 887 | inode_init_once((struct inode *)vnode); |
| 850 | } | ||
| 851 | |||
| 852 | STATIC int __init | ||
| 853 | xfs_init_zones(void) | ||
| 854 | { | ||
| 855 | xfs_vnode_zone = kmem_zone_init_flags(sizeof(bhv_vnode_t), "xfs_vnode", | ||
| 856 | KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | | ||
| 857 | KM_ZONE_SPREAD, | ||
| 858 | xfs_fs_inode_init_once); | ||
| 859 | if (!xfs_vnode_zone) | ||
| 860 | goto out; | ||
| 861 | |||
| 862 | xfs_ioend_zone = kmem_zone_init(sizeof(xfs_ioend_t), "xfs_ioend"); | ||
| 863 | if (!xfs_ioend_zone) | ||
| 864 | goto out_destroy_vnode_zone; | ||
| 865 | |||
| 866 | xfs_ioend_pool = mempool_create_slab_pool(4 * MAX_BUF_PER_PAGE, | ||
| 867 | xfs_ioend_zone); | ||
| 868 | if (!xfs_ioend_pool) | ||
| 869 | goto out_free_ioend_zone; | ||
| 870 | return 0; | ||
| 871 | |||
| 872 | out_free_ioend_zone: | ||
| 873 | kmem_zone_destroy(xfs_ioend_zone); | ||
| 874 | out_destroy_vnode_zone: | ||
| 875 | kmem_zone_destroy(xfs_vnode_zone); | ||
| 876 | out: | ||
| 877 | return -ENOMEM; | ||
| 878 | } | ||
| 879 | |||
| 880 | STATIC void | ||
| 881 | xfs_destroy_zones(void) | ||
| 882 | { | ||
| 883 | mempool_destroy(xfs_ioend_pool); | ||
| 884 | kmem_zone_destroy(xfs_vnode_zone); | ||
| 885 | kmem_zone_destroy(xfs_ioend_zone); | ||
| 886 | } | 888 | } |
| 887 | 889 | ||
| 888 | /* | 890 | /* |
| @@ -987,7 +989,7 @@ void | |||
| 987 | xfs_flush_inode( | 989 | xfs_flush_inode( |
| 988 | xfs_inode_t *ip) | 990 | xfs_inode_t *ip) |
| 989 | { | 991 | { |
| 990 | struct inode *inode = ip->i_vnode; | 992 | struct inode *inode = VFS_I(ip); |
| 991 | 993 | ||
| 992 | igrab(inode); | 994 | igrab(inode); |
| 993 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inode_work); | 995 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inode_work); |
| @@ -1012,7 +1014,7 @@ void | |||
| 1012 | xfs_flush_device( | 1014 | xfs_flush_device( |
| 1013 | xfs_inode_t *ip) | 1015 | xfs_inode_t *ip) |
| 1014 | { | 1016 | { |
| 1015 | struct inode *inode = vn_to_inode(XFS_ITOV(ip)); | 1017 | struct inode *inode = VFS_I(ip); |
| 1016 | 1018 | ||
| 1017 | igrab(inode); | 1019 | igrab(inode); |
| 1018 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work); | 1020 | xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_device_work); |
| @@ -1074,7 +1076,7 @@ xfssyncd( | |||
| 1074 | list_del(&work->w_list); | 1076 | list_del(&work->w_list); |
| 1075 | if (work == &mp->m_sync_work) | 1077 | if (work == &mp->m_sync_work) |
| 1076 | continue; | 1078 | continue; |
| 1077 | kmem_free(work, sizeof(struct bhv_vfs_sync_work)); | 1079 | kmem_free(work); |
| 1078 | } | 1080 | } |
| 1079 | } | 1081 | } |
| 1080 | 1082 | ||
| @@ -1082,18 +1084,76 @@ xfssyncd( | |||
| 1082 | } | 1084 | } |
| 1083 | 1085 | ||
| 1084 | STATIC void | 1086 | STATIC void |
| 1087 | xfs_free_fsname( | ||
| 1088 | struct xfs_mount *mp) | ||
| 1089 | { | ||
| 1090 | kfree(mp->m_fsname); | ||
| 1091 | kfree(mp->m_rtname); | ||
| 1092 | kfree(mp->m_logname); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | STATIC void | ||
| 1085 | xfs_fs_put_super( | 1096 | xfs_fs_put_super( |
| 1086 | struct super_block *sb) | 1097 | struct super_block *sb) |
| 1087 | { | 1098 | { |
| 1088 | struct xfs_mount *mp = XFS_M(sb); | 1099 | struct xfs_mount *mp = XFS_M(sb); |
| 1100 | struct xfs_inode *rip = mp->m_rootip; | ||
| 1101 | int unmount_event_flags = 0; | ||
| 1089 | int error; | 1102 | int error; |
| 1090 | 1103 | ||
| 1091 | kthread_stop(mp->m_sync_task); | 1104 | kthread_stop(mp->m_sync_task); |
| 1092 | 1105 | ||
| 1093 | xfs_sync(mp, SYNC_ATTR | SYNC_DELWRI); | 1106 | xfs_sync(mp, SYNC_ATTR | SYNC_DELWRI); |
| 1094 | error = xfs_unmount(mp, 0, NULL); | 1107 | |
| 1095 | if (error) | 1108 | #ifdef HAVE_DMAPI |
| 1096 | printk("XFS: unmount got error=%d\n", error); | 1109 | if (mp->m_flags & XFS_MOUNT_DMAPI) { |
| 1110 | unmount_event_flags = | ||
| 1111 | (mp->m_dmevmask & (1 << DM_EVENT_UNMOUNT)) ? | ||
| 1112 | 0 : DM_FLAGS_UNWANTED; | ||
| 1113 | /* | ||
| 1114 | * Ignore error from dmapi here, first unmount is not allowed | ||
| 1115 | * to fail anyway, and second we wouldn't want to fail a | ||
| 1116 | * unmount because of dmapi. | ||
| 1117 | */ | ||
| 1118 | XFS_SEND_PREUNMOUNT(mp, rip, DM_RIGHT_NULL, rip, DM_RIGHT_NULL, | ||
| 1119 | NULL, NULL, 0, 0, unmount_event_flags); | ||
| 1120 | } | ||
| 1121 | #endif | ||
| 1122 | |||
| 1123 | /* | ||
| 1124 | * Blow away any referenced inode in the filestreams cache. | ||
| 1125 | * This can and will cause log traffic as inodes go inactive | ||
| 1126 | * here. | ||
| 1127 | */ | ||
| 1128 | xfs_filestream_unmount(mp); | ||
| 1129 | |||
| 1130 | XFS_bflush(mp->m_ddev_targp); | ||
| 1131 | error = xfs_unmount_flush(mp, 0); | ||
| 1132 | WARN_ON(error); | ||
| 1133 | |||
| 1134 | /* | ||
| 1135 | * If we're forcing a shutdown, typically because of a media error, | ||
| 1136 | * we want to make sure we invalidate dirty pages that belong to | ||
| 1137 | * referenced vnodes as well. | ||
| 1138 | */ | ||
| 1139 | if (XFS_FORCED_SHUTDOWN(mp)) { | ||
| 1140 | error = xfs_sync(mp, SYNC_WAIT | SYNC_CLOSE); | ||
| 1141 | ASSERT(error != EFSCORRUPTED); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | if (mp->m_flags & XFS_MOUNT_DMAPI) { | ||
| 1145 | XFS_SEND_UNMOUNT(mp, rip, DM_RIGHT_NULL, 0, 0, | ||
| 1146 | unmount_event_flags); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | xfs_unmountfs(mp); | ||
| 1150 | xfs_freesb(mp); | ||
| 1151 | xfs_icsb_destroy_counters(mp); | ||
| 1152 | xfs_close_devices(mp); | ||
| 1153 | xfs_qmops_put(mp); | ||
| 1154 | xfs_dmops_put(mp); | ||
| 1155 | xfs_free_fsname(mp); | ||
| 1156 | kfree(mp); | ||
| 1097 | } | 1157 | } |
| 1098 | 1158 | ||
| 1099 | STATIC void | 1159 | STATIC void |
| @@ -1216,14 +1276,74 @@ xfs_fs_remount( | |||
| 1216 | char *options) | 1276 | char *options) |
| 1217 | { | 1277 | { |
| 1218 | struct xfs_mount *mp = XFS_M(sb); | 1278 | struct xfs_mount *mp = XFS_M(sb); |
| 1219 | struct xfs_mount_args *args = xfs_args_allocate(sb, 0); | 1279 | substring_t args[MAX_OPT_ARGS]; |
| 1220 | int error; | 1280 | char *p; |
| 1221 | 1281 | ||
| 1222 | error = xfs_parseargs(mp, options, args, 1); | 1282 | while ((p = strsep(&options, ",")) != NULL) { |
| 1223 | if (!error) | 1283 | int token; |
| 1224 | error = xfs_mntupdate(mp, flags, args); | 1284 | |
| 1225 | kmem_free(args, sizeof(*args)); | 1285 | if (!*p) |
| 1226 | return -error; | 1286 | continue; |
| 1287 | |||
| 1288 | token = match_token(p, tokens, args); | ||
| 1289 | switch (token) { | ||
| 1290 | case Opt_barrier: | ||
| 1291 | mp->m_flags |= XFS_MOUNT_BARRIER; | ||
| 1292 | |||
| 1293 | /* | ||
| 1294 | * Test if barriers are actually working if we can, | ||
| 1295 | * else delay this check until the filesystem is | ||
| 1296 | * marked writeable. | ||
| 1297 | */ | ||
| 1298 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) | ||
| 1299 | xfs_mountfs_check_barriers(mp); | ||
| 1300 | break; | ||
| 1301 | case Opt_nobarrier: | ||
| 1302 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | ||
| 1303 | break; | ||
| 1304 | default: | ||
| 1305 | /* | ||
| 1306 | * Logically we would return an error here to prevent | ||
| 1307 | * users from believing they might have changed | ||
| 1308 | * mount options using remount which can't be changed. | ||
| 1309 | * | ||
| 1310 | * But unfortunately mount(8) adds all options from | ||
| 1311 | * mtab and fstab to the mount arguments in some cases | ||
| 1312 | * so we can't blindly reject options, but have to | ||
| 1313 | * check for each specified option if it actually | ||
| 1314 | * differs from the currently set option and only | ||
| 1315 | * reject it if that's the case. | ||
| 1316 | * | ||
| 1317 | * Until that is implemented we return success for | ||
| 1318 | * every remount request, and silently ignore all | ||
| 1319 | * options that we can't actually change. | ||
| 1320 | */ | ||
| 1321 | #if 0 | ||
| 1322 | printk(KERN_INFO | ||
| 1323 | "XFS: mount option \"%s\" not supported for remount\n", p); | ||
| 1324 | return -EINVAL; | ||
| 1325 | #else | ||
| 1326 | return 0; | ||
| 1327 | #endif | ||
| 1328 | } | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | /* rw/ro -> rw */ | ||
| 1332 | if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) { | ||
| 1333 | mp->m_flags &= ~XFS_MOUNT_RDONLY; | ||
| 1334 | if (mp->m_flags & XFS_MOUNT_BARRIER) | ||
| 1335 | xfs_mountfs_check_barriers(mp); | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | /* rw -> ro */ | ||
| 1339 | if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { | ||
| 1340 | xfs_filestream_flush(mp); | ||
| 1341 | xfs_sync(mp, SYNC_DATA_QUIESCE); | ||
| 1342 | xfs_attr_quiesce(mp); | ||
| 1343 | mp->m_flags |= XFS_MOUNT_RDONLY; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | return 0; | ||
| 1227 | } | 1347 | } |
| 1228 | 1348 | ||
| 1229 | /* | 1349 | /* |
| @@ -1300,6 +1420,245 @@ xfs_fs_setxquota( | |||
| 1300 | Q_XSETPQLIM), id, (caddr_t)fdq); | 1420 | Q_XSETPQLIM), id, (caddr_t)fdq); |
| 1301 | } | 1421 | } |
| 1302 | 1422 | ||
| 1423 | /* | ||
| 1424 | * This function fills in xfs_mount_t fields based on mount args. | ||
| 1425 | * Note: the superblock has _not_ yet been read in. | ||
| 1426 | */ | ||
| 1427 | STATIC int | ||
| 1428 | xfs_start_flags( | ||
| 1429 | struct xfs_mount_args *ap, | ||
| 1430 | struct xfs_mount *mp) | ||
| 1431 | { | ||
| 1432 | int error; | ||
| 1433 | |||
| 1434 | /* Values are in BBs */ | ||
| 1435 | if ((ap->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { | ||
| 1436 | /* | ||
| 1437 | * At this point the superblock has not been read | ||
| 1438 | * in, therefore we do not know the block size. | ||
| 1439 | * Before the mount call ends we will convert | ||
| 1440 | * these to FSBs. | ||
| 1441 | */ | ||
| 1442 | mp->m_dalign = ap->sunit; | ||
| 1443 | mp->m_swidth = ap->swidth; | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | if (ap->logbufs != -1 && | ||
| 1447 | ap->logbufs != 0 && | ||
| 1448 | (ap->logbufs < XLOG_MIN_ICLOGS || | ||
| 1449 | ap->logbufs > XLOG_MAX_ICLOGS)) { | ||
| 1450 | cmn_err(CE_WARN, | ||
| 1451 | "XFS: invalid logbufs value: %d [not %d-%d]", | ||
| 1452 | ap->logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); | ||
| 1453 | return XFS_ERROR(EINVAL); | ||
| 1454 | } | ||
| 1455 | mp->m_logbufs = ap->logbufs; | ||
| 1456 | if (ap->logbufsize != -1 && | ||
| 1457 | ap->logbufsize != 0 && | ||
| 1458 | (ap->logbufsize < XLOG_MIN_RECORD_BSIZE || | ||
| 1459 | ap->logbufsize > XLOG_MAX_RECORD_BSIZE || | ||
| 1460 | !is_power_of_2(ap->logbufsize))) { | ||
| 1461 | cmn_err(CE_WARN, | ||
| 1462 | "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", | ||
| 1463 | ap->logbufsize); | ||
| 1464 | return XFS_ERROR(EINVAL); | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | error = ENOMEM; | ||
| 1468 | |||
| 1469 | mp->m_logbsize = ap->logbufsize; | ||
| 1470 | mp->m_fsname_len = strlen(ap->fsname) + 1; | ||
| 1471 | |||
| 1472 | mp->m_fsname = kstrdup(ap->fsname, GFP_KERNEL); | ||
| 1473 | if (!mp->m_fsname) | ||
| 1474 | goto out; | ||
| 1475 | |||
| 1476 | if (ap->rtname[0]) { | ||
| 1477 | mp->m_rtname = kstrdup(ap->rtname, GFP_KERNEL); | ||
| 1478 | if (!mp->m_rtname) | ||
| 1479 | goto out_free_fsname; | ||
| 1480 | |||
| 1481 | } | ||
| 1482 | |||
| 1483 | if (ap->logname[0]) { | ||
| 1484 | mp->m_logname = kstrdup(ap->logname, GFP_KERNEL); | ||
| 1485 | if (!mp->m_logname) | ||
| 1486 | goto out_free_rtname; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | if (ap->flags & XFSMNT_WSYNC) | ||
| 1490 | mp->m_flags |= XFS_MOUNT_WSYNC; | ||
| 1491 | #if XFS_BIG_INUMS | ||
| 1492 | if (ap->flags & XFSMNT_INO64) { | ||
| 1493 | mp->m_flags |= XFS_MOUNT_INO64; | ||
| 1494 | mp->m_inoadd = XFS_INO64_OFFSET; | ||
| 1495 | } | ||
| 1496 | #endif | ||
| 1497 | if (ap->flags & XFSMNT_RETERR) | ||
| 1498 | mp->m_flags |= XFS_MOUNT_RETERR; | ||
| 1499 | if (ap->flags & XFSMNT_NOALIGN) | ||
| 1500 | mp->m_flags |= XFS_MOUNT_NOALIGN; | ||
| 1501 | if (ap->flags & XFSMNT_SWALLOC) | ||
| 1502 | mp->m_flags |= XFS_MOUNT_SWALLOC; | ||
| 1503 | if (ap->flags & XFSMNT_OSYNCISOSYNC) | ||
| 1504 | mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC; | ||
| 1505 | if (ap->flags & XFSMNT_32BITINODES) | ||
| 1506 | mp->m_flags |= XFS_MOUNT_32BITINODES; | ||
| 1507 | |||
| 1508 | if (ap->flags & XFSMNT_IOSIZE) { | ||
| 1509 | if (ap->iosizelog > XFS_MAX_IO_LOG || | ||
| 1510 | ap->iosizelog < XFS_MIN_IO_LOG) { | ||
| 1511 | cmn_err(CE_WARN, | ||
| 1512 | "XFS: invalid log iosize: %d [not %d-%d]", | ||
| 1513 | ap->iosizelog, XFS_MIN_IO_LOG, | ||
| 1514 | XFS_MAX_IO_LOG); | ||
| 1515 | return XFS_ERROR(EINVAL); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; | ||
| 1519 | mp->m_readio_log = mp->m_writeio_log = ap->iosizelog; | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | if (ap->flags & XFSMNT_IKEEP) | ||
| 1523 | mp->m_flags |= XFS_MOUNT_IKEEP; | ||
| 1524 | if (ap->flags & XFSMNT_DIRSYNC) | ||
| 1525 | mp->m_flags |= XFS_MOUNT_DIRSYNC; | ||
| 1526 | if (ap->flags & XFSMNT_ATTR2) | ||
| 1527 | mp->m_flags |= XFS_MOUNT_ATTR2; | ||
| 1528 | if (ap->flags & XFSMNT_NOATTR2) | ||
| 1529 | mp->m_flags |= XFS_MOUNT_NOATTR2; | ||
| 1530 | |||
| 1531 | if (ap->flags2 & XFSMNT2_COMPAT_IOSIZE) | ||
| 1532 | mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; | ||
| 1533 | |||
| 1534 | /* | ||
| 1535 | * no recovery flag requires a read-only mount | ||
| 1536 | */ | ||
| 1537 | if (ap->flags & XFSMNT_NORECOVERY) { | ||
| 1538 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { | ||
| 1539 | cmn_err(CE_WARN, | ||
| 1540 | "XFS: tried to mount a FS read-write without recovery!"); | ||
| 1541 | return XFS_ERROR(EINVAL); | ||
| 1542 | } | ||
| 1543 | mp->m_flags |= XFS_MOUNT_NORECOVERY; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | if (ap->flags & XFSMNT_NOUUID) | ||
| 1547 | mp->m_flags |= XFS_MOUNT_NOUUID; | ||
| 1548 | if (ap->flags & XFSMNT_BARRIER) | ||
| 1549 | mp->m_flags |= XFS_MOUNT_BARRIER; | ||
| 1550 | else | ||
| 1551 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | ||
| 1552 | |||
| 1553 | if (ap->flags2 & XFSMNT2_FILESTREAMS) | ||
| 1554 | mp->m_flags |= XFS_MOUNT_FILESTREAMS; | ||
| 1555 | |||
| 1556 | if (ap->flags & XFSMNT_DMAPI) | ||
| 1557 | mp->m_flags |= XFS_MOUNT_DMAPI; | ||
| 1558 | return 0; | ||
| 1559 | |||
| 1560 | |||
| 1561 | out_free_rtname: | ||
| 1562 | kfree(mp->m_rtname); | ||
| 1563 | out_free_fsname: | ||
| 1564 | kfree(mp->m_fsname); | ||
| 1565 | out: | ||
| 1566 | return error; | ||
| 1567 | } | ||
| 1568 | |||
| 1569 | /* | ||
| 1570 | * This function fills in xfs_mount_t fields based on mount args. | ||
| 1571 | * Note: the superblock _has_ now been read in. | ||
| 1572 | */ | ||
| 1573 | STATIC int | ||
| 1574 | xfs_finish_flags( | ||
| 1575 | struct xfs_mount_args *ap, | ||
| 1576 | struct xfs_mount *mp) | ||
| 1577 | { | ||
| 1578 | int ronly = (mp->m_flags & XFS_MOUNT_RDONLY); | ||
| 1579 | |||
| 1580 | /* Fail a mount where the logbuf is smaller then the log stripe */ | ||
| 1581 | if (xfs_sb_version_haslogv2(&mp->m_sb)) { | ||
| 1582 | if ((ap->logbufsize <= 0) && | ||
| 1583 | (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)) { | ||
| 1584 | mp->m_logbsize = mp->m_sb.sb_logsunit; | ||
| 1585 | } else if (ap->logbufsize > 0 && | ||
| 1586 | ap->logbufsize < mp->m_sb.sb_logsunit) { | ||
| 1587 | cmn_err(CE_WARN, | ||
| 1588 | "XFS: logbuf size must be greater than or equal to log stripe size"); | ||
| 1589 | return XFS_ERROR(EINVAL); | ||
| 1590 | } | ||
| 1591 | } else { | ||
| 1592 | /* Fail a mount if the logbuf is larger than 32K */ | ||
| 1593 | if (ap->logbufsize > XLOG_BIG_RECORD_BSIZE) { | ||
| 1594 | cmn_err(CE_WARN, | ||
| 1595 | "XFS: logbuf size for version 1 logs must be 16K or 32K"); | ||
| 1596 | return XFS_ERROR(EINVAL); | ||
| 1597 | } | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | /* | ||
| 1601 | * mkfs'ed attr2 will turn on attr2 mount unless explicitly | ||
| 1602 | * told by noattr2 to turn it off | ||
| 1603 | */ | ||
| 1604 | if (xfs_sb_version_hasattr2(&mp->m_sb) && | ||
| 1605 | !(ap->flags & XFSMNT_NOATTR2)) | ||
| 1606 | mp->m_flags |= XFS_MOUNT_ATTR2; | ||
| 1607 | |||
| 1608 | /* | ||
| 1609 | * prohibit r/w mounts of read-only filesystems | ||
| 1610 | */ | ||
| 1611 | if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !ronly) { | ||
| 1612 | cmn_err(CE_WARN, | ||
| 1613 | "XFS: cannot mount a read-only filesystem as read-write"); | ||
| 1614 | return XFS_ERROR(EROFS); | ||
| 1615 | } | ||
| 1616 | |||
| 1617 | /* | ||
| 1618 | * check for shared mount. | ||
| 1619 | */ | ||
| 1620 | if (ap->flags & XFSMNT_SHARED) { | ||
| 1621 | if (!xfs_sb_version_hasshared(&mp->m_sb)) | ||
| 1622 | return XFS_ERROR(EINVAL); | ||
| 1623 | |||
| 1624 | /* | ||
| 1625 | * For IRIX 6.5, shared mounts must have the shared | ||
| 1626 | * version bit set, have the persistent readonly | ||
| 1627 | * field set, must be version 0 and can only be mounted | ||
| 1628 | * read-only. | ||
| 1629 | */ | ||
| 1630 | if (!ronly || !(mp->m_sb.sb_flags & XFS_SBF_READONLY) || | ||
| 1631 | (mp->m_sb.sb_shared_vn != 0)) | ||
| 1632 | return XFS_ERROR(EINVAL); | ||
| 1633 | |||
| 1634 | mp->m_flags |= XFS_MOUNT_SHARED; | ||
| 1635 | |||
| 1636 | /* | ||
| 1637 | * Shared XFS V0 can't deal with DMI. Return EINVAL. | ||
| 1638 | */ | ||
| 1639 | if (mp->m_sb.sb_shared_vn == 0 && (ap->flags & XFSMNT_DMAPI)) | ||
| 1640 | return XFS_ERROR(EINVAL); | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | if (ap->flags & XFSMNT_UQUOTA) { | ||
| 1644 | mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); | ||
| 1645 | if (ap->flags & XFSMNT_UQUOTAENF) | ||
| 1646 | mp->m_qflags |= XFS_UQUOTA_ENFD; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | if (ap->flags & XFSMNT_GQUOTA) { | ||
| 1650 | mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); | ||
| 1651 | if (ap->flags & XFSMNT_GQUOTAENF) | ||
| 1652 | mp->m_qflags |= XFS_OQUOTA_ENFD; | ||
| 1653 | } else if (ap->flags & XFSMNT_PQUOTA) { | ||
| 1654 | mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); | ||
| 1655 | if (ap->flags & XFSMNT_PQUOTAENF) | ||
| 1656 | mp->m_qflags |= XFS_OQUOTA_ENFD; | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | return 0; | ||
| 1660 | } | ||
| 1661 | |||
| 1303 | STATIC int | 1662 | STATIC int |
| 1304 | xfs_fs_fill_super( | 1663 | xfs_fs_fill_super( |
| 1305 | struct super_block *sb, | 1664 | struct super_block *sb, |
| @@ -1308,11 +1667,21 @@ xfs_fs_fill_super( | |||
| 1308 | { | 1667 | { |
| 1309 | struct inode *root; | 1668 | struct inode *root; |
| 1310 | struct xfs_mount *mp = NULL; | 1669 | struct xfs_mount *mp = NULL; |
| 1311 | struct xfs_mount_args *args = xfs_args_allocate(sb, silent); | 1670 | struct xfs_mount_args *args; |
| 1312 | int error; | 1671 | int flags = 0, error = ENOMEM; |
| 1313 | 1672 | ||
| 1314 | mp = xfs_mount_init(); | 1673 | args = xfs_args_allocate(sb, silent); |
| 1674 | if (!args) | ||
| 1675 | return -ENOMEM; | ||
| 1315 | 1676 | ||
| 1677 | mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL); | ||
| 1678 | if (!mp) | ||
| 1679 | goto out_free_args; | ||
| 1680 | |||
| 1681 | spin_lock_init(&mp->m_sb_lock); | ||
| 1682 | mutex_init(&mp->m_ilock); | ||
| 1683 | mutex_init(&mp->m_growlock); | ||
| 1684 | atomic_set(&mp->m_active_trans, 0); | ||
| 1316 | INIT_LIST_HEAD(&mp->m_sync_list); | 1685 | INIT_LIST_HEAD(&mp->m_sync_list); |
| 1317 | spin_lock_init(&mp->m_sync_lock); | 1686 | spin_lock_init(&mp->m_sync_lock); |
| 1318 | init_waitqueue_head(&mp->m_wait_single_sync_task); | 1687 | init_waitqueue_head(&mp->m_wait_single_sync_task); |
| @@ -1325,16 +1694,60 @@ xfs_fs_fill_super( | |||
| 1325 | 1694 | ||
| 1326 | error = xfs_parseargs(mp, (char *)data, args, 0); | 1695 | error = xfs_parseargs(mp, (char *)data, args, 0); |
| 1327 | if (error) | 1696 | if (error) |
| 1328 | goto fail_vfsop; | 1697 | goto out_free_mp; |
| 1329 | 1698 | ||
| 1330 | sb_min_blocksize(sb, BBSIZE); | 1699 | sb_min_blocksize(sb, BBSIZE); |
| 1700 | sb->s_xattr = xfs_xattr_handlers; | ||
| 1331 | sb->s_export_op = &xfs_export_operations; | 1701 | sb->s_export_op = &xfs_export_operations; |
| 1332 | sb->s_qcop = &xfs_quotactl_operations; | 1702 | sb->s_qcop = &xfs_quotactl_operations; |
| 1333 | sb->s_op = &xfs_super_operations; | 1703 | sb->s_op = &xfs_super_operations; |
| 1334 | 1704 | ||
| 1335 | error = xfs_mount(mp, args, NULL); | 1705 | error = xfs_dmops_get(mp, args); |
| 1706 | if (error) | ||
| 1707 | goto out_free_mp; | ||
| 1708 | error = xfs_qmops_get(mp, args); | ||
| 1709 | if (error) | ||
| 1710 | goto out_put_dmops; | ||
| 1711 | |||
| 1712 | if (args->flags & XFSMNT_QUIET) | ||
| 1713 | flags |= XFS_MFSI_QUIET; | ||
| 1714 | |||
| 1715 | error = xfs_open_devices(mp, args); | ||
| 1716 | if (error) | ||
| 1717 | goto out_put_qmops; | ||
| 1718 | |||
| 1719 | if (xfs_icsb_init_counters(mp)) | ||
| 1720 | mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB; | ||
| 1721 | |||
| 1722 | /* | ||
| 1723 | * Setup flags based on mount(2) options and then the superblock | ||
| 1724 | */ | ||
| 1725 | error = xfs_start_flags(args, mp); | ||
| 1726 | if (error) | ||
| 1727 | goto out_free_fsname; | ||
| 1728 | error = xfs_readsb(mp, flags); | ||
| 1729 | if (error) | ||
| 1730 | goto out_free_fsname; | ||
| 1731 | error = xfs_finish_flags(args, mp); | ||
| 1336 | if (error) | 1732 | if (error) |
| 1337 | goto fail_vfsop; | 1733 | goto out_free_sb; |
| 1734 | |||
| 1735 | error = xfs_setup_devices(mp); | ||
| 1736 | if (error) | ||
| 1737 | goto out_free_sb; | ||
| 1738 | |||
| 1739 | if (mp->m_flags & XFS_MOUNT_BARRIER) | ||
| 1740 | xfs_mountfs_check_barriers(mp); | ||
| 1741 | |||
| 1742 | error = xfs_filestream_mount(mp); | ||
| 1743 | if (error) | ||
| 1744 | goto out_free_sb; | ||
| 1745 | |||
| 1746 | error = xfs_mountfs(mp); | ||
| 1747 | if (error) | ||
| 1748 | goto out_filestream_unmount; | ||
| 1749 | |||
| 1750 | XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, args->mtpt, args->fsname); | ||
| 1338 | 1751 | ||
| 1339 | sb->s_dirt = 1; | 1752 | sb->s_dirt = 1; |
| 1340 | sb->s_magic = XFS_SB_MAGIC; | 1753 | sb->s_magic = XFS_SB_MAGIC; |
| @@ -1344,7 +1757,7 @@ xfs_fs_fill_super( | |||
| 1344 | sb->s_time_gran = 1; | 1757 | sb->s_time_gran = 1; |
| 1345 | set_posix_acl_flag(sb); | 1758 | set_posix_acl_flag(sb); |
| 1346 | 1759 | ||
| 1347 | root = igrab(mp->m_rootip->i_vnode); | 1760 | root = igrab(VFS_I(mp->m_rootip)); |
| 1348 | if (!root) { | 1761 | if (!root) { |
| 1349 | error = ENOENT; | 1762 | error = ENOENT; |
| 1350 | goto fail_unmount; | 1763 | goto fail_unmount; |
| @@ -1369,10 +1782,28 @@ xfs_fs_fill_super( | |||
| 1369 | 1782 | ||
| 1370 | xfs_itrace_exit(XFS_I(sb->s_root->d_inode)); | 1783 | xfs_itrace_exit(XFS_I(sb->s_root->d_inode)); |
| 1371 | 1784 | ||
| 1372 | kmem_free(args, sizeof(*args)); | 1785 | kfree(args); |
| 1373 | return 0; | 1786 | return 0; |
| 1374 | 1787 | ||
| 1375 | fail_vnrele: | 1788 | out_filestream_unmount: |
| 1789 | xfs_filestream_unmount(mp); | ||
| 1790 | out_free_sb: | ||
| 1791 | xfs_freesb(mp); | ||
| 1792 | out_free_fsname: | ||
| 1793 | xfs_free_fsname(mp); | ||
| 1794 | xfs_icsb_destroy_counters(mp); | ||
| 1795 | xfs_close_devices(mp); | ||
| 1796 | out_put_qmops: | ||
| 1797 | xfs_qmops_put(mp); | ||
| 1798 | out_put_dmops: | ||
| 1799 | xfs_dmops_put(mp); | ||
| 1800 | out_free_mp: | ||
| 1801 | kfree(mp); | ||
| 1802 | out_free_args: | ||
| 1803 | kfree(args); | ||
| 1804 | return -error; | ||
| 1805 | |||
| 1806 | fail_vnrele: | ||
| 1376 | if (sb->s_root) { | 1807 | if (sb->s_root) { |
| 1377 | dput(sb->s_root); | 1808 | dput(sb->s_root); |
| 1378 | sb->s_root = NULL; | 1809 | sb->s_root = NULL; |
| @@ -1380,12 +1811,20 @@ fail_vnrele: | |||
| 1380 | iput(root); | 1811 | iput(root); |
| 1381 | } | 1812 | } |
| 1382 | 1813 | ||
| 1383 | fail_unmount: | 1814 | fail_unmount: |
| 1384 | xfs_unmount(mp, 0, NULL); | 1815 | /* |
| 1816 | * Blow away any referenced inode in the filestreams cache. | ||
| 1817 | * This can and will cause log traffic as inodes go inactive | ||
| 1818 | * here. | ||
| 1819 | */ | ||
| 1820 | xfs_filestream_unmount(mp); | ||
| 1385 | 1821 | ||
| 1386 | fail_vfsop: | 1822 | XFS_bflush(mp->m_ddev_targp); |
| 1387 | kmem_free(args, sizeof(*args)); | 1823 | error = xfs_unmount_flush(mp, 0); |
| 1388 | return -error; | 1824 | WARN_ON(error); |
| 1825 | |||
| 1826 | xfs_unmountfs(mp); | ||
| 1827 | goto out_free_sb; | ||
| 1389 | } | 1828 | } |
| 1390 | 1829 | ||
| 1391 | STATIC int | 1830 | STATIC int |
| @@ -1430,9 +1869,235 @@ static struct file_system_type xfs_fs_type = { | |||
| 1430 | .fs_flags = FS_REQUIRES_DEV, | 1869 | .fs_flags = FS_REQUIRES_DEV, |
| 1431 | }; | 1870 | }; |
| 1432 | 1871 | ||
| 1872 | STATIC int __init | ||
| 1873 | xfs_alloc_trace_bufs(void) | ||
| 1874 | { | ||
| 1875 | #ifdef XFS_ALLOC_TRACE | ||
| 1876 | xfs_alloc_trace_buf = ktrace_alloc(XFS_ALLOC_TRACE_SIZE, KM_MAYFAIL); | ||
| 1877 | if (!xfs_alloc_trace_buf) | ||
| 1878 | goto out; | ||
| 1879 | #endif | ||
| 1880 | #ifdef XFS_BMAP_TRACE | ||
| 1881 | xfs_bmap_trace_buf = ktrace_alloc(XFS_BMAP_TRACE_SIZE, KM_MAYFAIL); | ||
| 1882 | if (!xfs_bmap_trace_buf) | ||
| 1883 | goto out_free_alloc_trace; | ||
| 1884 | #endif | ||
| 1885 | #ifdef XFS_BMBT_TRACE | ||
| 1886 | xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_MAYFAIL); | ||
| 1887 | if (!xfs_bmbt_trace_buf) | ||
| 1888 | goto out_free_bmap_trace; | ||
| 1889 | #endif | ||
| 1890 | #ifdef XFS_ATTR_TRACE | ||
| 1891 | xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_MAYFAIL); | ||
| 1892 | if (!xfs_attr_trace_buf) | ||
| 1893 | goto out_free_bmbt_trace; | ||
| 1894 | #endif | ||
| 1895 | #ifdef XFS_DIR2_TRACE | ||
| 1896 | xfs_dir2_trace_buf = ktrace_alloc(XFS_DIR2_GTRACE_SIZE, KM_MAYFAIL); | ||
| 1897 | if (!xfs_dir2_trace_buf) | ||
| 1898 | goto out_free_attr_trace; | ||
| 1899 | #endif | ||
| 1900 | |||
| 1901 | return 0; | ||
| 1902 | |||
| 1903 | #ifdef XFS_DIR2_TRACE | ||
| 1904 | out_free_attr_trace: | ||
| 1905 | #endif | ||
| 1906 | #ifdef XFS_ATTR_TRACE | ||
| 1907 | ktrace_free(xfs_attr_trace_buf); | ||
| 1908 | out_free_bmbt_trace: | ||
| 1909 | #endif | ||
| 1910 | #ifdef XFS_BMBT_TRACE | ||
| 1911 | ktrace_free(xfs_bmbt_trace_buf); | ||
| 1912 | out_free_bmap_trace: | ||
| 1913 | #endif | ||
| 1914 | #ifdef XFS_BMAP_TRACE | ||
| 1915 | ktrace_free(xfs_bmap_trace_buf); | ||
| 1916 | out_free_alloc_trace: | ||
| 1917 | #endif | ||
| 1918 | #ifdef XFS_ALLOC_TRACE | ||
| 1919 | ktrace_free(xfs_alloc_trace_buf); | ||
| 1920 | out: | ||
| 1921 | #endif | ||
| 1922 | return -ENOMEM; | ||
| 1923 | } | ||
| 1924 | |||
| 1925 | STATIC void | ||
| 1926 | xfs_free_trace_bufs(void) | ||
| 1927 | { | ||
| 1928 | #ifdef XFS_DIR2_TRACE | ||
| 1929 | ktrace_free(xfs_dir2_trace_buf); | ||
| 1930 | #endif | ||
| 1931 | #ifdef XFS_ATTR_TRACE | ||
| 1932 | ktrace_free(xfs_attr_trace_buf); | ||
| 1933 | #endif | ||
| 1934 | #ifdef XFS_BMBT_TRACE | ||
| 1935 | ktrace_free(xfs_bmbt_trace_buf); | ||
| 1936 | #endif | ||
| 1937 | #ifdef XFS_BMAP_TRACE | ||
| 1938 | ktrace_free(xfs_bmap_trace_buf); | ||
| 1939 | #endif | ||
| 1940 | #ifdef XFS_ALLOC_TRACE | ||
| 1941 | ktrace_free(xfs_alloc_trace_buf); | ||
| 1942 | #endif | ||
| 1943 | } | ||
| 1944 | |||
| 1945 | STATIC int __init | ||
| 1946 | xfs_init_zones(void) | ||
| 1947 | { | ||
| 1948 | xfs_vnode_zone = kmem_zone_init_flags(sizeof(struct inode), "xfs_vnode", | ||
| 1949 | KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | | ||
| 1950 | KM_ZONE_SPREAD, | ||
| 1951 | xfs_fs_inode_init_once); | ||
| 1952 | if (!xfs_vnode_zone) | ||
| 1953 | goto out; | ||
| 1954 | |||
| 1955 | xfs_ioend_zone = kmem_zone_init(sizeof(xfs_ioend_t), "xfs_ioend"); | ||
| 1956 | if (!xfs_ioend_zone) | ||
| 1957 | goto out_destroy_vnode_zone; | ||
| 1958 | |||
| 1959 | xfs_ioend_pool = mempool_create_slab_pool(4 * MAX_BUF_PER_PAGE, | ||
| 1960 | xfs_ioend_zone); | ||
| 1961 | if (!xfs_ioend_pool) | ||
| 1962 | goto out_destroy_ioend_zone; | ||
| 1963 | |||
| 1964 | xfs_log_ticket_zone = kmem_zone_init(sizeof(xlog_ticket_t), | ||
| 1965 | "xfs_log_ticket"); | ||
| 1966 | if (!xfs_log_ticket_zone) | ||
| 1967 | goto out_destroy_ioend_pool; | ||
| 1968 | |||
| 1969 | xfs_bmap_free_item_zone = kmem_zone_init(sizeof(xfs_bmap_free_item_t), | ||
| 1970 | "xfs_bmap_free_item"); | ||
| 1971 | if (!xfs_bmap_free_item_zone) | ||
| 1972 | goto out_destroy_log_ticket_zone; | ||
| 1973 | xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t), | ||
| 1974 | "xfs_btree_cur"); | ||
| 1975 | if (!xfs_btree_cur_zone) | ||
| 1976 | goto out_destroy_bmap_free_item_zone; | ||
| 1977 | |||
| 1978 | xfs_da_state_zone = kmem_zone_init(sizeof(xfs_da_state_t), | ||
| 1979 | "xfs_da_state"); | ||
| 1980 | if (!xfs_da_state_zone) | ||
| 1981 | goto out_destroy_btree_cur_zone; | ||
| 1982 | |||
| 1983 | xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf"); | ||
| 1984 | if (!xfs_dabuf_zone) | ||
| 1985 | goto out_destroy_da_state_zone; | ||
| 1986 | |||
| 1987 | xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); | ||
| 1988 | if (!xfs_ifork_zone) | ||
| 1989 | goto out_destroy_dabuf_zone; | ||
| 1990 | |||
| 1991 | xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans"); | ||
| 1992 | if (!xfs_trans_zone) | ||
| 1993 | goto out_destroy_ifork_zone; | ||
| 1994 | |||
| 1995 | /* | ||
| 1996 | * The size of the zone allocated buf log item is the maximum | ||
| 1997 | * size possible under XFS. This wastes a little bit of memory, | ||
| 1998 | * but it is much faster. | ||
| 1999 | */ | ||
| 2000 | xfs_buf_item_zone = kmem_zone_init((sizeof(xfs_buf_log_item_t) + | ||
| 2001 | (((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) / | ||
| 2002 | NBWORD) * sizeof(int))), "xfs_buf_item"); | ||
| 2003 | if (!xfs_buf_item_zone) | ||
| 2004 | goto out_destroy_trans_zone; | ||
| 2005 | |||
| 2006 | xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) + | ||
| 2007 | ((XFS_EFD_MAX_FAST_EXTENTS - 1) * | ||
| 2008 | sizeof(xfs_extent_t))), "xfs_efd_item"); | ||
| 2009 | if (!xfs_efd_zone) | ||
| 2010 | goto out_destroy_buf_item_zone; | ||
| 2011 | |||
| 2012 | xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) + | ||
| 2013 | ((XFS_EFI_MAX_FAST_EXTENTS - 1) * | ||
| 2014 | sizeof(xfs_extent_t))), "xfs_efi_item"); | ||
| 2015 | if (!xfs_efi_zone) | ||
| 2016 | goto out_destroy_efd_zone; | ||
| 2017 | |||
| 2018 | xfs_inode_zone = | ||
| 2019 | kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode", | ||
| 2020 | KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | | ||
| 2021 | KM_ZONE_SPREAD, NULL); | ||
| 2022 | if (!xfs_inode_zone) | ||
| 2023 | goto out_destroy_efi_zone; | ||
| 2024 | |||
| 2025 | xfs_ili_zone = | ||
| 2026 | kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili", | ||
| 2027 | KM_ZONE_SPREAD, NULL); | ||
| 2028 | if (!xfs_ili_zone) | ||
| 2029 | goto out_destroy_inode_zone; | ||
| 2030 | |||
| 2031 | #ifdef CONFIG_XFS_POSIX_ACL | ||
| 2032 | xfs_acl_zone = kmem_zone_init(sizeof(xfs_acl_t), "xfs_acl"); | ||
| 2033 | if (!xfs_acl_zone) | ||
| 2034 | goto out_destroy_ili_zone; | ||
| 2035 | #endif | ||
| 2036 | |||
| 2037 | return 0; | ||
| 2038 | |||
| 2039 | #ifdef CONFIG_XFS_POSIX_ACL | ||
| 2040 | out_destroy_ili_zone: | ||
| 2041 | #endif | ||
| 2042 | kmem_zone_destroy(xfs_ili_zone); | ||
| 2043 | out_destroy_inode_zone: | ||
| 2044 | kmem_zone_destroy(xfs_inode_zone); | ||
| 2045 | out_destroy_efi_zone: | ||
| 2046 | kmem_zone_destroy(xfs_efi_zone); | ||
| 2047 | out_destroy_efd_zone: | ||
| 2048 | kmem_zone_destroy(xfs_efd_zone); | ||
| 2049 | out_destroy_buf_item_zone: | ||
| 2050 | kmem_zone_destroy(xfs_buf_item_zone); | ||
| 2051 | out_destroy_trans_zone: | ||
| 2052 | kmem_zone_destroy(xfs_trans_zone); | ||
| 2053 | out_destroy_ifork_zone: | ||
| 2054 | kmem_zone_destroy(xfs_ifork_zone); | ||
| 2055 | out_destroy_dabuf_zone: | ||
| 2056 | kmem_zone_destroy(xfs_dabuf_zone); | ||
| 2057 | out_destroy_da_state_zone: | ||
| 2058 | kmem_zone_destroy(xfs_da_state_zone); | ||
| 2059 | out_destroy_btree_cur_zone: | ||
| 2060 | kmem_zone_destroy(xfs_btree_cur_zone); | ||
| 2061 | out_destroy_bmap_free_item_zone: | ||
| 2062 | kmem_zone_destroy(xfs_bmap_free_item_zone); | ||
| 2063 | out_destroy_log_ticket_zone: | ||
| 2064 | kmem_zone_destroy(xfs_log_ticket_zone); | ||
| 2065 | out_destroy_ioend_pool: | ||
| 2066 | mempool_destroy(xfs_ioend_pool); | ||
| 2067 | out_destroy_ioend_zone: | ||
| 2068 | kmem_zone_destroy(xfs_ioend_zone); | ||
| 2069 | out_destroy_vnode_zone: | ||
| 2070 | kmem_zone_destroy(xfs_vnode_zone); | ||
| 2071 | out: | ||
| 2072 | return -ENOMEM; | ||
| 2073 | } | ||
| 2074 | |||
| 2075 | STATIC void | ||
| 2076 | xfs_destroy_zones(void) | ||
| 2077 | { | ||
| 2078 | #ifdef CONFIG_XFS_POSIX_ACL | ||
| 2079 | kmem_zone_destroy(xfs_acl_zone); | ||
| 2080 | #endif | ||
| 2081 | kmem_zone_destroy(xfs_ili_zone); | ||
| 2082 | kmem_zone_destroy(xfs_inode_zone); | ||
| 2083 | kmem_zone_destroy(xfs_efi_zone); | ||
| 2084 | kmem_zone_destroy(xfs_efd_zone); | ||
| 2085 | kmem_zone_destroy(xfs_buf_item_zone); | ||
| 2086 | kmem_zone_destroy(xfs_trans_zone); | ||
| 2087 | kmem_zone_destroy(xfs_ifork_zone); | ||
| 2088 | kmem_zone_destroy(xfs_dabuf_zone); | ||
| 2089 | kmem_zone_destroy(xfs_da_state_zone); | ||
| 2090 | kmem_zone_destroy(xfs_btree_cur_zone); | ||
| 2091 | kmem_zone_destroy(xfs_bmap_free_item_zone); | ||
| 2092 | kmem_zone_destroy(xfs_log_ticket_zone); | ||
| 2093 | mempool_destroy(xfs_ioend_pool); | ||
| 2094 | kmem_zone_destroy(xfs_ioend_zone); | ||
| 2095 | kmem_zone_destroy(xfs_vnode_zone); | ||
| 2096 | |||
| 2097 | } | ||
| 1433 | 2098 | ||
| 1434 | STATIC int __init | 2099 | STATIC int __init |
| 1435 | init_xfs_fs( void ) | 2100 | init_xfs_fs(void) |
| 1436 | { | 2101 | { |
| 1437 | int error; | 2102 | int error; |
| 1438 | static char message[] __initdata = KERN_INFO \ | 2103 | static char message[] __initdata = KERN_INFO \ |
| @@ -1441,42 +2106,73 @@ init_xfs_fs( void ) | |||
| 1441 | printk(message); | 2106 | printk(message); |
| 1442 | 2107 | ||
| 1443 | ktrace_init(64); | 2108 | ktrace_init(64); |
| 2109 | vn_init(); | ||
| 2110 | xfs_dir_startup(); | ||
| 1444 | 2111 | ||
| 1445 | error = xfs_init_zones(); | 2112 | error = xfs_init_zones(); |
| 1446 | if (error < 0) | 2113 | if (error) |
| 1447 | goto undo_zones; | 2114 | goto out; |
| 2115 | |||
| 2116 | error = xfs_alloc_trace_bufs(); | ||
| 2117 | if (error) | ||
| 2118 | goto out_destroy_zones; | ||
| 2119 | |||
| 2120 | error = xfs_mru_cache_init(); | ||
| 2121 | if (error) | ||
| 2122 | goto out_free_trace_buffers; | ||
| 2123 | |||
| 2124 | error = xfs_filestream_init(); | ||
| 2125 | if (error) | ||
| 2126 | goto out_mru_cache_uninit; | ||
| 1448 | 2127 | ||
| 1449 | error = xfs_buf_init(); | 2128 | error = xfs_buf_init(); |
| 1450 | if (error < 0) | 2129 | if (error) |
| 1451 | goto undo_buffers; | 2130 | goto out_filestream_uninit; |
| 2131 | |||
| 2132 | error = xfs_init_procfs(); | ||
| 2133 | if (error) | ||
| 2134 | goto out_buf_terminate; | ||
| 2135 | |||
| 2136 | error = xfs_sysctl_register(); | ||
| 2137 | if (error) | ||
| 2138 | goto out_cleanup_procfs; | ||
| 1452 | 2139 | ||
| 1453 | vn_init(); | ||
| 1454 | xfs_init(); | ||
| 1455 | uuid_init(); | ||
| 1456 | vfs_initquota(); | 2140 | vfs_initquota(); |
| 1457 | 2141 | ||
| 1458 | error = register_filesystem(&xfs_fs_type); | 2142 | error = register_filesystem(&xfs_fs_type); |
| 1459 | if (error) | 2143 | if (error) |
| 1460 | goto undo_register; | 2144 | goto out_sysctl_unregister; |
| 1461 | return 0; | 2145 | return 0; |
| 1462 | 2146 | ||
| 1463 | undo_register: | 2147 | out_sysctl_unregister: |
| 2148 | xfs_sysctl_unregister(); | ||
| 2149 | out_cleanup_procfs: | ||
| 2150 | xfs_cleanup_procfs(); | ||
| 2151 | out_buf_terminate: | ||
| 1464 | xfs_buf_terminate(); | 2152 | xfs_buf_terminate(); |
| 1465 | 2153 | out_filestream_uninit: | |
| 1466 | undo_buffers: | 2154 | xfs_filestream_uninit(); |
| 2155 | out_mru_cache_uninit: | ||
| 2156 | xfs_mru_cache_uninit(); | ||
| 2157 | out_free_trace_buffers: | ||
| 2158 | xfs_free_trace_bufs(); | ||
| 2159 | out_destroy_zones: | ||
| 1467 | xfs_destroy_zones(); | 2160 | xfs_destroy_zones(); |
| 1468 | 2161 | out: | |
| 1469 | undo_zones: | ||
| 1470 | return error; | 2162 | return error; |
| 1471 | } | 2163 | } |
| 1472 | 2164 | ||
| 1473 | STATIC void __exit | 2165 | STATIC void __exit |
| 1474 | exit_xfs_fs( void ) | 2166 | exit_xfs_fs(void) |
| 1475 | { | 2167 | { |
| 1476 | vfs_exitquota(); | 2168 | vfs_exitquota(); |
| 1477 | unregister_filesystem(&xfs_fs_type); | 2169 | unregister_filesystem(&xfs_fs_type); |
| 1478 | xfs_cleanup(); | 2170 | xfs_sysctl_unregister(); |
| 2171 | xfs_cleanup_procfs(); | ||
| 1479 | xfs_buf_terminate(); | 2172 | xfs_buf_terminate(); |
| 2173 | xfs_filestream_uninit(); | ||
| 2174 | xfs_mru_cache_uninit(); | ||
| 2175 | xfs_free_trace_bufs(); | ||
| 1480 | xfs_destroy_zones(); | 2176 | xfs_destroy_zones(); |
| 1481 | ktrace_uninit(); | 2177 | ktrace_uninit(); |
| 1482 | } | 2178 | } |
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 3efb7c6d3303..fe2ef4e6a0f9 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h | |||
| @@ -101,18 +101,13 @@ struct block_device; | |||
| 101 | 101 | ||
| 102 | extern __uint64_t xfs_max_file_offset(unsigned int); | 102 | extern __uint64_t xfs_max_file_offset(unsigned int); |
| 103 | 103 | ||
| 104 | extern void xfs_initialize_vnode(struct xfs_mount *mp, bhv_vnode_t *vp, | ||
| 105 | struct xfs_inode *ip); | ||
| 106 | |||
| 107 | extern void xfs_flush_inode(struct xfs_inode *); | 104 | extern void xfs_flush_inode(struct xfs_inode *); |
| 108 | extern void xfs_flush_device(struct xfs_inode *); | 105 | extern void xfs_flush_device(struct xfs_inode *); |
| 109 | 106 | ||
| 110 | extern int xfs_blkdev_get(struct xfs_mount *, const char *, | ||
| 111 | struct block_device **); | ||
| 112 | extern void xfs_blkdev_put(struct block_device *); | ||
| 113 | extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); | 107 | extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); |
| 114 | 108 | ||
| 115 | extern const struct export_operations xfs_export_operations; | 109 | extern const struct export_operations xfs_export_operations; |
| 110 | extern struct xattr_handler *xfs_xattr_handlers[]; | ||
| 116 | 111 | ||
| 117 | #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) | 112 | #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) |
| 118 | 113 | ||
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c index bb997d75c05c..7dacb5bbde3f 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.c +++ b/fs/xfs/linux-2.6/xfs_sysctl.c | |||
| @@ -259,15 +259,17 @@ static ctl_table xfs_root_table[] = { | |||
| 259 | {} | 259 | {} |
| 260 | }; | 260 | }; |
| 261 | 261 | ||
| 262 | void | 262 | int |
| 263 | xfs_sysctl_register(void) | 263 | xfs_sysctl_register(void) |
| 264 | { | 264 | { |
| 265 | xfs_table_header = register_sysctl_table(xfs_root_table); | 265 | xfs_table_header = register_sysctl_table(xfs_root_table); |
| 266 | if (!xfs_table_header) | ||
| 267 | return -ENOMEM; | ||
| 268 | return 0; | ||
| 266 | } | 269 | } |
| 267 | 270 | ||
| 268 | void | 271 | void |
| 269 | xfs_sysctl_unregister(void) | 272 | xfs_sysctl_unregister(void) |
| 270 | { | 273 | { |
| 271 | if (xfs_table_header) | 274 | unregister_sysctl_table(xfs_table_header); |
| 272 | unregister_sysctl_table(xfs_table_header); | ||
| 273 | } | 275 | } |
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.h b/fs/xfs/linux-2.6/xfs_sysctl.h index 98b97e399d6f..4aadb8056c37 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.h +++ b/fs/xfs/linux-2.6/xfs_sysctl.h | |||
| @@ -93,10 +93,10 @@ enum { | |||
| 93 | extern xfs_param_t xfs_params; | 93 | extern xfs_param_t xfs_params; |
| 94 | 94 | ||
| 95 | #ifdef CONFIG_SYSCTL | 95 | #ifdef CONFIG_SYSCTL |
| 96 | extern void xfs_sysctl_register(void); | 96 | extern int xfs_sysctl_register(void); |
| 97 | extern void xfs_sysctl_unregister(void); | 97 | extern void xfs_sysctl_unregister(void); |
| 98 | #else | 98 | #else |
| 99 | # define xfs_sysctl_register() do { } while (0) | 99 | # define xfs_sysctl_register() (0) |
| 100 | # define xfs_sysctl_unregister() do { } while (0) | 100 | # define xfs_sysctl_unregister() do { } while (0) |
| 101 | #endif /* CONFIG_SYSCTL */ | 101 | #endif /* CONFIG_SYSCTL */ |
| 102 | 102 | ||
diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index bc7afe007338..b52528bbbfff 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | ||
| 34 | 34 | ||
| 35 | /* | 35 | /* |
| 36 | * Dedicated vnode inactive/reclaim sync semaphores. | 36 | * Dedicated vnode inactive/reclaim sync wait queues. |
| 37 | * Prime number of hash buckets since address is used as the key. | 37 | * Prime number of hash buckets since address is used as the key. |
| 38 | */ | 38 | */ |
| 39 | #define NVSYNC 37 | 39 | #define NVSYNC 37 |
| @@ -82,74 +82,6 @@ vn_ioerror( | |||
| 82 | xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l); | 82 | xfs_do_force_shutdown(ip->i_mount, SHUTDOWN_DEVICE_REQ, f, l); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | /* | ||
| 86 | * Revalidate the Linux inode from the XFS inode. | ||
| 87 | * Note: i_size _not_ updated; we must hold the inode | ||
| 88 | * semaphore when doing that - callers responsibility. | ||
| 89 | */ | ||
| 90 | int | ||
| 91 | vn_revalidate( | ||
| 92 | bhv_vnode_t *vp) | ||
| 93 | { | ||
| 94 | struct inode *inode = vn_to_inode(vp); | ||
| 95 | struct xfs_inode *ip = XFS_I(inode); | ||
| 96 | struct xfs_mount *mp = ip->i_mount; | ||
| 97 | unsigned long xflags; | ||
| 98 | |||
| 99 | xfs_itrace_entry(ip); | ||
| 100 | |||
| 101 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 102 | return -EIO; | ||
| 103 | |||
| 104 | xfs_ilock(ip, XFS_ILOCK_SHARED); | ||
| 105 | inode->i_mode = ip->i_d.di_mode; | ||
| 106 | inode->i_uid = ip->i_d.di_uid; | ||
| 107 | inode->i_gid = ip->i_d.di_gid; | ||
| 108 | inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; | ||
| 109 | inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; | ||
| 110 | inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; | ||
| 111 | inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; | ||
| 112 | |||
| 113 | xflags = xfs_ip2xflags(ip); | ||
| 114 | if (xflags & XFS_XFLAG_IMMUTABLE) | ||
| 115 | inode->i_flags |= S_IMMUTABLE; | ||
| 116 | else | ||
| 117 | inode->i_flags &= ~S_IMMUTABLE; | ||
| 118 | if (xflags & XFS_XFLAG_APPEND) | ||
| 119 | inode->i_flags |= S_APPEND; | ||
| 120 | else | ||
| 121 | inode->i_flags &= ~S_APPEND; | ||
| 122 | if (xflags & XFS_XFLAG_SYNC) | ||
| 123 | inode->i_flags |= S_SYNC; | ||
| 124 | else | ||
| 125 | inode->i_flags &= ~S_SYNC; | ||
| 126 | if (xflags & XFS_XFLAG_NOATIME) | ||
| 127 | inode->i_flags |= S_NOATIME; | ||
| 128 | else | ||
| 129 | inode->i_flags &= ~S_NOATIME; | ||
| 130 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | ||
| 131 | |||
| 132 | xfs_iflags_clear(ip, XFS_IMODIFIED); | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * Add a reference to a referenced vnode. | ||
| 138 | */ | ||
| 139 | bhv_vnode_t * | ||
| 140 | vn_hold( | ||
| 141 | bhv_vnode_t *vp) | ||
| 142 | { | ||
| 143 | struct inode *inode; | ||
| 144 | |||
| 145 | XFS_STATS_INC(vn_hold); | ||
| 146 | |||
| 147 | inode = igrab(vn_to_inode(vp)); | ||
| 148 | ASSERT(inode); | ||
| 149 | |||
| 150 | return vp; | ||
| 151 | } | ||
| 152 | |||
| 153 | #ifdef XFS_INODE_TRACE | 85 | #ifdef XFS_INODE_TRACE |
| 154 | 86 | ||
| 155 | /* | 87 | /* |
| @@ -158,7 +90,7 @@ vn_hold( | |||
| 158 | */ | 90 | */ |
| 159 | static inline int xfs_icount(struct xfs_inode *ip) | 91 | static inline int xfs_icount(struct xfs_inode *ip) |
| 160 | { | 92 | { |
| 161 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); | 93 | struct inode *vp = VFS_I(ip); |
| 162 | 94 | ||
| 163 | if (vp) | 95 | if (vp) |
| 164 | return vn_count(vp); | 96 | return vn_count(vp); |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 25eb2a9e8d9b..683ce16210ff 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h | |||
| @@ -19,24 +19,9 @@ | |||
| 19 | #define __XFS_VNODE_H__ | 19 | #define __XFS_VNODE_H__ |
| 20 | 20 | ||
| 21 | struct file; | 21 | struct file; |
| 22 | struct bhv_vattr; | ||
| 23 | struct xfs_iomap; | 22 | struct xfs_iomap; |
| 24 | struct attrlist_cursor_kern; | 23 | struct attrlist_cursor_kern; |
| 25 | 24 | ||
| 26 | typedef struct inode bhv_vnode_t; | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Vnode to Linux inode mapping. | ||
| 30 | */ | ||
| 31 | static inline bhv_vnode_t *vn_from_inode(struct inode *inode) | ||
| 32 | { | ||
| 33 | return inode; | ||
| 34 | } | ||
| 35 | static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) | ||
| 36 | { | ||
| 37 | return vnode; | ||
| 38 | } | ||
| 39 | |||
| 40 | /* | 25 | /* |
| 41 | * Return values for xfs_inactive. A return value of | 26 | * Return values for xfs_inactive. A return value of |
| 42 | * VN_INACTIVE_NOCACHE implies that the file system behavior | 27 | * VN_INACTIVE_NOCACHE implies that the file system behavior |
| @@ -66,87 +51,8 @@ static inline struct inode *vn_to_inode(bhv_vnode_t *vnode) | |||
| 66 | Prevent VM access to the pages until | 51 | Prevent VM access to the pages until |
| 67 | the operation completes. */ | 52 | the operation completes. */ |
| 68 | 53 | ||
| 69 | /* | ||
| 70 | * Vnode attributes. va_mask indicates those attributes the caller | ||
| 71 | * wants to set or extract. | ||
| 72 | */ | ||
| 73 | typedef struct bhv_vattr { | ||
| 74 | int va_mask; /* bit-mask of attributes present */ | ||
| 75 | mode_t va_mode; /* file access mode and type */ | ||
| 76 | xfs_nlink_t va_nlink; /* number of references to file */ | ||
| 77 | uid_t va_uid; /* owner user id */ | ||
| 78 | gid_t va_gid; /* owner group id */ | ||
| 79 | xfs_ino_t va_nodeid; /* file id */ | ||
| 80 | xfs_off_t va_size; /* file size in bytes */ | ||
| 81 | u_long va_blocksize; /* blocksize preferred for i/o */ | ||
| 82 | struct timespec va_atime; /* time of last access */ | ||
| 83 | struct timespec va_mtime; /* time of last modification */ | ||
| 84 | struct timespec va_ctime; /* time file changed */ | ||
| 85 | u_int va_gen; /* generation number of file */ | ||
| 86 | xfs_dev_t va_rdev; /* device the special file represents */ | ||
| 87 | __int64_t va_nblocks; /* number of blocks allocated */ | ||
| 88 | u_long va_xflags; /* random extended file flags */ | ||
| 89 | u_long va_extsize; /* file extent size */ | ||
| 90 | u_long va_nextents; /* number of extents in file */ | ||
| 91 | u_long va_anextents; /* number of attr extents in file */ | ||
| 92 | prid_t va_projid; /* project id */ | ||
| 93 | } bhv_vattr_t; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * setattr or getattr attributes | ||
| 97 | */ | ||
| 98 | #define XFS_AT_TYPE 0x00000001 | ||
| 99 | #define XFS_AT_MODE 0x00000002 | ||
| 100 | #define XFS_AT_UID 0x00000004 | ||
| 101 | #define XFS_AT_GID 0x00000008 | ||
| 102 | #define XFS_AT_FSID 0x00000010 | ||
| 103 | #define XFS_AT_NODEID 0x00000020 | ||
| 104 | #define XFS_AT_NLINK 0x00000040 | ||
| 105 | #define XFS_AT_SIZE 0x00000080 | ||
| 106 | #define XFS_AT_ATIME 0x00000100 | ||
| 107 | #define XFS_AT_MTIME 0x00000200 | ||
| 108 | #define XFS_AT_CTIME 0x00000400 | ||
| 109 | #define XFS_AT_RDEV 0x00000800 | ||
| 110 | #define XFS_AT_BLKSIZE 0x00001000 | ||
| 111 | #define XFS_AT_NBLOCKS 0x00002000 | ||
| 112 | #define XFS_AT_VCODE 0x00004000 | ||
| 113 | #define XFS_AT_MAC 0x00008000 | ||
| 114 | #define XFS_AT_UPDATIME 0x00010000 | ||
| 115 | #define XFS_AT_UPDMTIME 0x00020000 | ||
| 116 | #define XFS_AT_UPDCTIME 0x00040000 | ||
| 117 | #define XFS_AT_ACL 0x00080000 | ||
| 118 | #define XFS_AT_CAP 0x00100000 | ||
| 119 | #define XFS_AT_INF 0x00200000 | ||
| 120 | #define XFS_AT_XFLAGS 0x00400000 | ||
| 121 | #define XFS_AT_EXTSIZE 0x00800000 | ||
| 122 | #define XFS_AT_NEXTENTS 0x01000000 | ||
| 123 | #define XFS_AT_ANEXTENTS 0x02000000 | ||
| 124 | #define XFS_AT_PROJID 0x04000000 | ||
| 125 | #define XFS_AT_SIZE_NOPERM 0x08000000 | ||
| 126 | #define XFS_AT_GENCOUNT 0x10000000 | ||
| 127 | |||
| 128 | #define XFS_AT_ALL (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ | ||
| 129 | XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ | ||
| 130 | XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ | ||
| 131 | XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|XFS_AT_MAC|\ | ||
| 132 | XFS_AT_ACL|XFS_AT_CAP|XFS_AT_INF|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|\ | ||
| 133 | XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_PROJID|XFS_AT_GENCOUNT) | ||
| 134 | |||
| 135 | #define XFS_AT_STAT (XFS_AT_TYPE|XFS_AT_MODE|XFS_AT_UID|XFS_AT_GID|\ | ||
| 136 | XFS_AT_FSID|XFS_AT_NODEID|XFS_AT_NLINK|XFS_AT_SIZE|\ | ||
| 137 | XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME|XFS_AT_RDEV|\ | ||
| 138 | XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_PROJID) | ||
| 139 | |||
| 140 | #define XFS_AT_TIMES (XFS_AT_ATIME|XFS_AT_MTIME|XFS_AT_CTIME) | ||
| 141 | |||
| 142 | #define XFS_AT_UPDTIMES (XFS_AT_UPDATIME|XFS_AT_UPDMTIME|XFS_AT_UPDCTIME) | ||
| 143 | |||
| 144 | #define XFS_AT_NOSET (XFS_AT_NLINK|XFS_AT_RDEV|XFS_AT_FSID|XFS_AT_NODEID|\ | ||
| 145 | XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\ | ||
| 146 | XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT) | ||
| 147 | 54 | ||
| 148 | extern void vn_init(void); | 55 | extern void vn_init(void); |
| 149 | extern int vn_revalidate(bhv_vnode_t *); | ||
| 150 | 56 | ||
| 151 | /* | 57 | /* |
| 152 | * Yeah, these don't take vnode anymore at all, all this should be | 58 | * Yeah, these don't take vnode anymore at all, all this should be |
| @@ -156,57 +62,52 @@ extern void vn_iowait(struct xfs_inode *ip); | |||
| 156 | extern void vn_iowake(struct xfs_inode *ip); | 62 | extern void vn_iowake(struct xfs_inode *ip); |
| 157 | extern void vn_ioerror(struct xfs_inode *ip, int error, char *f, int l); | 63 | extern void vn_ioerror(struct xfs_inode *ip, int error, char *f, int l); |
| 158 | 64 | ||
| 159 | static inline int vn_count(bhv_vnode_t *vp) | 65 | static inline int vn_count(struct inode *vp) |
| 160 | { | 66 | { |
| 161 | return atomic_read(&vn_to_inode(vp)->i_count); | 67 | return atomic_read(&vp->i_count); |
| 162 | } | 68 | } |
| 163 | 69 | ||
| 164 | /* | 70 | #define IHOLD(ip) \ |
| 165 | * Vnode reference counting functions (and macros for compatibility). | 71 | do { \ |
| 166 | */ | 72 | ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \ |
| 167 | extern bhv_vnode_t *vn_hold(bhv_vnode_t *); | 73 | atomic_inc(&(VFS_I(ip)->i_count)); \ |
| 74 | xfs_itrace_hold((ip), __FILE__, __LINE__, (inst_t *)__return_address); \ | ||
| 75 | } while (0) | ||
| 168 | 76 | ||
| 169 | #if defined(XFS_INODE_TRACE) | 77 | #define IRELE(ip) \ |
| 170 | #define VN_HOLD(vp) \ | 78 | do { \ |
| 171 | ((void)vn_hold(vp), \ | 79 | xfs_itrace_rele((ip), __FILE__, __LINE__, (inst_t *)__return_address); \ |
| 172 | xfs_itrace_hold(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address)) | 80 | iput(VFS_I(ip)); \ |
| 173 | #define VN_RELE(vp) \ | 81 | } while (0) |
| 174 | (xfs_itrace_rele(xfs_vtoi(vp), __FILE__, __LINE__, (inst_t *)__return_address), \ | ||
| 175 | iput(vn_to_inode(vp))) | ||
| 176 | #else | ||
| 177 | #define VN_HOLD(vp) ((void)vn_hold(vp)) | ||
| 178 | #define VN_RELE(vp) (iput(vn_to_inode(vp))) | ||
| 179 | #endif | ||
| 180 | 82 | ||
| 181 | static inline bhv_vnode_t *vn_grab(bhv_vnode_t *vp) | 83 | static inline struct inode *vn_grab(struct inode *vp) |
| 182 | { | 84 | { |
| 183 | struct inode *inode = igrab(vn_to_inode(vp)); | 85 | return igrab(vp); |
| 184 | return inode ? vn_from_inode(inode) : NULL; | ||
| 185 | } | 86 | } |
| 186 | 87 | ||
| 187 | /* | 88 | /* |
| 188 | * Dealing with bad inodes | 89 | * Dealing with bad inodes |
| 189 | */ | 90 | */ |
| 190 | static inline int VN_BAD(bhv_vnode_t *vp) | 91 | static inline int VN_BAD(struct inode *vp) |
| 191 | { | 92 | { |
| 192 | return is_bad_inode(vn_to_inode(vp)); | 93 | return is_bad_inode(vp); |
| 193 | } | 94 | } |
| 194 | 95 | ||
| 195 | /* | 96 | /* |
| 196 | * Extracting atime values in various formats | 97 | * Extracting atime values in various formats |
| 197 | */ | 98 | */ |
| 198 | static inline void vn_atime_to_bstime(bhv_vnode_t *vp, xfs_bstime_t *bs_atime) | 99 | static inline void vn_atime_to_bstime(struct inode *vp, xfs_bstime_t *bs_atime) |
| 199 | { | 100 | { |
| 200 | bs_atime->tv_sec = vp->i_atime.tv_sec; | 101 | bs_atime->tv_sec = vp->i_atime.tv_sec; |
| 201 | bs_atime->tv_nsec = vp->i_atime.tv_nsec; | 102 | bs_atime->tv_nsec = vp->i_atime.tv_nsec; |
| 202 | } | 103 | } |
| 203 | 104 | ||
| 204 | static inline void vn_atime_to_timespec(bhv_vnode_t *vp, struct timespec *ts) | 105 | static inline void vn_atime_to_timespec(struct inode *vp, struct timespec *ts) |
| 205 | { | 106 | { |
| 206 | *ts = vp->i_atime; | 107 | *ts = vp->i_atime; |
| 207 | } | 108 | } |
| 208 | 109 | ||
| 209 | static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) | 110 | static inline void vn_atime_to_time_t(struct inode *vp, time_t *tt) |
| 210 | { | 111 | { |
| 211 | *tt = vp->i_atime.tv_sec; | 112 | *tt = vp->i_atime.tv_sec; |
| 212 | } | 113 | } |
| @@ -214,20 +115,11 @@ static inline void vn_atime_to_time_t(bhv_vnode_t *vp, time_t *tt) | |||
| 214 | /* | 115 | /* |
| 215 | * Some useful predicates. | 116 | * Some useful predicates. |
| 216 | */ | 117 | */ |
| 217 | #define VN_MAPPED(vp) mapping_mapped(vn_to_inode(vp)->i_mapping) | 118 | #define VN_MAPPED(vp) mapping_mapped(vp->i_mapping) |
| 218 | #define VN_CACHED(vp) (vn_to_inode(vp)->i_mapping->nrpages) | 119 | #define VN_CACHED(vp) (vp->i_mapping->nrpages) |
| 219 | #define VN_DIRTY(vp) mapping_tagged(vn_to_inode(vp)->i_mapping, \ | 120 | #define VN_DIRTY(vp) mapping_tagged(vp->i_mapping, \ |
| 220 | PAGECACHE_TAG_DIRTY) | 121 | PAGECACHE_TAG_DIRTY) |
| 221 | 122 | ||
| 222 | /* | ||
| 223 | * Flags to vop_setattr/getattr. | ||
| 224 | */ | ||
| 225 | #define ATTR_UTIME 0x01 /* non-default utime(2) request */ | ||
| 226 | #define ATTR_DMI 0x08 /* invocation from a DMI function */ | ||
| 227 | #define ATTR_LAZY 0x80 /* set/get attributes lazily */ | ||
| 228 | #define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ | ||
| 229 | #define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ | ||
| 230 | #define ATTR_NOSIZETOK 0x400 /* Don't get the SIZE token */ | ||
| 231 | 123 | ||
| 232 | /* | 124 | /* |
| 233 | * Tracking vnode activity. | 125 | * Tracking vnode activity. |
diff --git a/fs/xfs/linux-2.6/xfs_xattr.c b/fs/xfs/linux-2.6/xfs_xattr.c new file mode 100644 index 000000000000..964621fde6ed --- /dev/null +++ b/fs/xfs/linux-2.6/xfs_xattr.c | |||
| @@ -0,0 +1,330 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Christoph Hellwig. | ||
| 3 | * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write the Free Software Foundation, | ||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include "xfs.h" | ||
| 20 | #include "xfs_da_btree.h" | ||
| 21 | #include "xfs_bmap_btree.h" | ||
| 22 | #include "xfs_inode.h" | ||
| 23 | #include "xfs_attr.h" | ||
| 24 | #include "xfs_attr_leaf.h" | ||
| 25 | #include "xfs_acl.h" | ||
| 26 | #include "xfs_vnodeops.h" | ||
| 27 | |||
| 28 | #include <linux/posix_acl_xattr.h> | ||
| 29 | #include <linux/xattr.h> | ||
| 30 | |||
| 31 | |||
| 32 | /* | ||
| 33 | * ACL handling. Should eventually be moved into xfs_acl.c | ||
| 34 | */ | ||
| 35 | |||
| 36 | static int | ||
| 37 | xfs_decode_acl(const char *name) | ||
| 38 | { | ||
| 39 | if (strcmp(name, "posix_acl_access") == 0) | ||
| 40 | return _ACL_TYPE_ACCESS; | ||
| 41 | else if (strcmp(name, "posix_acl_default") == 0) | ||
| 42 | return _ACL_TYPE_DEFAULT; | ||
| 43 | return -EINVAL; | ||
| 44 | } | ||
| 45 | |||
| 46 | /* | ||
| 47 | * Get system extended attributes which at the moment only | ||
| 48 | * includes Posix ACLs. | ||
| 49 | */ | ||
| 50 | static int | ||
| 51 | xfs_xattr_system_get(struct inode *inode, const char *name, | ||
| 52 | void *buffer, size_t size) | ||
| 53 | { | ||
| 54 | int acl; | ||
| 55 | |||
| 56 | acl = xfs_decode_acl(name); | ||
| 57 | if (acl < 0) | ||
| 58 | return acl; | ||
| 59 | |||
| 60 | return xfs_acl_vget(inode, buffer, size, acl); | ||
| 61 | } | ||
| 62 | |||
| 63 | static int | ||
| 64 | xfs_xattr_system_set(struct inode *inode, const char *name, | ||
| 65 | const void *value, size_t size, int flags) | ||
| 66 | { | ||
| 67 | int acl; | ||
| 68 | |||
| 69 | acl = xfs_decode_acl(name); | ||
| 70 | if (acl < 0) | ||
| 71 | return acl; | ||
| 72 | if (flags & XATTR_CREATE) | ||
| 73 | return -EINVAL; | ||
| 74 | |||
| 75 | if (!value) | ||
| 76 | return xfs_acl_vremove(inode, acl); | ||
| 77 | |||
| 78 | return xfs_acl_vset(inode, (void *)value, size, acl); | ||
| 79 | } | ||
| 80 | |||
| 81 | static struct xattr_handler xfs_xattr_system_handler = { | ||
| 82 | .prefix = XATTR_SYSTEM_PREFIX, | ||
| 83 | .get = xfs_xattr_system_get, | ||
| 84 | .set = xfs_xattr_system_set, | ||
| 85 | }; | ||
| 86 | |||
| 87 | |||
| 88 | /* | ||
| 89 | * Real xattr handling. The only difference between the namespaces is | ||
| 90 | * a flag passed to the low-level attr code. | ||
| 91 | */ | ||
| 92 | |||
| 93 | static int | ||
| 94 | __xfs_xattr_get(struct inode *inode, const char *name, | ||
| 95 | void *value, size_t size, int xflags) | ||
| 96 | { | ||
| 97 | struct xfs_inode *ip = XFS_I(inode); | ||
| 98 | int error, asize = size; | ||
| 99 | |||
| 100 | if (strcmp(name, "") == 0) | ||
| 101 | return -EINVAL; | ||
| 102 | |||
| 103 | /* Convert Linux syscall to XFS internal ATTR flags */ | ||
| 104 | if (!size) { | ||
| 105 | xflags |= ATTR_KERNOVAL; | ||
| 106 | value = NULL; | ||
| 107 | } | ||
| 108 | |||
| 109 | error = -xfs_attr_get(ip, name, value, &asize, xflags); | ||
| 110 | if (error) | ||
| 111 | return error; | ||
| 112 | return asize; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int | ||
| 116 | __xfs_xattr_set(struct inode *inode, const char *name, const void *value, | ||
| 117 | size_t size, int flags, int xflags) | ||
| 118 | { | ||
| 119 | struct xfs_inode *ip = XFS_I(inode); | ||
| 120 | |||
| 121 | if (strcmp(name, "") == 0) | ||
| 122 | return -EINVAL; | ||
| 123 | |||
| 124 | /* Convert Linux syscall to XFS internal ATTR flags */ | ||
| 125 | if (flags & XATTR_CREATE) | ||
| 126 | xflags |= ATTR_CREATE; | ||
| 127 | if (flags & XATTR_REPLACE) | ||
| 128 | xflags |= ATTR_REPLACE; | ||
| 129 | |||
| 130 | if (!value) | ||
| 131 | return -xfs_attr_remove(ip, name, xflags); | ||
| 132 | return -xfs_attr_set(ip, name, (void *)value, size, xflags); | ||
| 133 | } | ||
| 134 | |||
| 135 | static int | ||
| 136 | xfs_xattr_user_get(struct inode *inode, const char *name, | ||
| 137 | void *value, size_t size) | ||
| 138 | { | ||
| 139 | return __xfs_xattr_get(inode, name, value, size, 0); | ||
| 140 | } | ||
| 141 | |||
| 142 | static int | ||
| 143 | xfs_xattr_user_set(struct inode *inode, const char *name, | ||
| 144 | const void *value, size_t size, int flags) | ||
| 145 | { | ||
| 146 | return __xfs_xattr_set(inode, name, value, size, flags, 0); | ||
| 147 | } | ||
| 148 | |||
| 149 | static struct xattr_handler xfs_xattr_user_handler = { | ||
| 150 | .prefix = XATTR_USER_PREFIX, | ||
| 151 | .get = xfs_xattr_user_get, | ||
| 152 | .set = xfs_xattr_user_set, | ||
| 153 | }; | ||
| 154 | |||
| 155 | |||
| 156 | static int | ||
| 157 | xfs_xattr_trusted_get(struct inode *inode, const char *name, | ||
| 158 | void *value, size_t size) | ||
| 159 | { | ||
| 160 | return __xfs_xattr_get(inode, name, value, size, ATTR_ROOT); | ||
| 161 | } | ||
| 162 | |||
| 163 | static int | ||
| 164 | xfs_xattr_trusted_set(struct inode *inode, const char *name, | ||
| 165 | const void *value, size_t size, int flags) | ||
| 166 | { | ||
| 167 | return __xfs_xattr_set(inode, name, value, size, flags, ATTR_ROOT); | ||
| 168 | } | ||
| 169 | |||
| 170 | static struct xattr_handler xfs_xattr_trusted_handler = { | ||
| 171 | .prefix = XATTR_TRUSTED_PREFIX, | ||
| 172 | .get = xfs_xattr_trusted_get, | ||
| 173 | .set = xfs_xattr_trusted_set, | ||
| 174 | }; | ||
| 175 | |||
| 176 | |||
| 177 | static int | ||
| 178 | xfs_xattr_secure_get(struct inode *inode, const char *name, | ||
| 179 | void *value, size_t size) | ||
| 180 | { | ||
| 181 | return __xfs_xattr_get(inode, name, value, size, ATTR_SECURE); | ||
| 182 | } | ||
| 183 | |||
| 184 | static int | ||
| 185 | xfs_xattr_secure_set(struct inode *inode, const char *name, | ||
| 186 | const void *value, size_t size, int flags) | ||
| 187 | { | ||
| 188 | return __xfs_xattr_set(inode, name, value, size, flags, ATTR_SECURE); | ||
| 189 | } | ||
| 190 | |||
| 191 | static struct xattr_handler xfs_xattr_security_handler = { | ||
| 192 | .prefix = XATTR_SECURITY_PREFIX, | ||
| 193 | .get = xfs_xattr_secure_get, | ||
| 194 | .set = xfs_xattr_secure_set, | ||
| 195 | }; | ||
| 196 | |||
| 197 | |||
| 198 | struct xattr_handler *xfs_xattr_handlers[] = { | ||
| 199 | &xfs_xattr_user_handler, | ||
| 200 | &xfs_xattr_trusted_handler, | ||
| 201 | &xfs_xattr_security_handler, | ||
| 202 | &xfs_xattr_system_handler, | ||
| 203 | NULL | ||
| 204 | }; | ||
| 205 | |||
| 206 | static unsigned int xfs_xattr_prefix_len(int flags) | ||
| 207 | { | ||
| 208 | if (flags & XFS_ATTR_SECURE) | ||
| 209 | return sizeof("security"); | ||
| 210 | else if (flags & XFS_ATTR_ROOT) | ||
| 211 | return sizeof("trusted"); | ||
| 212 | else | ||
| 213 | return sizeof("user"); | ||
| 214 | } | ||
| 215 | |||
| 216 | static const char *xfs_xattr_prefix(int flags) | ||
| 217 | { | ||
| 218 | if (flags & XFS_ATTR_SECURE) | ||
| 219 | return xfs_xattr_security_handler.prefix; | ||
| 220 | else if (flags & XFS_ATTR_ROOT) | ||
| 221 | return xfs_xattr_trusted_handler.prefix; | ||
| 222 | else | ||
| 223 | return xfs_xattr_user_handler.prefix; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int | ||
| 227 | xfs_xattr_put_listent(struct xfs_attr_list_context *context, int flags, | ||
| 228 | char *name, int namelen, int valuelen, char *value) | ||
| 229 | { | ||
| 230 | unsigned int prefix_len = xfs_xattr_prefix_len(flags); | ||
| 231 | char *offset; | ||
| 232 | int arraytop; | ||
| 233 | |||
| 234 | ASSERT(context->count >= 0); | ||
| 235 | |||
| 236 | /* | ||
| 237 | * Only show root namespace entries if we are actually allowed to | ||
| 238 | * see them. | ||
| 239 | */ | ||
| 240 | if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN)) | ||
| 241 | return 0; | ||
| 242 | |||
| 243 | arraytop = context->count + prefix_len + namelen + 1; | ||
| 244 | if (arraytop > context->firstu) { | ||
| 245 | context->count = -1; /* insufficient space */ | ||
| 246 | return 1; | ||
| 247 | } | ||
| 248 | offset = (char *)context->alist + context->count; | ||
| 249 | strncpy(offset, xfs_xattr_prefix(flags), prefix_len); | ||
| 250 | offset += prefix_len; | ||
| 251 | strncpy(offset, name, namelen); /* real name */ | ||
| 252 | offset += namelen; | ||
| 253 | *offset = '\0'; | ||
| 254 | context->count += prefix_len + namelen + 1; | ||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int | ||
| 259 | xfs_xattr_put_listent_sizes(struct xfs_attr_list_context *context, int flags, | ||
| 260 | char *name, int namelen, int valuelen, char *value) | ||
| 261 | { | ||
| 262 | context->count += xfs_xattr_prefix_len(flags) + namelen + 1; | ||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int | ||
| 267 | list_one_attr(const char *name, const size_t len, void *data, | ||
| 268 | size_t size, ssize_t *result) | ||
| 269 | { | ||
| 270 | char *p = data + *result; | ||
| 271 | |||
| 272 | *result += len; | ||
| 273 | if (!size) | ||
| 274 | return 0; | ||
| 275 | if (*result > size) | ||
| 276 | return -ERANGE; | ||
| 277 | |||
| 278 | strcpy(p, name); | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | ssize_t | ||
| 283 | xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size) | ||
| 284 | { | ||
| 285 | struct xfs_attr_list_context context; | ||
| 286 | struct attrlist_cursor_kern cursor = { 0 }; | ||
| 287 | struct inode *inode = dentry->d_inode; | ||
| 288 | int error; | ||
| 289 | |||
| 290 | /* | ||
| 291 | * First read the regular on-disk attributes. | ||
| 292 | */ | ||
| 293 | memset(&context, 0, sizeof(context)); | ||
| 294 | context.dp = XFS_I(inode); | ||
| 295 | context.cursor = &cursor; | ||
| 296 | context.resynch = 1; | ||
| 297 | context.alist = data; | ||
| 298 | context.bufsize = size; | ||
| 299 | context.firstu = context.bufsize; | ||
| 300 | |||
| 301 | if (size) | ||
| 302 | context.put_listent = xfs_xattr_put_listent; | ||
| 303 | else | ||
| 304 | context.put_listent = xfs_xattr_put_listent_sizes; | ||
| 305 | |||
| 306 | xfs_attr_list_int(&context); | ||
| 307 | if (context.count < 0) | ||
| 308 | return -ERANGE; | ||
| 309 | |||
| 310 | /* | ||
| 311 | * Then add the two synthetic ACL attributes. | ||
| 312 | */ | ||
| 313 | if (xfs_acl_vhasacl_access(inode)) { | ||
| 314 | error = list_one_attr(POSIX_ACL_XATTR_ACCESS, | ||
| 315 | strlen(POSIX_ACL_XATTR_ACCESS) + 1, | ||
| 316 | data, size, &context.count); | ||
| 317 | if (error) | ||
| 318 | return error; | ||
| 319 | } | ||
| 320 | |||
| 321 | if (xfs_acl_vhasacl_default(inode)) { | ||
| 322 | error = list_one_attr(POSIX_ACL_XATTR_DEFAULT, | ||
| 323 | strlen(POSIX_ACL_XATTR_DEFAULT) + 1, | ||
| 324 | data, size, &context.count); | ||
| 325 | if (error) | ||
| 326 | return error; | ||
| 327 | } | ||
| 328 | |||
| 329 | return context.count; | ||
| 330 | } | ||
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 85df3288efd5..f2705f2fd43c 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c | |||
| @@ -101,11 +101,18 @@ xfs_qm_dqinit( | |||
| 101 | if (brandnewdquot) { | 101 | if (brandnewdquot) { |
| 102 | dqp->dq_flnext = dqp->dq_flprev = dqp; | 102 | dqp->dq_flnext = dqp->dq_flprev = dqp; |
| 103 | mutex_init(&dqp->q_qlock); | 103 | mutex_init(&dqp->q_qlock); |
| 104 | initnsema(&dqp->q_flock, 1, "fdq"); | ||
| 105 | sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq"); | 104 | sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq"); |
| 106 | 105 | ||
| 106 | /* | ||
| 107 | * Because we want to use a counting completion, complete | ||
| 108 | * the flush completion once to allow a single access to | ||
| 109 | * the flush completion without blocking. | ||
| 110 | */ | ||
| 111 | init_completion(&dqp->q_flush); | ||
| 112 | complete(&dqp->q_flush); | ||
| 113 | |||
| 107 | #ifdef XFS_DQUOT_TRACE | 114 | #ifdef XFS_DQUOT_TRACE |
| 108 | dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP); | 115 | dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_NOFS); |
| 109 | xfs_dqtrace_entry(dqp, "DQINIT"); | 116 | xfs_dqtrace_entry(dqp, "DQINIT"); |
| 110 | #endif | 117 | #endif |
| 111 | } else { | 118 | } else { |
| @@ -150,7 +157,6 @@ xfs_qm_dqdestroy( | |||
| 150 | ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp)); | 157 | ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp)); |
| 151 | 158 | ||
| 152 | mutex_destroy(&dqp->q_qlock); | 159 | mutex_destroy(&dqp->q_qlock); |
| 153 | freesema(&dqp->q_flock); | ||
| 154 | sv_destroy(&dqp->q_pinwait); | 160 | sv_destroy(&dqp->q_pinwait); |
| 155 | 161 | ||
| 156 | #ifdef XFS_DQUOT_TRACE | 162 | #ifdef XFS_DQUOT_TRACE |
| @@ -431,7 +437,7 @@ xfs_qm_dqalloc( | |||
| 431 | * when it unlocks the inode. Since we want to keep the quota | 437 | * when it unlocks the inode. Since we want to keep the quota |
| 432 | * inode around, we bump the vnode ref count now. | 438 | * inode around, we bump the vnode ref count now. |
| 433 | */ | 439 | */ |
| 434 | VN_HOLD(XFS_ITOV(quotip)); | 440 | IHOLD(quotip); |
| 435 | 441 | ||
| 436 | xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL); | 442 | xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL); |
| 437 | nmaps = 1; | 443 | nmaps = 1; |
| @@ -1211,7 +1217,7 @@ xfs_qm_dqflush( | |||
| 1211 | int error; | 1217 | int error; |
| 1212 | 1218 | ||
| 1213 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | 1219 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
| 1214 | ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); | 1220 | ASSERT(!completion_done(&dqp->q_flush)); |
| 1215 | xfs_dqtrace_entry(dqp, "DQFLUSH"); | 1221 | xfs_dqtrace_entry(dqp, "DQFLUSH"); |
| 1216 | 1222 | ||
| 1217 | /* | 1223 | /* |
| @@ -1348,34 +1354,18 @@ xfs_qm_dqflush_done( | |||
| 1348 | xfs_dqfunlock(dqp); | 1354 | xfs_dqfunlock(dqp); |
| 1349 | } | 1355 | } |
| 1350 | 1356 | ||
| 1351 | |||
| 1352 | int | ||
| 1353 | xfs_qm_dqflock_nowait( | ||
| 1354 | xfs_dquot_t *dqp) | ||
| 1355 | { | ||
| 1356 | int locked; | ||
| 1357 | |||
| 1358 | locked = cpsema(&((dqp)->q_flock)); | ||
| 1359 | |||
| 1360 | /* XXX ifdef these out */ | ||
| 1361 | if (locked) | ||
| 1362 | (dqp)->dq_flags |= XFS_DQ_FLOCKED; | ||
| 1363 | return (locked); | ||
| 1364 | } | ||
| 1365 | |||
| 1366 | |||
| 1367 | int | 1357 | int |
| 1368 | xfs_qm_dqlock_nowait( | 1358 | xfs_qm_dqlock_nowait( |
| 1369 | xfs_dquot_t *dqp) | 1359 | xfs_dquot_t *dqp) |
| 1370 | { | 1360 | { |
| 1371 | return (mutex_trylock(&((dqp)->q_qlock))); | 1361 | return mutex_trylock(&dqp->q_qlock); |
| 1372 | } | 1362 | } |
| 1373 | 1363 | ||
| 1374 | void | 1364 | void |
| 1375 | xfs_dqlock( | 1365 | xfs_dqlock( |
| 1376 | xfs_dquot_t *dqp) | 1366 | xfs_dquot_t *dqp) |
| 1377 | { | 1367 | { |
| 1378 | mutex_lock(&(dqp->q_qlock)); | 1368 | mutex_lock(&dqp->q_qlock); |
| 1379 | } | 1369 | } |
| 1380 | 1370 | ||
| 1381 | void | 1371 | void |
| @@ -1435,8 +1425,7 @@ xfs_dqlock2( | |||
| 1435 | /* ARGSUSED */ | 1425 | /* ARGSUSED */ |
| 1436 | int | 1426 | int |
| 1437 | xfs_qm_dqpurge( | 1427 | xfs_qm_dqpurge( |
| 1438 | xfs_dquot_t *dqp, | 1428 | xfs_dquot_t *dqp) |
| 1439 | uint flags) | ||
| 1440 | { | 1429 | { |
| 1441 | xfs_dqhash_t *thishash; | 1430 | xfs_dqhash_t *thishash; |
| 1442 | xfs_mount_t *mp = dqp->q_mount; | 1431 | xfs_mount_t *mp = dqp->q_mount; |
| @@ -1469,7 +1458,7 @@ xfs_qm_dqpurge( | |||
| 1469 | * if we're turning off quotas. Basically, we need this flush | 1458 | * if we're turning off quotas. Basically, we need this flush |
| 1470 | * lock, and are willing to block on it. | 1459 | * lock, and are willing to block on it. |
| 1471 | */ | 1460 | */ |
| 1472 | if (! xfs_qm_dqflock_nowait(dqp)) { | 1461 | if (!xfs_dqflock_nowait(dqp)) { |
| 1473 | /* | 1462 | /* |
| 1474 | * Block on the flush lock after nudging dquot buffer, | 1463 | * Block on the flush lock after nudging dquot buffer, |
| 1475 | * if it is incore. | 1464 | * if it is incore. |
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/quota/xfs_dquot.h index 5c371a92e3e2..8958d0faf8d3 100644 --- a/fs/xfs/quota/xfs_dquot.h +++ b/fs/xfs/quota/xfs_dquot.h | |||
| @@ -82,7 +82,7 @@ typedef struct xfs_dquot { | |||
| 82 | xfs_qcnt_t q_res_icount; /* total inos allocd+reserved */ | 82 | xfs_qcnt_t q_res_icount; /* total inos allocd+reserved */ |
| 83 | xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */ | 83 | xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */ |
| 84 | mutex_t q_qlock; /* quota lock */ | 84 | mutex_t q_qlock; /* quota lock */ |
| 85 | sema_t q_flock; /* flush lock */ | 85 | struct completion q_flush; /* flush completion queue */ |
| 86 | uint q_pincount; /* pin count for this dquot */ | 86 | uint q_pincount; /* pin count for this dquot */ |
| 87 | sv_t q_pinwait; /* sync var for pinning */ | 87 | sv_t q_pinwait; /* sync var for pinning */ |
| 88 | #ifdef XFS_DQUOT_TRACE | 88 | #ifdef XFS_DQUOT_TRACE |
| @@ -113,17 +113,25 @@ XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) | |||
| 113 | 113 | ||
| 114 | 114 | ||
| 115 | /* | 115 | /* |
| 116 | * The following three routines simply manage the q_flock | 116 | * Manage the q_flush completion queue embedded in the dquot. This completion |
| 117 | * semaphore embedded in the dquot. This semaphore synchronizes | 117 | * queue synchronizes processes attempting to flush the in-core dquot back to |
| 118 | * processes attempting to flush the in-core dquot back to disk. | 118 | * disk. |
| 119 | */ | 119 | */ |
| 120 | #define xfs_dqflock(dqp) { psema(&((dqp)->q_flock), PINOD | PRECALC);\ | 120 | static inline void xfs_dqflock(xfs_dquot_t *dqp) |
| 121 | (dqp)->dq_flags |= XFS_DQ_FLOCKED; } | 121 | { |
| 122 | #define xfs_dqfunlock(dqp) { ASSERT(issemalocked(&((dqp)->q_flock))); \ | 122 | wait_for_completion(&dqp->q_flush); |
| 123 | vsema(&((dqp)->q_flock)); \ | 123 | } |
| 124 | (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); } | 124 | |
| 125 | static inline int xfs_dqflock_nowait(xfs_dquot_t *dqp) | ||
| 126 | { | ||
| 127 | return try_wait_for_completion(&dqp->q_flush); | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline void xfs_dqfunlock(xfs_dquot_t *dqp) | ||
| 131 | { | ||
| 132 | complete(&dqp->q_flush); | ||
| 133 | } | ||
| 125 | 134 | ||
| 126 | #define XFS_DQ_IS_FLUSH_LOCKED(dqp) (issemalocked(&((dqp)->q_flock))) | ||
| 127 | #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) | 135 | #define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) |
| 128 | #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) | 136 | #define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) |
| 129 | #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) | 137 | #define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) |
| @@ -164,10 +172,9 @@ extern void xfs_qm_dqprint(xfs_dquot_t *); | |||
| 164 | 172 | ||
| 165 | extern void xfs_qm_dqdestroy(xfs_dquot_t *); | 173 | extern void xfs_qm_dqdestroy(xfs_dquot_t *); |
| 166 | extern int xfs_qm_dqflush(xfs_dquot_t *, uint); | 174 | extern int xfs_qm_dqflush(xfs_dquot_t *, uint); |
| 167 | extern int xfs_qm_dqpurge(xfs_dquot_t *, uint); | 175 | extern int xfs_qm_dqpurge(xfs_dquot_t *); |
| 168 | extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); | 176 | extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); |
| 169 | extern int xfs_qm_dqlock_nowait(xfs_dquot_t *); | 177 | extern int xfs_qm_dqlock_nowait(xfs_dquot_t *); |
| 170 | extern int xfs_qm_dqflock_nowait(xfs_dquot_t *); | ||
| 171 | extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp); | 178 | extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp); |
| 172 | extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, | 179 | extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, |
| 173 | xfs_disk_dquot_t *); | 180 | xfs_disk_dquot_t *); |
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 36e05ca78412..f028644caa5e 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c | |||
| @@ -151,7 +151,7 @@ xfs_qm_dquot_logitem_push( | |||
| 151 | dqp = logitem->qli_dquot; | 151 | dqp = logitem->qli_dquot; |
| 152 | 152 | ||
| 153 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); | 153 | ASSERT(XFS_DQ_IS_LOCKED(dqp)); |
| 154 | ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); | 154 | ASSERT(!completion_done(&dqp->q_flush)); |
| 155 | 155 | ||
| 156 | /* | 156 | /* |
| 157 | * Since we were able to lock the dquot's flush lock and | 157 | * Since we were able to lock the dquot's flush lock and |
| @@ -245,7 +245,7 @@ xfs_qm_dquot_logitem_pushbuf( | |||
| 245 | * inode flush completed and the inode was taken off the AIL. | 245 | * inode flush completed and the inode was taken off the AIL. |
| 246 | * So, just get out. | 246 | * So, just get out. |
| 247 | */ | 247 | */ |
| 248 | if (!issemalocked(&(dqp->q_flock)) || | 248 | if (completion_done(&dqp->q_flush) || |
| 249 | ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { | 249 | ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { |
| 250 | qip->qli_pushbuf_flag = 0; | 250 | qip->qli_pushbuf_flag = 0; |
| 251 | xfs_dqunlock(dqp); | 251 | xfs_dqunlock(dqp); |
| @@ -258,7 +258,7 @@ xfs_qm_dquot_logitem_pushbuf( | |||
| 258 | if (bp != NULL) { | 258 | if (bp != NULL) { |
| 259 | if (XFS_BUF_ISDELAYWRITE(bp)) { | 259 | if (XFS_BUF_ISDELAYWRITE(bp)) { |
| 260 | dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && | 260 | dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && |
| 261 | issemalocked(&(dqp->q_flock))); | 261 | !completion_done(&dqp->q_flush)); |
| 262 | qip->qli_pushbuf_flag = 0; | 262 | qip->qli_pushbuf_flag = 0; |
| 263 | xfs_dqunlock(dqp); | 263 | xfs_dqunlock(dqp); |
| 264 | 264 | ||
| @@ -317,7 +317,7 @@ xfs_qm_dquot_logitem_trylock( | |||
| 317 | return (XFS_ITEM_LOCKED); | 317 | return (XFS_ITEM_LOCKED); |
| 318 | 318 | ||
| 319 | retval = XFS_ITEM_SUCCESS; | 319 | retval = XFS_ITEM_SUCCESS; |
| 320 | if (! xfs_qm_dqflock_nowait(dqp)) { | 320 | if (!xfs_dqflock_nowait(dqp)) { |
| 321 | /* | 321 | /* |
| 322 | * The dquot is already being flushed. It may have been | 322 | * The dquot is already being flushed. It may have been |
| 323 | * flushed delayed write, however, and we don't want to | 323 | * flushed delayed write, however, and we don't want to |
| @@ -576,8 +576,8 @@ xfs_qm_qoffend_logitem_committed( | |||
| 576 | * xfs_trans_delete_ail() drops the AIL lock. | 576 | * xfs_trans_delete_ail() drops the AIL lock. |
| 577 | */ | 577 | */ |
| 578 | xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs); | 578 | xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs); |
| 579 | kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); | 579 | kmem_free(qfs); |
| 580 | kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); | 580 | kmem_free(qfe); |
| 581 | return (xfs_lsn_t)-1; | 581 | return (xfs_lsn_t)-1; |
| 582 | } | 582 | } |
| 583 | 583 | ||
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index d31cce1165c5..df0ffef9775a 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
| @@ -192,8 +192,8 @@ xfs_qm_destroy( | |||
| 192 | xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); | 192 | xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); |
| 193 | xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); | 193 | xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); |
| 194 | } | 194 | } |
| 195 | kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t)); | 195 | kmem_free(xqm->qm_usr_dqhtable); |
| 196 | kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t)); | 196 | kmem_free(xqm->qm_grp_dqhtable); |
| 197 | xqm->qm_usr_dqhtable = NULL; | 197 | xqm->qm_usr_dqhtable = NULL; |
| 198 | xqm->qm_grp_dqhtable = NULL; | 198 | xqm->qm_grp_dqhtable = NULL; |
| 199 | xqm->qm_dqhashmask = 0; | 199 | xqm->qm_dqhashmask = 0; |
| @@ -201,7 +201,7 @@ xfs_qm_destroy( | |||
| 201 | #ifdef DEBUG | 201 | #ifdef DEBUG |
| 202 | mutex_destroy(&qcheck_lock); | 202 | mutex_destroy(&qcheck_lock); |
| 203 | #endif | 203 | #endif |
| 204 | kmem_free(xqm, sizeof(xfs_qm_t)); | 204 | kmem_free(xqm); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | /* | 207 | /* |
| @@ -310,8 +310,7 @@ xfs_qm_unmount_quotadestroy( | |||
| 310 | */ | 310 | */ |
| 311 | void | 311 | void |
| 312 | xfs_qm_mount_quotas( | 312 | xfs_qm_mount_quotas( |
| 313 | xfs_mount_t *mp, | 313 | xfs_mount_t *mp) |
| 314 | int mfsi_flags) | ||
| 315 | { | 314 | { |
| 316 | int error = 0; | 315 | int error = 0; |
| 317 | uint sbf; | 316 | uint sbf; |
| @@ -346,8 +345,7 @@ xfs_qm_mount_quotas( | |||
| 346 | /* | 345 | /* |
| 347 | * If any of the quotas are not consistent, do a quotacheck. | 346 | * If any of the quotas are not consistent, do a quotacheck. |
| 348 | */ | 347 | */ |
| 349 | if (XFS_QM_NEED_QUOTACHECK(mp) && | 348 | if (XFS_QM_NEED_QUOTACHECK(mp)) { |
| 350 | !(mfsi_flags & XFS_MFSI_NO_QUOTACHECK)) { | ||
| 351 | error = xfs_qm_quotacheck(mp); | 349 | error = xfs_qm_quotacheck(mp); |
| 352 | if (error) { | 350 | if (error) { |
| 353 | /* Quotacheck failed and disabled quotas. */ | 351 | /* Quotacheck failed and disabled quotas. */ |
| @@ -445,11 +443,11 @@ xfs_qm_unmount_quotas( | |||
| 445 | } | 443 | } |
| 446 | } | 444 | } |
| 447 | if (uqp) { | 445 | if (uqp) { |
| 448 | XFS_PURGE_INODE(uqp); | 446 | IRELE(uqp); |
| 449 | mp->m_quotainfo->qi_uquotaip = NULL; | 447 | mp->m_quotainfo->qi_uquotaip = NULL; |
| 450 | } | 448 | } |
| 451 | if (gqp) { | 449 | if (gqp) { |
| 452 | XFS_PURGE_INODE(gqp); | 450 | IRELE(gqp); |
| 453 | mp->m_quotainfo->qi_gquotaip = NULL; | 451 | mp->m_quotainfo->qi_gquotaip = NULL; |
| 454 | } | 452 | } |
| 455 | out: | 453 | out: |
| @@ -484,7 +482,7 @@ again: | |||
| 484 | xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY"); | 482 | xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY"); |
| 485 | /* XXX a sentinel would be better */ | 483 | /* XXX a sentinel would be better */ |
| 486 | recl = XFS_QI_MPLRECLAIMS(mp); | 484 | recl = XFS_QI_MPLRECLAIMS(mp); |
| 487 | if (! xfs_qm_dqflock_nowait(dqp)) { | 485 | if (!xfs_dqflock_nowait(dqp)) { |
| 488 | /* | 486 | /* |
| 489 | * If we can't grab the flush lock then check | 487 | * If we can't grab the flush lock then check |
| 490 | * to see if the dquot has been flushed delayed | 488 | * to see if the dquot has been flushed delayed |
| @@ -631,7 +629,7 @@ xfs_qm_dqpurge_int( | |||
| 631 | * freelist in INACTIVE state. | 629 | * freelist in INACTIVE state. |
| 632 | */ | 630 | */ |
| 633 | nextdqp = dqp->MPL_NEXT; | 631 | nextdqp = dqp->MPL_NEXT; |
| 634 | nmisses += xfs_qm_dqpurge(dqp, flags); | 632 | nmisses += xfs_qm_dqpurge(dqp); |
| 635 | dqp = nextdqp; | 633 | dqp = nextdqp; |
| 636 | } | 634 | } |
| 637 | xfs_qm_mplist_unlock(mp); | 635 | xfs_qm_mplist_unlock(mp); |
| @@ -1062,7 +1060,7 @@ xfs_qm_sync( | |||
| 1062 | 1060 | ||
| 1063 | /* XXX a sentinel would be better */ | 1061 | /* XXX a sentinel would be better */ |
| 1064 | recl = XFS_QI_MPLRECLAIMS(mp); | 1062 | recl = XFS_QI_MPLRECLAIMS(mp); |
| 1065 | if (! xfs_qm_dqflock_nowait(dqp)) { | 1063 | if (!xfs_dqflock_nowait(dqp)) { |
| 1066 | if (nowait) { | 1064 | if (nowait) { |
| 1067 | xfs_dqunlock(dqp); | 1065 | xfs_dqunlock(dqp); |
| 1068 | continue; | 1066 | continue; |
| @@ -1134,7 +1132,7 @@ xfs_qm_init_quotainfo( | |||
| 1134 | * and change the superblock accordingly. | 1132 | * and change the superblock accordingly. |
| 1135 | */ | 1133 | */ |
| 1136 | if ((error = xfs_qm_init_quotainos(mp))) { | 1134 | if ((error = xfs_qm_init_quotainos(mp))) { |
| 1137 | kmem_free(qinf, sizeof(xfs_quotainfo_t)); | 1135 | kmem_free(qinf); |
| 1138 | mp->m_quotainfo = NULL; | 1136 | mp->m_quotainfo = NULL; |
| 1139 | return error; | 1137 | return error; |
| 1140 | } | 1138 | } |
| @@ -1240,15 +1238,15 @@ xfs_qm_destroy_quotainfo( | |||
| 1240 | xfs_qm_list_destroy(&qi->qi_dqlist); | 1238 | xfs_qm_list_destroy(&qi->qi_dqlist); |
| 1241 | 1239 | ||
| 1242 | if (qi->qi_uquotaip) { | 1240 | if (qi->qi_uquotaip) { |
| 1243 | XFS_PURGE_INODE(qi->qi_uquotaip); | 1241 | IRELE(qi->qi_uquotaip); |
| 1244 | qi->qi_uquotaip = NULL; /* paranoia */ | 1242 | qi->qi_uquotaip = NULL; /* paranoia */ |
| 1245 | } | 1243 | } |
| 1246 | if (qi->qi_gquotaip) { | 1244 | if (qi->qi_gquotaip) { |
| 1247 | XFS_PURGE_INODE(qi->qi_gquotaip); | 1245 | IRELE(qi->qi_gquotaip); |
| 1248 | qi->qi_gquotaip = NULL; | 1246 | qi->qi_gquotaip = NULL; |
| 1249 | } | 1247 | } |
| 1250 | mutex_destroy(&qi->qi_quotaofflock); | 1248 | mutex_destroy(&qi->qi_quotaofflock); |
| 1251 | kmem_free(qi, sizeof(xfs_quotainfo_t)); | 1249 | kmem_free(qi); |
| 1252 | mp->m_quotainfo = NULL; | 1250 | mp->m_quotainfo = NULL; |
| 1253 | } | 1251 | } |
| 1254 | 1252 | ||
| @@ -1394,7 +1392,7 @@ xfs_qm_qino_alloc( | |||
| 1394 | * locked exclusively and joined to the transaction already. | 1392 | * locked exclusively and joined to the transaction already. |
| 1395 | */ | 1393 | */ |
| 1396 | ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL)); | 1394 | ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL)); |
| 1397 | VN_HOLD(XFS_ITOV((*ip))); | 1395 | IHOLD(*ip); |
| 1398 | 1396 | ||
| 1399 | /* | 1397 | /* |
| 1400 | * Make the changes in the superblock, and log those too. | 1398 | * Make the changes in the superblock, and log those too. |
| @@ -1623,7 +1621,7 @@ xfs_qm_dqiterate( | |||
| 1623 | break; | 1621 | break; |
| 1624 | } while (nmaps > 0); | 1622 | } while (nmaps > 0); |
| 1625 | 1623 | ||
| 1626 | kmem_free(map, XFS_DQITER_MAP_SIZE * sizeof(*map)); | 1624 | kmem_free(map); |
| 1627 | 1625 | ||
| 1628 | return error; | 1626 | return error; |
| 1629 | } | 1627 | } |
| @@ -2079,7 +2077,7 @@ xfs_qm_shake_freelist( | |||
| 2079 | * Try to grab the flush lock. If this dquot is in the process of | 2077 | * Try to grab the flush lock. If this dquot is in the process of |
| 2080 | * getting flushed to disk, we don't want to reclaim it. | 2078 | * getting flushed to disk, we don't want to reclaim it. |
| 2081 | */ | 2079 | */ |
| 2082 | if (! xfs_qm_dqflock_nowait(dqp)) { | 2080 | if (!xfs_dqflock_nowait(dqp)) { |
| 2083 | xfs_dqunlock(dqp); | 2081 | xfs_dqunlock(dqp); |
| 2084 | dqp = dqp->dq_flnext; | 2082 | dqp = dqp->dq_flnext; |
| 2085 | continue; | 2083 | continue; |
| @@ -2257,7 +2255,7 @@ xfs_qm_dqreclaim_one(void) | |||
| 2257 | * Try to grab the flush lock. If this dquot is in the process of | 2255 | * Try to grab the flush lock. If this dquot is in the process of |
| 2258 | * getting flushed to disk, we don't want to reclaim it. | 2256 | * getting flushed to disk, we don't want to reclaim it. |
| 2259 | */ | 2257 | */ |
| 2260 | if (! xfs_qm_dqflock_nowait(dqp)) { | 2258 | if (!xfs_dqflock_nowait(dqp)) { |
| 2261 | xfs_dqunlock(dqp); | 2259 | xfs_dqunlock(dqp); |
| 2262 | continue; | 2260 | continue; |
| 2263 | } | 2261 | } |
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h index cd2300e374af..44f25349e478 100644 --- a/fs/xfs/quota/xfs_qm.h +++ b/fs/xfs/quota/xfs_qm.h | |||
| @@ -165,7 +165,7 @@ typedef struct xfs_dquot_acct { | |||
| 165 | #define XFS_QM_RELE(xqm) ((xqm)->qm_nrefs--) | 165 | #define XFS_QM_RELE(xqm) ((xqm)->qm_nrefs--) |
| 166 | 166 | ||
| 167 | extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); | 167 | extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); |
| 168 | extern void xfs_qm_mount_quotas(xfs_mount_t *, int); | 168 | extern void xfs_qm_mount_quotas(xfs_mount_t *); |
| 169 | extern int xfs_qm_quotacheck(xfs_mount_t *); | 169 | extern int xfs_qm_quotacheck(xfs_mount_t *); |
| 170 | extern void xfs_qm_unmount_quotadestroy(xfs_mount_t *); | 170 | extern void xfs_qm_unmount_quotadestroy(xfs_mount_t *); |
| 171 | extern int xfs_qm_unmount_quotas(xfs_mount_t *); | 171 | extern int xfs_qm_unmount_quotas(xfs_mount_t *); |
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index f4f6c4c861d7..eea2e60b456b 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c | |||
| @@ -162,7 +162,7 @@ xfs_qm_newmount( | |||
| 162 | * mounting, and get on with the boring life | 162 | * mounting, and get on with the boring life |
| 163 | * without disk quotas. | 163 | * without disk quotas. |
| 164 | */ | 164 | */ |
| 165 | xfs_qm_mount_quotas(mp, 0); | 165 | xfs_qm_mount_quotas(mp); |
| 166 | } else { | 166 | } else { |
| 167 | /* | 167 | /* |
| 168 | * Clear the quota flags, but remember them. This | 168 | * Clear the quota flags, but remember them. This |
| @@ -184,13 +184,12 @@ STATIC int | |||
| 184 | xfs_qm_endmount( | 184 | xfs_qm_endmount( |
| 185 | xfs_mount_t *mp, | 185 | xfs_mount_t *mp, |
| 186 | uint needquotamount, | 186 | uint needquotamount, |
| 187 | uint quotaflags, | 187 | uint quotaflags) |
| 188 | int mfsi_flags) | ||
| 189 | { | 188 | { |
| 190 | if (needquotamount) { | 189 | if (needquotamount) { |
| 191 | ASSERT(mp->m_qflags == 0); | 190 | ASSERT(mp->m_qflags == 0); |
| 192 | mp->m_qflags = quotaflags; | 191 | mp->m_qflags = quotaflags; |
| 193 | xfs_qm_mount_quotas(mp, mfsi_flags); | 192 | xfs_qm_mount_quotas(mp); |
| 194 | } | 193 | } |
| 195 | 194 | ||
| 196 | #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) | 195 | #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) |
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 768a3b27d2b6..1a3b803dfa55 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c | |||
| @@ -362,11 +362,11 @@ xfs_qm_scall_quotaoff( | |||
| 362 | * if we don't need them anymore. | 362 | * if we don't need them anymore. |
| 363 | */ | 363 | */ |
| 364 | if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) { | 364 | if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) { |
| 365 | XFS_PURGE_INODE(XFS_QI_UQIP(mp)); | 365 | IRELE(XFS_QI_UQIP(mp)); |
| 366 | XFS_QI_UQIP(mp) = NULL; | 366 | XFS_QI_UQIP(mp) = NULL; |
| 367 | } | 367 | } |
| 368 | if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) { | 368 | if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && XFS_QI_GQIP(mp)) { |
| 369 | XFS_PURGE_INODE(XFS_QI_GQIP(mp)); | 369 | IRELE(XFS_QI_GQIP(mp)); |
| 370 | XFS_QI_GQIP(mp) = NULL; | 370 | XFS_QI_GQIP(mp) = NULL; |
| 371 | } | 371 | } |
| 372 | out_error: | 372 | out_error: |
| @@ -1034,7 +1034,7 @@ xfs_qm_dqrele_all_inodes( | |||
| 1034 | { | 1034 | { |
| 1035 | xfs_inode_t *ip, *topino; | 1035 | xfs_inode_t *ip, *topino; |
| 1036 | uint ireclaims; | 1036 | uint ireclaims; |
| 1037 | bhv_vnode_t *vp; | 1037 | struct inode *vp; |
| 1038 | boolean_t vnode_refd; | 1038 | boolean_t vnode_refd; |
| 1039 | 1039 | ||
| 1040 | ASSERT(mp->m_quotainfo); | 1040 | ASSERT(mp->m_quotainfo); |
| @@ -1059,7 +1059,7 @@ again: | |||
| 1059 | ip = ip->i_mnext; | 1059 | ip = ip->i_mnext; |
| 1060 | continue; | 1060 | continue; |
| 1061 | } | 1061 | } |
| 1062 | vp = XFS_ITOV_NULL(ip); | 1062 | vp = VFS_I(ip); |
| 1063 | if (!vp) { | 1063 | if (!vp) { |
| 1064 | ASSERT(ip->i_udquot == NULL); | 1064 | ASSERT(ip->i_udquot == NULL); |
| 1065 | ASSERT(ip->i_gdquot == NULL); | 1065 | ASSERT(ip->i_gdquot == NULL); |
| @@ -1449,14 +1449,14 @@ xfs_qm_internalqcheck( | |||
| 1449 | for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { | 1449 | for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { |
| 1450 | xfs_dqtest_cmp(d); | 1450 | xfs_dqtest_cmp(d); |
| 1451 | e = (xfs_dqtest_t *) d->HL_NEXT; | 1451 | e = (xfs_dqtest_t *) d->HL_NEXT; |
| 1452 | kmem_free(d, sizeof(xfs_dqtest_t)); | 1452 | kmem_free(d); |
| 1453 | d = e; | 1453 | d = e; |
| 1454 | } | 1454 | } |
| 1455 | h1 = &qmtest_gdqtab[i]; | 1455 | h1 = &qmtest_gdqtab[i]; |
| 1456 | for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { | 1456 | for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { |
| 1457 | xfs_dqtest_cmp(d); | 1457 | xfs_dqtest_cmp(d); |
| 1458 | e = (xfs_dqtest_t *) d->HL_NEXT; | 1458 | e = (xfs_dqtest_t *) d->HL_NEXT; |
| 1459 | kmem_free(d, sizeof(xfs_dqtest_t)); | 1459 | kmem_free(d); |
| 1460 | d = e; | 1460 | d = e; |
| 1461 | } | 1461 | } |
| 1462 | } | 1462 | } |
| @@ -1467,8 +1467,8 @@ xfs_qm_internalqcheck( | |||
| 1467 | } else { | 1467 | } else { |
| 1468 | cmn_err(CE_DEBUG, "******** quotacheck successful! ********"); | 1468 | cmn_err(CE_DEBUG, "******** quotacheck successful! ********"); |
| 1469 | } | 1469 | } |
| 1470 | kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); | 1470 | kmem_free(qmtest_udqtab); |
| 1471 | kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); | 1471 | kmem_free(qmtest_gdqtab); |
| 1472 | mutex_unlock(&qcheck_lock); | 1472 | mutex_unlock(&qcheck_lock); |
| 1473 | return (qmtest_nfails); | 1473 | return (qmtest_nfails); |
| 1474 | } | 1474 | } |
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h index 5e4a40b1c565..c4fcea600bc2 100644 --- a/fs/xfs/quota/xfs_quota_priv.h +++ b/fs/xfs/quota/xfs_quota_priv.h | |||
| @@ -158,9 +158,6 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \ | |||
| 158 | #define XFS_IS_SUSER_DQUOT(dqp) \ | 158 | #define XFS_IS_SUSER_DQUOT(dqp) \ |
| 159 | (!((dqp)->q_core.d_id)) | 159 | (!((dqp)->q_core.d_id)) |
| 160 | 160 | ||
| 161 | #define XFS_PURGE_INODE(ip) \ | ||
| 162 | IRELE(ip); | ||
| 163 | |||
| 164 | #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ | 161 | #define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ |
| 165 | (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \ | 162 | (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \ |
| 166 | (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???"))) | 163 | (((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???"))) |
diff --git a/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c index 0b75d302508f..a34ef05489b1 100644 --- a/fs/xfs/support/ktrace.c +++ b/fs/xfs/support/ktrace.c | |||
| @@ -89,7 +89,7 @@ ktrace_alloc(int nentries, unsigned int __nocast sleep) | |||
| 89 | if (sleep & KM_SLEEP) | 89 | if (sleep & KM_SLEEP) |
| 90 | panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); | 90 | panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); |
| 91 | 91 | ||
| 92 | kmem_free(ktp, sizeof(*ktp)); | 92 | kmem_free(ktp); |
| 93 | 93 | ||
| 94 | return NULL; | 94 | return NULL; |
| 95 | } | 95 | } |
| @@ -126,7 +126,7 @@ ktrace_free(ktrace_t *ktp) | |||
| 126 | } else { | 126 | } else { |
| 127 | entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t)); | 127 | entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t)); |
| 128 | 128 | ||
| 129 | kmem_free(ktp->kt_entries, entries_size); | 129 | kmem_free(ktp->kt_entries); |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | kmem_zone_free(ktrace_hdr_zone, ktp); | 132 | kmem_zone_free(ktrace_hdr_zone, ktp); |
diff --git a/fs/xfs/support/uuid.c b/fs/xfs/support/uuid.c index 493a6ecf8590..5830c040ea7e 100644 --- a/fs/xfs/support/uuid.c +++ b/fs/xfs/support/uuid.c | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | */ | 17 | */ |
| 18 | #include <xfs.h> | 18 | #include <xfs.h> |
| 19 | 19 | ||
| 20 | static mutex_t uuid_monitor; | 20 | static DEFINE_MUTEX(uuid_monitor); |
| 21 | static int uuid_table_size; | 21 | static int uuid_table_size; |
| 22 | static uuid_t *uuid_table; | 22 | static uuid_t *uuid_table; |
| 23 | 23 | ||
| @@ -132,9 +132,3 @@ uuid_table_remove(uuid_t *uuid) | |||
| 132 | ASSERT(i < uuid_table_size); | 132 | ASSERT(i < uuid_table_size); |
| 133 | mutex_unlock(&uuid_monitor); | 133 | mutex_unlock(&uuid_monitor); |
| 134 | } | 134 | } |
| 135 | |||
| 136 | void __init | ||
| 137 | uuid_init(void) | ||
| 138 | { | ||
| 139 | mutex_init(&uuid_monitor); | ||
| 140 | } | ||
diff --git a/fs/xfs/support/uuid.h b/fs/xfs/support/uuid.h index b6f5922199ba..cff5b607d445 100644 --- a/fs/xfs/support/uuid.h +++ b/fs/xfs/support/uuid.h | |||
| @@ -22,7 +22,6 @@ typedef struct { | |||
| 22 | unsigned char __u_bits[16]; | 22 | unsigned char __u_bits[16]; |
| 23 | } uuid_t; | 23 | } uuid_t; |
| 24 | 24 | ||
| 25 | extern void uuid_init(void); | ||
| 26 | extern void uuid_create_nil(uuid_t *uuid); | 25 | extern void uuid_create_nil(uuid_t *uuid); |
| 27 | extern int uuid_is_nil(uuid_t *uuid); | 26 | extern int uuid_is_nil(uuid_t *uuid); |
| 28 | extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); | 27 | extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); |
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index ebee3a4f703a..b2f639a1416f 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c | |||
| @@ -37,15 +37,15 @@ | |||
| 37 | #include <linux/capability.h> | 37 | #include <linux/capability.h> |
| 38 | #include <linux/posix_acl_xattr.h> | 38 | #include <linux/posix_acl_xattr.h> |
| 39 | 39 | ||
| 40 | STATIC int xfs_acl_setmode(bhv_vnode_t *, xfs_acl_t *, int *); | 40 | STATIC int xfs_acl_setmode(struct inode *, xfs_acl_t *, int *); |
| 41 | STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); | 41 | STATIC void xfs_acl_filter_mode(mode_t, xfs_acl_t *); |
| 42 | STATIC void xfs_acl_get_endian(xfs_acl_t *); | 42 | STATIC void xfs_acl_get_endian(xfs_acl_t *); |
| 43 | STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); | 43 | STATIC int xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *); |
| 44 | STATIC int xfs_acl_invalid(xfs_acl_t *); | 44 | STATIC int xfs_acl_invalid(xfs_acl_t *); |
| 45 | STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); | 45 | STATIC void xfs_acl_sync_mode(mode_t, xfs_acl_t *); |
| 46 | STATIC void xfs_acl_get_attr(bhv_vnode_t *, xfs_acl_t *, int, int, int *); | 46 | STATIC void xfs_acl_get_attr(struct inode *, xfs_acl_t *, int, int, int *); |
| 47 | STATIC void xfs_acl_set_attr(bhv_vnode_t *, xfs_acl_t *, int, int *); | 47 | STATIC void xfs_acl_set_attr(struct inode *, xfs_acl_t *, int, int *); |
| 48 | STATIC int xfs_acl_allow_set(bhv_vnode_t *, int); | 48 | STATIC int xfs_acl_allow_set(struct inode *, int); |
| 49 | 49 | ||
| 50 | kmem_zone_t *xfs_acl_zone; | 50 | kmem_zone_t *xfs_acl_zone; |
| 51 | 51 | ||
| @@ -55,7 +55,7 @@ kmem_zone_t *xfs_acl_zone; | |||
| 55 | */ | 55 | */ |
| 56 | int | 56 | int |
| 57 | xfs_acl_vhasacl_access( | 57 | xfs_acl_vhasacl_access( |
| 58 | bhv_vnode_t *vp) | 58 | struct inode *vp) |
| 59 | { | 59 | { |
| 60 | int error; | 60 | int error; |
| 61 | 61 | ||
| @@ -68,7 +68,7 @@ xfs_acl_vhasacl_access( | |||
| 68 | */ | 68 | */ |
| 69 | int | 69 | int |
| 70 | xfs_acl_vhasacl_default( | 70 | xfs_acl_vhasacl_default( |
| 71 | bhv_vnode_t *vp) | 71 | struct inode *vp) |
| 72 | { | 72 | { |
| 73 | int error; | 73 | int error; |
| 74 | 74 | ||
| @@ -207,7 +207,7 @@ posix_acl_xfs_to_xattr( | |||
| 207 | 207 | ||
| 208 | int | 208 | int |
| 209 | xfs_acl_vget( | 209 | xfs_acl_vget( |
| 210 | bhv_vnode_t *vp, | 210 | struct inode *vp, |
| 211 | void *acl, | 211 | void *acl, |
| 212 | size_t size, | 212 | size_t size, |
| 213 | int kind) | 213 | int kind) |
| @@ -217,7 +217,6 @@ xfs_acl_vget( | |||
| 217 | posix_acl_xattr_header *ext_acl = acl; | 217 | posix_acl_xattr_header *ext_acl = acl; |
| 218 | int flags = 0; | 218 | int flags = 0; |
| 219 | 219 | ||
| 220 | VN_HOLD(vp); | ||
| 221 | if(size) { | 220 | if(size) { |
| 222 | if (!(_ACL_ALLOC(xfs_acl))) { | 221 | if (!(_ACL_ALLOC(xfs_acl))) { |
| 223 | error = ENOMEM; | 222 | error = ENOMEM; |
| @@ -239,11 +238,10 @@ xfs_acl_vget( | |||
| 239 | goto out; | 238 | goto out; |
| 240 | } | 239 | } |
| 241 | if (kind == _ACL_TYPE_ACCESS) | 240 | if (kind == _ACL_TYPE_ACCESS) |
| 242 | xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, xfs_acl); | 241 | xfs_acl_sync_mode(XFS_I(vp)->i_d.di_mode, xfs_acl); |
| 243 | error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); | 242 | error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size); |
| 244 | } | 243 | } |
| 245 | out: | 244 | out: |
| 246 | VN_RELE(vp); | ||
| 247 | if(xfs_acl) | 245 | if(xfs_acl) |
| 248 | _ACL_FREE(xfs_acl); | 246 | _ACL_FREE(xfs_acl); |
| 249 | return -error; | 247 | return -error; |
| @@ -251,28 +249,26 @@ out: | |||
| 251 | 249 | ||
| 252 | int | 250 | int |
| 253 | xfs_acl_vremove( | 251 | xfs_acl_vremove( |
| 254 | bhv_vnode_t *vp, | 252 | struct inode *vp, |
| 255 | int kind) | 253 | int kind) |
| 256 | { | 254 | { |
| 257 | int error; | 255 | int error; |
| 258 | 256 | ||
| 259 | VN_HOLD(vp); | ||
| 260 | error = xfs_acl_allow_set(vp, kind); | 257 | error = xfs_acl_allow_set(vp, kind); |
| 261 | if (!error) { | 258 | if (!error) { |
| 262 | error = xfs_attr_remove(xfs_vtoi(vp), | 259 | error = xfs_attr_remove(XFS_I(vp), |
| 263 | kind == _ACL_TYPE_DEFAULT? | 260 | kind == _ACL_TYPE_DEFAULT? |
| 264 | SGI_ACL_DEFAULT: SGI_ACL_FILE, | 261 | SGI_ACL_DEFAULT: SGI_ACL_FILE, |
| 265 | ATTR_ROOT); | 262 | ATTR_ROOT); |
| 266 | if (error == ENOATTR) | 263 | if (error == ENOATTR) |
| 267 | error = 0; /* 'scool */ | 264 | error = 0; /* 'scool */ |
| 268 | } | 265 | } |
| 269 | VN_RELE(vp); | ||
| 270 | return -error; | 266 | return -error; |
| 271 | } | 267 | } |
| 272 | 268 | ||
| 273 | int | 269 | int |
| 274 | xfs_acl_vset( | 270 | xfs_acl_vset( |
| 275 | bhv_vnode_t *vp, | 271 | struct inode *vp, |
| 276 | void *acl, | 272 | void *acl, |
| 277 | size_t size, | 273 | size_t size, |
| 278 | int kind) | 274 | int kind) |
| @@ -298,7 +294,6 @@ xfs_acl_vset( | |||
| 298 | return 0; | 294 | return 0; |
| 299 | } | 295 | } |
| 300 | 296 | ||
| 301 | VN_HOLD(vp); | ||
| 302 | error = xfs_acl_allow_set(vp, kind); | 297 | error = xfs_acl_allow_set(vp, kind); |
| 303 | 298 | ||
| 304 | /* Incoming ACL exists, set file mode based on its value */ | 299 | /* Incoming ACL exists, set file mode based on its value */ |
| @@ -321,7 +316,6 @@ xfs_acl_vset( | |||
| 321 | } | 316 | } |
| 322 | 317 | ||
| 323 | out: | 318 | out: |
| 324 | VN_RELE(vp); | ||
| 325 | _ACL_FREE(xfs_acl); | 319 | _ACL_FREE(xfs_acl); |
| 326 | return -error; | 320 | return -error; |
| 327 | } | 321 | } |
| @@ -341,8 +335,7 @@ xfs_acl_iaccess( | |||
| 341 | 335 | ||
| 342 | /* If the file has no ACL return -1. */ | 336 | /* If the file has no ACL return -1. */ |
| 343 | rval = sizeof(xfs_acl_t); | 337 | rval = sizeof(xfs_acl_t); |
| 344 | if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, | 338 | if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval, ATTR_ROOT)) { |
| 345 | ATTR_ROOT | ATTR_KERNACCESS)) { | ||
| 346 | _ACL_FREE(acl); | 339 | _ACL_FREE(acl); |
| 347 | return -1; | 340 | return -1; |
| 348 | } | 341 | } |
| @@ -364,7 +357,7 @@ xfs_acl_iaccess( | |||
| 364 | 357 | ||
| 365 | STATIC int | 358 | STATIC int |
| 366 | xfs_acl_allow_set( | 359 | xfs_acl_allow_set( |
| 367 | bhv_vnode_t *vp, | 360 | struct inode *vp, |
| 368 | int kind) | 361 | int kind) |
| 369 | { | 362 | { |
| 370 | if (vp->i_flags & (S_IMMUTABLE|S_APPEND)) | 363 | if (vp->i_flags & (S_IMMUTABLE|S_APPEND)) |
| @@ -373,7 +366,7 @@ xfs_acl_allow_set( | |||
| 373 | return ENOTDIR; | 366 | return ENOTDIR; |
| 374 | if (vp->i_sb->s_flags & MS_RDONLY) | 367 | if (vp->i_sb->s_flags & MS_RDONLY) |
| 375 | return EROFS; | 368 | return EROFS; |
| 376 | if (xfs_vtoi(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER)) | 369 | if (XFS_I(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER)) |
| 377 | return EPERM; | 370 | return EPERM; |
| 378 | return 0; | 371 | return 0; |
| 379 | } | 372 | } |
| @@ -567,7 +560,7 @@ xfs_acl_get_endian( | |||
| 567 | */ | 560 | */ |
| 568 | STATIC void | 561 | STATIC void |
| 569 | xfs_acl_get_attr( | 562 | xfs_acl_get_attr( |
| 570 | bhv_vnode_t *vp, | 563 | struct inode *vp, |
| 571 | xfs_acl_t *aclp, | 564 | xfs_acl_t *aclp, |
| 572 | int kind, | 565 | int kind, |
| 573 | int flags, | 566 | int flags, |
| @@ -577,7 +570,7 @@ xfs_acl_get_attr( | |||
| 577 | 570 | ||
| 578 | ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); | 571 | ASSERT((flags & ATTR_KERNOVAL) ? (aclp == NULL) : 1); |
| 579 | flags |= ATTR_ROOT; | 572 | flags |= ATTR_ROOT; |
| 580 | *error = xfs_attr_get(xfs_vtoi(vp), | 573 | *error = xfs_attr_get(XFS_I(vp), |
| 581 | kind == _ACL_TYPE_ACCESS ? | 574 | kind == _ACL_TYPE_ACCESS ? |
| 582 | SGI_ACL_FILE : SGI_ACL_DEFAULT, | 575 | SGI_ACL_FILE : SGI_ACL_DEFAULT, |
| 583 | (char *)aclp, &len, flags); | 576 | (char *)aclp, &len, flags); |
| @@ -591,7 +584,7 @@ xfs_acl_get_attr( | |||
| 591 | */ | 584 | */ |
| 592 | STATIC void | 585 | STATIC void |
| 593 | xfs_acl_set_attr( | 586 | xfs_acl_set_attr( |
| 594 | bhv_vnode_t *vp, | 587 | struct inode *vp, |
| 595 | xfs_acl_t *aclp, | 588 | xfs_acl_t *aclp, |
| 596 | int kind, | 589 | int kind, |
| 597 | int *error) | 590 | int *error) |
| @@ -616,7 +609,7 @@ xfs_acl_set_attr( | |||
| 616 | INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); | 609 | INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); |
| 617 | } | 610 | } |
| 618 | INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); | 611 | INT_SET(newacl->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); |
| 619 | *error = xfs_attr_set(xfs_vtoi(vp), | 612 | *error = xfs_attr_set(XFS_I(vp), |
| 620 | kind == _ACL_TYPE_ACCESS ? | 613 | kind == _ACL_TYPE_ACCESS ? |
| 621 | SGI_ACL_FILE: SGI_ACL_DEFAULT, | 614 | SGI_ACL_FILE: SGI_ACL_DEFAULT, |
| 622 | (char *)newacl, len, ATTR_ROOT); | 615 | (char *)newacl, len, ATTR_ROOT); |
| @@ -625,7 +618,7 @@ xfs_acl_set_attr( | |||
| 625 | 618 | ||
| 626 | int | 619 | int |
| 627 | xfs_acl_vtoacl( | 620 | xfs_acl_vtoacl( |
| 628 | bhv_vnode_t *vp, | 621 | struct inode *vp, |
| 629 | xfs_acl_t *access_acl, | 622 | xfs_acl_t *access_acl, |
| 630 | xfs_acl_t *default_acl) | 623 | xfs_acl_t *default_acl) |
| 631 | { | 624 | { |
| @@ -640,7 +633,7 @@ xfs_acl_vtoacl( | |||
| 640 | if (error) | 633 | if (error) |
| 641 | access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; | 634 | access_acl->acl_cnt = XFS_ACL_NOT_PRESENT; |
| 642 | else /* We have a good ACL and the file mode, synchronize. */ | 635 | else /* We have a good ACL and the file mode, synchronize. */ |
| 643 | xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, access_acl); | 636 | xfs_acl_sync_mode(XFS_I(vp)->i_d.di_mode, access_acl); |
| 644 | } | 637 | } |
| 645 | 638 | ||
| 646 | if (default_acl) { | 639 | if (default_acl) { |
| @@ -657,7 +650,7 @@ xfs_acl_vtoacl( | |||
| 657 | */ | 650 | */ |
| 658 | int | 651 | int |
| 659 | xfs_acl_inherit( | 652 | xfs_acl_inherit( |
| 660 | bhv_vnode_t *vp, | 653 | struct inode *vp, |
| 661 | mode_t mode, | 654 | mode_t mode, |
| 662 | xfs_acl_t *pdaclp) | 655 | xfs_acl_t *pdaclp) |
| 663 | { | 656 | { |
| @@ -716,11 +709,11 @@ out_error: | |||
| 716 | */ | 709 | */ |
| 717 | STATIC int | 710 | STATIC int |
| 718 | xfs_acl_setmode( | 711 | xfs_acl_setmode( |
| 719 | bhv_vnode_t *vp, | 712 | struct inode *vp, |
| 720 | xfs_acl_t *acl, | 713 | xfs_acl_t *acl, |
| 721 | int *basicperms) | 714 | int *basicperms) |
| 722 | { | 715 | { |
| 723 | bhv_vattr_t va; | 716 | struct iattr iattr; |
| 724 | xfs_acl_entry_t *ap; | 717 | xfs_acl_entry_t *ap; |
| 725 | xfs_acl_entry_t *gap = NULL; | 718 | xfs_acl_entry_t *gap = NULL; |
| 726 | int i, nomask = 1; | 719 | int i, nomask = 1; |
| @@ -734,25 +727,25 @@ xfs_acl_setmode( | |||
| 734 | * Copy the u::, g::, o::, and m:: bits from the ACL into the | 727 | * Copy the u::, g::, o::, and m:: bits from the ACL into the |
| 735 | * mode. The m:: bits take precedence over the g:: bits. | 728 | * mode. The m:: bits take precedence over the g:: bits. |
| 736 | */ | 729 | */ |
| 737 | va.va_mask = XFS_AT_MODE; | 730 | iattr.ia_valid = ATTR_MODE; |
| 738 | va.va_mode = xfs_vtoi(vp)->i_d.di_mode; | 731 | iattr.ia_mode = XFS_I(vp)->i_d.di_mode; |
| 739 | va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); | 732 | iattr.ia_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); |
| 740 | ap = acl->acl_entry; | 733 | ap = acl->acl_entry; |
| 741 | for (i = 0; i < acl->acl_cnt; ++i) { | 734 | for (i = 0; i < acl->acl_cnt; ++i) { |
| 742 | switch (ap->ae_tag) { | 735 | switch (ap->ae_tag) { |
| 743 | case ACL_USER_OBJ: | 736 | case ACL_USER_OBJ: |
| 744 | va.va_mode |= ap->ae_perm << 6; | 737 | iattr.ia_mode |= ap->ae_perm << 6; |
| 745 | break; | 738 | break; |
| 746 | case ACL_GROUP_OBJ: | 739 | case ACL_GROUP_OBJ: |
| 747 | gap = ap; | 740 | gap = ap; |
| 748 | break; | 741 | break; |
| 749 | case ACL_MASK: /* more than just standard modes */ | 742 | case ACL_MASK: /* more than just standard modes */ |
| 750 | nomask = 0; | 743 | nomask = 0; |
| 751 | va.va_mode |= ap->ae_perm << 3; | 744 | iattr.ia_mode |= ap->ae_perm << 3; |
| 752 | *basicperms = 0; | 745 | *basicperms = 0; |
| 753 | break; | 746 | break; |
| 754 | case ACL_OTHER: | 747 | case ACL_OTHER: |
| 755 | va.va_mode |= ap->ae_perm; | 748 | iattr.ia_mode |= ap->ae_perm; |
| 756 | break; | 749 | break; |
| 757 | default: /* more than just standard modes */ | 750 | default: /* more than just standard modes */ |
| 758 | *basicperms = 0; | 751 | *basicperms = 0; |
| @@ -763,9 +756,9 @@ xfs_acl_setmode( | |||
| 763 | 756 | ||
| 764 | /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ | 757 | /* Set the group bits from ACL_GROUP_OBJ if there's no ACL_MASK */ |
| 765 | if (gap && nomask) | 758 | if (gap && nomask) |
| 766 | va.va_mode |= gap->ae_perm << 3; | 759 | iattr.ia_mode |= gap->ae_perm << 3; |
| 767 | 760 | ||
| 768 | return xfs_setattr(xfs_vtoi(vp), &va, 0, sys_cred); | 761 | return xfs_setattr(XFS_I(vp), &iattr, 0, sys_cred); |
| 769 | } | 762 | } |
| 770 | 763 | ||
| 771 | /* | 764 | /* |
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 332a772461c4..a4e293b93efa 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h | |||
| @@ -46,6 +46,8 @@ typedef struct xfs_acl { | |||
| 46 | #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) | 46 | #define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) |
| 47 | #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) | 47 | #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) |
| 48 | 48 | ||
| 49 | #define _ACL_TYPE_ACCESS 1 | ||
| 50 | #define _ACL_TYPE_DEFAULT 2 | ||
| 49 | 51 | ||
| 50 | #ifdef CONFIG_XFS_POSIX_ACL | 52 | #ifdef CONFIG_XFS_POSIX_ACL |
| 51 | 53 | ||
| @@ -57,17 +59,15 @@ extern struct kmem_zone *xfs_acl_zone; | |||
| 57 | (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name)) | 59 | (zone) = kmem_zone_init(sizeof(xfs_acl_t), (name)) |
| 58 | #define xfs_acl_zone_destroy(zone) kmem_zone_destroy(zone) | 60 | #define xfs_acl_zone_destroy(zone) kmem_zone_destroy(zone) |
| 59 | 61 | ||
| 60 | extern int xfs_acl_inherit(bhv_vnode_t *, mode_t mode, xfs_acl_t *); | 62 | extern int xfs_acl_inherit(struct inode *, mode_t mode, xfs_acl_t *); |
| 61 | extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); | 63 | extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); |
| 62 | extern int xfs_acl_vtoacl(bhv_vnode_t *, xfs_acl_t *, xfs_acl_t *); | 64 | extern int xfs_acl_vtoacl(struct inode *, xfs_acl_t *, xfs_acl_t *); |
| 63 | extern int xfs_acl_vhasacl_access(bhv_vnode_t *); | 65 | extern int xfs_acl_vhasacl_access(struct inode *); |
| 64 | extern int xfs_acl_vhasacl_default(bhv_vnode_t *); | 66 | extern int xfs_acl_vhasacl_default(struct inode *); |
| 65 | extern int xfs_acl_vset(bhv_vnode_t *, void *, size_t, int); | 67 | extern int xfs_acl_vset(struct inode *, void *, size_t, int); |
| 66 | extern int xfs_acl_vget(bhv_vnode_t *, void *, size_t, int); | 68 | extern int xfs_acl_vget(struct inode *, void *, size_t, int); |
| 67 | extern int xfs_acl_vremove(bhv_vnode_t *, int); | 69 | extern int xfs_acl_vremove(struct inode *, int); |
| 68 | 70 | ||
| 69 | #define _ACL_TYPE_ACCESS 1 | ||
| 70 | #define _ACL_TYPE_DEFAULT 2 | ||
| 71 | #define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) | 71 | #define _ACL_PERM_INVALID(perm) ((perm) & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) |
| 72 | 72 | ||
| 73 | #define _ACL_INHERIT(c,m,d) (xfs_acl_inherit(c,m,d)) | 73 | #define _ACL_INHERIT(c,m,d) (xfs_acl_inherit(c,m,d)) |
diff --git a/fs/xfs/xfs_arch.h b/fs/xfs/xfs_arch.h index f9472a2076d4..0b3b5efe848c 100644 --- a/fs/xfs/xfs_arch.h +++ b/fs/xfs/xfs_arch.h | |||
| @@ -92,16 +92,6 @@ | |||
| 92 | ((__u8*)(pointer))[1] = (((value) ) & 0xff); \ | 92 | ((__u8*)(pointer))[1] = (((value) ) & 0xff); \ |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | /* define generic INT_ macros */ | ||
| 96 | |||
| 97 | #define INT_GET(reference,arch) \ | ||
| 98 | (((arch) == ARCH_NOCONVERT) \ | ||
| 99 | ? \ | ||
| 100 | (reference) \ | ||
| 101 | : \ | ||
| 102 | INT_SWAP((reference),(reference)) \ | ||
| 103 | ) | ||
| 104 | |||
| 105 | /* does not return a value */ | 95 | /* does not return a value */ |
| 106 | #define INT_SET(reference,arch,valueref) \ | 96 | #define INT_SET(reference,arch,valueref) \ |
| 107 | (__builtin_constant_p(valueref) ? \ | 97 | (__builtin_constant_p(valueref) ? \ |
| @@ -112,64 +102,6 @@ | |||
| 112 | ) \ | 102 | ) \ |
| 113 | ) | 103 | ) |
| 114 | 104 | ||
| 115 | /* does not return a value */ | ||
| 116 | #define INT_MOD_EXPR(reference,arch,code) \ | ||
| 117 | (((arch) == ARCH_NOCONVERT) \ | ||
| 118 | ? \ | ||
| 119 | (void)((reference) code) \ | ||
| 120 | : \ | ||
| 121 | (void)( \ | ||
| 122 | (reference) = INT_GET((reference),arch) , \ | ||
| 123 | ((reference) code), \ | ||
| 124 | INT_SET(reference, arch, reference) \ | ||
| 125 | ) \ | ||
| 126 | ) | ||
| 127 | |||
| 128 | /* does not return a value */ | ||
| 129 | #define INT_MOD(reference,arch,delta) \ | ||
| 130 | (void)( \ | ||
| 131 | INT_MOD_EXPR(reference,arch,+=(delta)) \ | ||
| 132 | ) | ||
| 133 | |||
| 134 | /* | ||
| 135 | * INT_COPY - copy a value between two locations with the | ||
| 136 | * _same architecture_ but _potentially different sizes_ | ||
| 137 | * | ||
| 138 | * if the types of the two parameters are equal or they are | ||
| 139 | * in native architecture, a simple copy is done | ||
| 140 | * | ||
| 141 | * otherwise, architecture conversions are done | ||
| 142 | * | ||
| 143 | */ | ||
| 144 | |||
| 145 | /* does not return a value */ | ||
| 146 | #define INT_COPY(dst,src,arch) \ | ||
| 147 | ( \ | ||
| 148 | ((sizeof(dst) == sizeof(src)) || ((arch) == ARCH_NOCONVERT)) \ | ||
| 149 | ? \ | ||
| 150 | (void)((dst) = (src)) \ | ||
| 151 | : \ | ||
| 152 | INT_SET(dst, arch, INT_GET(src, arch)) \ | ||
| 153 | ) | ||
| 154 | |||
| 155 | /* | ||
| 156 | * INT_XLATE - copy a value in either direction between two locations | ||
| 157 | * with different architectures | ||
| 158 | * | ||
| 159 | * dir < 0 - copy from memory to buffer (native to arch) | ||
| 160 | * dir > 0 - copy from buffer to memory (arch to native) | ||
| 161 | */ | ||
| 162 | |||
| 163 | /* does not return a value */ | ||
| 164 | #define INT_XLATE(buf,mem,dir,arch) {\ | ||
| 165 | ASSERT(dir); \ | ||
| 166 | if (dir>0) { \ | ||
| 167 | (mem)=INT_GET(buf, arch); \ | ||
| 168 | } else { \ | ||
| 169 | INT_SET(buf, arch, mem); \ | ||
| 170 | } \ | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | 105 | /* |
| 174 | * In directories inode numbers are stored as unaligned arrays of unsigned | 106 | * In directories inode numbers are stored as unaligned arrays of unsigned |
| 175 | * 8bit integers on disk. | 107 | * 8bit integers on disk. |
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index df151a859186..f7cdc28aff41 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
| @@ -16,8 +16,6 @@ | |||
| 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <linux/capability.h> | ||
| 20 | |||
| 21 | #include "xfs.h" | 19 | #include "xfs.h" |
| 22 | #include "xfs_fs.h" | 20 | #include "xfs_fs.h" |
| 23 | #include "xfs_types.h" | 21 | #include "xfs_types.h" |
| @@ -57,11 +55,6 @@ | |||
| 57 | * Provide the external interfaces to manage attribute lists. | 55 | * Provide the external interfaces to manage attribute lists. |
| 58 | */ | 56 | */ |
| 59 | 57 | ||
| 60 | #define ATTR_SYSCOUNT 2 | ||
| 61 | static struct attrnames posix_acl_access; | ||
| 62 | static struct attrnames posix_acl_default; | ||
| 63 | static struct attrnames *attr_system_names[ATTR_SYSCOUNT]; | ||
| 64 | |||
| 65 | /*======================================================================== | 58 | /*======================================================================== |
| 66 | * Function prototypes for the kernel. | 59 | * Function prototypes for the kernel. |
| 67 | *========================================================================*/ | 60 | *========================================================================*/ |
| @@ -116,6 +109,17 @@ xfs_attr_name_to_xname( | |||
| 116 | return 0; | 109 | return 0; |
| 117 | } | 110 | } |
| 118 | 111 | ||
| 112 | STATIC int | ||
| 113 | xfs_inode_hasattr( | ||
| 114 | struct xfs_inode *ip) | ||
| 115 | { | ||
| 116 | if (!XFS_IFORK_Q(ip) || | ||
| 117 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 118 | ip->i_d.di_anextents == 0)) | ||
| 119 | return 0; | ||
| 120 | return 1; | ||
| 121 | } | ||
| 122 | |||
| 119 | /*======================================================================== | 123 | /*======================================================================== |
| 120 | * Overall external interface routines. | 124 | * Overall external interface routines. |
| 121 | *========================================================================*/ | 125 | *========================================================================*/ |
| @@ -127,10 +131,8 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name, | |||
| 127 | xfs_da_args_t args; | 131 | xfs_da_args_t args; |
| 128 | int error; | 132 | int error; |
| 129 | 133 | ||
| 130 | if ((XFS_IFORK_Q(ip) == 0) || | 134 | if (!xfs_inode_hasattr(ip)) |
| 131 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | 135 | return ENOATTR; |
| 132 | ip->i_d.di_anextents == 0)) | ||
| 133 | return(ENOATTR); | ||
| 134 | 136 | ||
| 135 | /* | 137 | /* |
| 136 | * Fill in the arg structure for this request. | 138 | * Fill in the arg structure for this request. |
| @@ -148,11 +150,7 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name, | |||
| 148 | /* | 150 | /* |
| 149 | * Decide on what work routines to call based on the inode size. | 151 | * Decide on what work routines to call based on the inode size. |
| 150 | */ | 152 | */ |
| 151 | if (XFS_IFORK_Q(ip) == 0 || | 153 | if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
| 152 | (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 153 | ip->i_d.di_anextents == 0)) { | ||
| 154 | error = XFS_ERROR(ENOATTR); | ||
| 155 | } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | ||
| 156 | error = xfs_attr_shortform_getvalue(&args); | 154 | error = xfs_attr_shortform_getvalue(&args); |
| 157 | } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { | 155 | } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { |
| 158 | error = xfs_attr_leaf_get(&args); | 156 | error = xfs_attr_leaf_get(&args); |
| @@ -196,6 +194,46 @@ xfs_attr_get( | |||
| 196 | return(error); | 194 | return(error); |
| 197 | } | 195 | } |
| 198 | 196 | ||
| 197 | /* | ||
| 198 | * Calculate how many blocks we need for the new attribute, | ||
| 199 | */ | ||
| 200 | int | ||
| 201 | xfs_attr_calc_size( | ||
| 202 | struct xfs_inode *ip, | ||
| 203 | int namelen, | ||
| 204 | int valuelen, | ||
| 205 | int *local) | ||
| 206 | { | ||
| 207 | struct xfs_mount *mp = ip->i_mount; | ||
| 208 | int size; | ||
| 209 | int nblks; | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Determine space new attribute will use, and if it would be | ||
| 213 | * "local" or "remote" (note: local != inline). | ||
| 214 | */ | ||
| 215 | size = xfs_attr_leaf_newentsize(namelen, valuelen, | ||
| 216 | mp->m_sb.sb_blocksize, local); | ||
| 217 | |||
| 218 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
| 219 | if (*local) { | ||
| 220 | if (size > (mp->m_sb.sb_blocksize >> 1)) { | ||
| 221 | /* Double split possible */ | ||
| 222 | nblks *= 2; | ||
| 223 | } | ||
| 224 | } else { | ||
| 225 | /* | ||
| 226 | * Out of line attribute, cannot double split, but | ||
| 227 | * make room for the attribute value itself. | ||
| 228 | */ | ||
| 229 | uint dblocks = XFS_B_TO_FSB(mp, valuelen); | ||
| 230 | nblks += dblocks; | ||
| 231 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
| 232 | } | ||
| 233 | |||
| 234 | return nblks; | ||
| 235 | } | ||
| 236 | |||
| 199 | STATIC int | 237 | STATIC int |
| 200 | xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | 238 | xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, |
| 201 | char *value, int valuelen, int flags) | 239 | char *value, int valuelen, int flags) |
| @@ -204,10 +242,9 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
| 204 | xfs_fsblock_t firstblock; | 242 | xfs_fsblock_t firstblock; |
| 205 | xfs_bmap_free_t flist; | 243 | xfs_bmap_free_t flist; |
| 206 | int error, err2, committed; | 244 | int error, err2, committed; |
| 207 | int local, size; | ||
| 208 | uint nblks; | ||
| 209 | xfs_mount_t *mp = dp->i_mount; | 245 | xfs_mount_t *mp = dp->i_mount; |
| 210 | int rsvd = (flags & ATTR_ROOT) != 0; | 246 | int rsvd = (flags & ATTR_ROOT) != 0; |
| 247 | int local; | ||
| 211 | 248 | ||
| 212 | /* | 249 | /* |
| 213 | * Attach the dquots to the inode. | 250 | * Attach the dquots to the inode. |
| @@ -241,33 +278,10 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
| 241 | args.firstblock = &firstblock; | 278 | args.firstblock = &firstblock; |
| 242 | args.flist = &flist; | 279 | args.flist = &flist; |
| 243 | args.whichfork = XFS_ATTR_FORK; | 280 | args.whichfork = XFS_ATTR_FORK; |
| 244 | args.addname = 1; | 281 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
| 245 | args.oknoent = 1; | ||
| 246 | |||
| 247 | /* | ||
| 248 | * Determine space new attribute will use, and if it would be | ||
| 249 | * "local" or "remote" (note: local != inline). | ||
| 250 | */ | ||
| 251 | size = xfs_attr_leaf_newentsize(name->len, valuelen, | ||
| 252 | mp->m_sb.sb_blocksize, &local); | ||
| 253 | |||
| 254 | nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); | ||
| 255 | if (local) { | ||
| 256 | if (size > (mp->m_sb.sb_blocksize >> 1)) { | ||
| 257 | /* Double split possible */ | ||
| 258 | nblks <<= 1; | ||
| 259 | } | ||
| 260 | } else { | ||
| 261 | uint dblocks = XFS_B_TO_FSB(mp, valuelen); | ||
| 262 | /* Out of line attribute, cannot double split, but make | ||
| 263 | * room for the attribute value itself. | ||
| 264 | */ | ||
| 265 | nblks += dblocks; | ||
| 266 | nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); | ||
| 267 | } | ||
| 268 | 282 | ||
| 269 | /* Size is now blocks for attribute data */ | 283 | /* Size is now blocks for attribute data */ |
| 270 | args.total = nblks; | 284 | args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local); |
| 271 | 285 | ||
| 272 | /* | 286 | /* |
| 273 | * Start our first transaction of the day. | 287 | * Start our first transaction of the day. |
| @@ -289,18 +303,17 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
| 289 | if (rsvd) | 303 | if (rsvd) |
| 290 | args.trans->t_flags |= XFS_TRANS_RESERVE; | 304 | args.trans->t_flags |= XFS_TRANS_RESERVE; |
| 291 | 305 | ||
| 292 | if ((error = xfs_trans_reserve(args.trans, (uint) nblks, | 306 | if ((error = xfs_trans_reserve(args.trans, args.total, |
| 293 | XFS_ATTRSET_LOG_RES(mp, nblks), | 307 | XFS_ATTRSET_LOG_RES(mp, args.total), 0, |
| 294 | 0, XFS_TRANS_PERM_LOG_RES, | 308 | XFS_TRANS_PERM_LOG_RES, XFS_ATTRSET_LOG_COUNT))) { |
| 295 | XFS_ATTRSET_LOG_COUNT))) { | ||
| 296 | xfs_trans_cancel(args.trans, 0); | 309 | xfs_trans_cancel(args.trans, 0); |
| 297 | return(error); | 310 | return(error); |
| 298 | } | 311 | } |
| 299 | xfs_ilock(dp, XFS_ILOCK_EXCL); | 312 | xfs_ilock(dp, XFS_ILOCK_EXCL); |
| 300 | 313 | ||
| 301 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, nblks, 0, | 314 | error = XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, args.trans, dp, args.total, 0, |
| 302 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : | 315 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : |
| 303 | XFS_QMOPT_RES_REGBLKS); | 316 | XFS_QMOPT_RES_REGBLKS); |
| 304 | if (error) { | 317 | if (error) { |
| 305 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 318 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
| 306 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); | 319 | xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); |
| @@ -387,7 +400,9 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name, | |||
| 387 | * Commit the leaf transformation. We'll need another (linked) | 400 | * Commit the leaf transformation. We'll need another (linked) |
| 388 | * transaction to add the new attribute to the leaf. | 401 | * transaction to add the new attribute to the leaf. |
| 389 | */ | 402 | */ |
| 390 | if ((error = xfs_attr_rolltrans(&args.trans, dp))) | 403 | |
| 404 | error = xfs_trans_roll(&args.trans, dp); | ||
| 405 | if (error) | ||
| 391 | goto out; | 406 | goto out; |
| 392 | 407 | ||
| 393 | } | 408 | } |
| @@ -529,9 +544,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags) | |||
| 529 | /* | 544 | /* |
| 530 | * Decide on what work routines to call based on the inode size. | 545 | * Decide on what work routines to call based on the inode size. |
| 531 | */ | 546 | */ |
| 532 | if (XFS_IFORK_Q(dp) == 0 || | 547 | if (!xfs_inode_hasattr(dp)) { |
| 533 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 534 | dp->i_d.di_anextents == 0)) { | ||
| 535 | error = XFS_ERROR(ENOATTR); | 548 | error = XFS_ERROR(ENOATTR); |
| 536 | goto out; | 549 | goto out; |
| 537 | } | 550 | } |
| @@ -601,29 +614,33 @@ xfs_attr_remove( | |||
| 601 | return error; | 614 | return error; |
| 602 | 615 | ||
| 603 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 616 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
| 604 | if (XFS_IFORK_Q(dp) == 0 || | 617 | if (!xfs_inode_hasattr(dp)) { |
| 605 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 606 | dp->i_d.di_anextents == 0)) { | ||
| 607 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 618 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
| 608 | return(XFS_ERROR(ENOATTR)); | 619 | return XFS_ERROR(ENOATTR); |
| 609 | } | 620 | } |
| 610 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 621 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
| 611 | 622 | ||
| 612 | return xfs_attr_remove_int(dp, &xname, flags); | 623 | return xfs_attr_remove_int(dp, &xname, flags); |
| 613 | } | 624 | } |
| 614 | 625 | ||
| 615 | STATIC int | 626 | int |
| 616 | xfs_attr_list_int(xfs_attr_list_context_t *context) | 627 | xfs_attr_list_int(xfs_attr_list_context_t *context) |
| 617 | { | 628 | { |
| 618 | int error; | 629 | int error; |
| 619 | xfs_inode_t *dp = context->dp; | 630 | xfs_inode_t *dp = context->dp; |
| 620 | 631 | ||
| 632 | XFS_STATS_INC(xs_attr_list); | ||
| 633 | |||
| 634 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
| 635 | return EIO; | ||
| 636 | |||
| 637 | xfs_ilock(dp, XFS_ILOCK_SHARED); | ||
| 638 | xfs_attr_trace_l_c("syscall start", context); | ||
| 639 | |||
| 621 | /* | 640 | /* |
| 622 | * Decide on what work routines to call based on the inode size. | 641 | * Decide on what work routines to call based on the inode size. |
| 623 | */ | 642 | */ |
| 624 | if (XFS_IFORK_Q(dp) == 0 || | 643 | if (!xfs_inode_hasattr(dp)) { |
| 625 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 626 | dp->i_d.di_anextents == 0)) { | ||
| 627 | error = 0; | 644 | error = 0; |
| 628 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 645 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
| 629 | error = xfs_attr_shortform_list(context); | 646 | error = xfs_attr_shortform_list(context); |
| @@ -632,6 +649,10 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) | |||
| 632 | } else { | 649 | } else { |
| 633 | error = xfs_attr_node_list(context); | 650 | error = xfs_attr_node_list(context); |
| 634 | } | 651 | } |
| 652 | |||
| 653 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
| 654 | xfs_attr_trace_l_c("syscall end", context); | ||
| 655 | |||
| 635 | return error; | 656 | return error; |
| 636 | } | 657 | } |
| 637 | 658 | ||
| @@ -648,74 +669,50 @@ xfs_attr_list_int(xfs_attr_list_context_t *context) | |||
| 648 | */ | 669 | */ |
| 649 | /*ARGSUSED*/ | 670 | /*ARGSUSED*/ |
| 650 | STATIC int | 671 | STATIC int |
| 651 | xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp, | 672 | xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags, |
| 652 | char *name, int namelen, | 673 | char *name, int namelen, |
| 653 | int valuelen, char *value) | 674 | int valuelen, char *value) |
| 654 | { | 675 | { |
| 676 | struct attrlist *alist = (struct attrlist *)context->alist; | ||
| 655 | attrlist_ent_t *aep; | 677 | attrlist_ent_t *aep; |
| 656 | int arraytop; | 678 | int arraytop; |
| 657 | 679 | ||
| 658 | ASSERT(!(context->flags & ATTR_KERNOVAL)); | 680 | ASSERT(!(context->flags & ATTR_KERNOVAL)); |
| 659 | ASSERT(context->count >= 0); | 681 | ASSERT(context->count >= 0); |
| 660 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); | 682 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); |
| 661 | ASSERT(context->firstu >= sizeof(*context->alist)); | 683 | ASSERT(context->firstu >= sizeof(*alist)); |
| 662 | ASSERT(context->firstu <= context->bufsize); | 684 | ASSERT(context->firstu <= context->bufsize); |
| 663 | 685 | ||
| 664 | arraytop = sizeof(*context->alist) + | 686 | /* |
| 665 | context->count * sizeof(context->alist->al_offset[0]); | 687 | * Only list entries in the right namespace. |
| 688 | */ | ||
| 689 | if (((context->flags & ATTR_SECURE) == 0) != | ||
| 690 | ((flags & XFS_ATTR_SECURE) == 0)) | ||
| 691 | return 0; | ||
| 692 | if (((context->flags & ATTR_ROOT) == 0) != | ||
| 693 | ((flags & XFS_ATTR_ROOT) == 0)) | ||
| 694 | return 0; | ||
| 695 | |||
| 696 | arraytop = sizeof(*alist) + | ||
| 697 | context->count * sizeof(alist->al_offset[0]); | ||
| 666 | context->firstu -= ATTR_ENTSIZE(namelen); | 698 | context->firstu -= ATTR_ENTSIZE(namelen); |
| 667 | if (context->firstu < arraytop) { | 699 | if (context->firstu < arraytop) { |
| 668 | xfs_attr_trace_l_c("buffer full", context); | 700 | xfs_attr_trace_l_c("buffer full", context); |
| 669 | context->alist->al_more = 1; | 701 | alist->al_more = 1; |
| 670 | context->seen_enough = 1; | 702 | context->seen_enough = 1; |
| 671 | return 1; | 703 | return 1; |
| 672 | } | 704 | } |
| 673 | 705 | ||
| 674 | aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); | 706 | aep = (attrlist_ent_t *)&context->alist[context->firstu]; |
| 675 | aep->a_valuelen = valuelen; | 707 | aep->a_valuelen = valuelen; |
| 676 | memcpy(aep->a_name, name, namelen); | 708 | memcpy(aep->a_name, name, namelen); |
| 677 | aep->a_name[ namelen ] = 0; | 709 | aep->a_name[namelen] = 0; |
| 678 | context->alist->al_offset[ context->count++ ] = context->firstu; | 710 | alist->al_offset[context->count++] = context->firstu; |
| 679 | context->alist->al_count = context->count; | 711 | alist->al_count = context->count; |
| 680 | xfs_attr_trace_l_c("add", context); | 712 | xfs_attr_trace_l_c("add", context); |
| 681 | return 0; | 713 | return 0; |
| 682 | } | 714 | } |
| 683 | 715 | ||
| 684 | STATIC int | ||
| 685 | xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
| 686 | char *name, int namelen, | ||
| 687 | int valuelen, char *value) | ||
| 688 | { | ||
| 689 | char *offset; | ||
| 690 | int arraytop; | ||
| 691 | |||
| 692 | ASSERT(context->count >= 0); | ||
| 693 | |||
| 694 | arraytop = context->count + namesp->attr_namelen + namelen + 1; | ||
| 695 | if (arraytop > context->firstu) { | ||
| 696 | context->count = -1; /* insufficient space */ | ||
| 697 | return 1; | ||
| 698 | } | ||
| 699 | offset = (char *)context->alist + context->count; | ||
| 700 | strncpy(offset, namesp->attr_name, namesp->attr_namelen); | ||
| 701 | offset += namesp->attr_namelen; | ||
| 702 | strncpy(offset, name, namelen); /* real name */ | ||
| 703 | offset += namelen; | ||
| 704 | *offset = '\0'; | ||
| 705 | context->count += namesp->attr_namelen + namelen + 1; | ||
| 706 | return 0; | ||
| 707 | } | ||
| 708 | |||
| 709 | /*ARGSUSED*/ | ||
| 710 | STATIC int | ||
| 711 | xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp, | ||
| 712 | char *name, int namelen, | ||
| 713 | int valuelen, char *value) | ||
| 714 | { | ||
| 715 | context->count += namesp->attr_namelen + namelen + 1; | ||
| 716 | return 0; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* | 716 | /* |
| 720 | * Generate a list of extended attribute names and optionally | 717 | * Generate a list of extended attribute names and optionally |
| 721 | * also value lengths. Positive return value follows the XFS | 718 | * also value lengths. Positive return value follows the XFS |
| @@ -732,10 +729,9 @@ xfs_attr_list( | |||
| 732 | attrlist_cursor_kern_t *cursor) | 729 | attrlist_cursor_kern_t *cursor) |
| 733 | { | 730 | { |
| 734 | xfs_attr_list_context_t context; | 731 | xfs_attr_list_context_t context; |
| 732 | struct attrlist *alist; | ||
| 735 | int error; | 733 | int error; |
| 736 | 734 | ||
| 737 | XFS_STATS_INC(xs_attr_list); | ||
| 738 | |||
| 739 | /* | 735 | /* |
| 740 | * Validate the cursor. | 736 | * Validate the cursor. |
| 741 | */ | 737 | */ |
| @@ -756,52 +752,23 @@ xfs_attr_list( | |||
| 756 | /* | 752 | /* |
| 757 | * Initialize the output buffer. | 753 | * Initialize the output buffer. |
| 758 | */ | 754 | */ |
| 755 | memset(&context, 0, sizeof(context)); | ||
| 759 | context.dp = dp; | 756 | context.dp = dp; |
| 760 | context.cursor = cursor; | 757 | context.cursor = cursor; |
| 761 | context.count = 0; | ||
| 762 | context.dupcnt = 0; | ||
| 763 | context.resynch = 1; | 758 | context.resynch = 1; |
| 764 | context.flags = flags; | 759 | context.flags = flags; |
| 765 | context.seen_enough = 0; | 760 | context.alist = buffer; |
| 766 | context.alist = (attrlist_t *)buffer; | 761 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ |
| 767 | context.put_value = 0; | 762 | context.firstu = context.bufsize; |
| 768 | 763 | context.put_listent = xfs_attr_put_listent; | |
| 769 | if (flags & ATTR_KERNAMELS) { | ||
| 770 | context.bufsize = bufsize; | ||
| 771 | context.firstu = context.bufsize; | ||
| 772 | if (flags & ATTR_KERNOVAL) | ||
| 773 | context.put_listent = xfs_attr_kern_list_sizes; | ||
| 774 | else | ||
| 775 | context.put_listent = xfs_attr_kern_list; | ||
| 776 | } else { | ||
| 777 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ | ||
| 778 | context.firstu = context.bufsize; | ||
| 779 | context.alist->al_count = 0; | ||
| 780 | context.alist->al_more = 0; | ||
| 781 | context.alist->al_offset[0] = context.bufsize; | ||
| 782 | context.put_listent = xfs_attr_put_listent; | ||
| 783 | } | ||
| 784 | |||
| 785 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
| 786 | return EIO; | ||
| 787 | 764 | ||
| 788 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 765 | alist = (struct attrlist *)context.alist; |
| 789 | xfs_attr_trace_l_c("syscall start", &context); | 766 | alist->al_count = 0; |
| 767 | alist->al_more = 0; | ||
| 768 | alist->al_offset[0] = context.bufsize; | ||
| 790 | 769 | ||
| 791 | error = xfs_attr_list_int(&context); | 770 | error = xfs_attr_list_int(&context); |
| 792 | 771 | ASSERT(error >= 0); | |
| 793 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
| 794 | xfs_attr_trace_l_c("syscall end", &context); | ||
| 795 | |||
| 796 | if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) { | ||
| 797 | /* must return negated buffer size or the error */ | ||
| 798 | if (context.count < 0) | ||
| 799 | error = XFS_ERROR(ERANGE); | ||
| 800 | else | ||
| 801 | error = -context.count; | ||
| 802 | } else | ||
| 803 | ASSERT(error >= 0); | ||
| 804 | |||
| 805 | return error; | 772 | return error; |
| 806 | } | 773 | } |
| 807 | 774 | ||
| @@ -816,12 +783,10 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
| 816 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); | 783 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); |
| 817 | 784 | ||
| 818 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 785 | xfs_ilock(dp, XFS_ILOCK_SHARED); |
| 819 | if ((XFS_IFORK_Q(dp) == 0) || | 786 | if (!xfs_inode_hasattr(dp) || |
| 820 | (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || | 787 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
| 821 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 822 | dp->i_d.di_anextents == 0)) { | ||
| 823 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 788 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
| 824 | return(0); | 789 | return 0; |
| 825 | } | 790 | } |
| 826 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 791 | xfs_iunlock(dp, XFS_ILOCK_SHARED); |
| 827 | 792 | ||
| @@ -854,10 +819,8 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
| 854 | /* | 819 | /* |
| 855 | * Decide on what work routines to call based on the inode size. | 820 | * Decide on what work routines to call based on the inode size. |
| 856 | */ | 821 | */ |
| 857 | if ((XFS_IFORK_Q(dp) == 0) || | 822 | if (!xfs_inode_hasattr(dp) || |
| 858 | (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || | 823 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { |
| 859 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
| 860 | dp->i_d.di_anextents == 0)) { | ||
| 861 | error = 0; | 824 | error = 0; |
| 862 | goto out; | 825 | goto out; |
| 863 | } | 826 | } |
| @@ -974,7 +937,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
| 974 | xfs_da_brelse(args->trans, bp); | 937 | xfs_da_brelse(args->trans, bp); |
| 975 | return(retval); | 938 | return(retval); |
| 976 | } | 939 | } |
| 977 | args->rename = 1; /* an atomic rename */ | 940 | args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ |
| 978 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | 941 | args->blkno2 = args->blkno; /* set 2nd entry info*/ |
| 979 | args->index2 = args->index; | 942 | args->index2 = args->index; |
| 980 | args->rmtblkno2 = args->rmtblkno; | 943 | args->rmtblkno2 = args->rmtblkno; |
| @@ -1019,7 +982,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
| 1019 | * Commit the current trans (including the inode) and start | 982 | * Commit the current trans (including the inode) and start |
| 1020 | * a new one. | 983 | * a new one. |
| 1021 | */ | 984 | */ |
| 1022 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 985 | error = xfs_trans_roll(&args->trans, dp); |
| 986 | if (error) | ||
| 1023 | return (error); | 987 | return (error); |
| 1024 | 988 | ||
| 1025 | /* | 989 | /* |
| @@ -1033,7 +997,8 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
| 1033 | * Commit the transaction that added the attr name so that | 997 | * Commit the transaction that added the attr name so that |
| 1034 | * later routines can manage their own transactions. | 998 | * later routines can manage their own transactions. |
| 1035 | */ | 999 | */ |
| 1036 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1000 | error = xfs_trans_roll(&args->trans, dp); |
| 1001 | if (error) | ||
| 1037 | return (error); | 1002 | return (error); |
| 1038 | 1003 | ||
| 1039 | /* | 1004 | /* |
| @@ -1054,7 +1019,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
| 1054 | * so that one disappears and one appears atomically. Then we | 1019 | * so that one disappears and one appears atomically. Then we |
| 1055 | * must remove the "old" attribute/value pair. | 1020 | * must remove the "old" attribute/value pair. |
| 1056 | */ | 1021 | */ |
| 1057 | if (args->rename) { | 1022 | if (args->op_flags & XFS_DA_OP_RENAME) { |
| 1058 | /* | 1023 | /* |
| 1059 | * In a separate transaction, set the incomplete flag on the | 1024 | * In a separate transaction, set the incomplete flag on the |
| 1060 | * "old" attr and clear the incomplete flag on the "new" attr. | 1025 | * "old" attr and clear the incomplete flag on the "new" attr. |
| @@ -1122,7 +1087,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) | |||
| 1122 | /* | 1087 | /* |
| 1123 | * Commit the remove and start the next trans in series. | 1088 | * Commit the remove and start the next trans in series. |
| 1124 | */ | 1089 | */ |
| 1125 | error = xfs_attr_rolltrans(&args->trans, dp); | 1090 | error = xfs_trans_roll(&args->trans, dp); |
| 1126 | 1091 | ||
| 1127 | } else if (args->rmtblkno > 0) { | 1092 | } else if (args->rmtblkno > 0) { |
| 1128 | /* | 1093 | /* |
| @@ -1307,7 +1272,7 @@ restart: | |||
| 1307 | } else if (retval == EEXIST) { | 1272 | } else if (retval == EEXIST) { |
| 1308 | if (args->flags & ATTR_CREATE) | 1273 | if (args->flags & ATTR_CREATE) |
| 1309 | goto out; | 1274 | goto out; |
| 1310 | args->rename = 1; /* atomic rename op */ | 1275 | args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ |
| 1311 | args->blkno2 = args->blkno; /* set 2nd entry info*/ | 1276 | args->blkno2 = args->blkno; /* set 2nd entry info*/ |
| 1312 | args->index2 = args->index; | 1277 | args->index2 = args->index; |
| 1313 | args->rmtblkno2 = args->rmtblkno; | 1278 | args->rmtblkno2 = args->rmtblkno; |
| @@ -1353,7 +1318,8 @@ restart: | |||
| 1353 | * Commit the node conversion and start the next | 1318 | * Commit the node conversion and start the next |
| 1354 | * trans in the chain. | 1319 | * trans in the chain. |
| 1355 | */ | 1320 | */ |
| 1356 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1321 | error = xfs_trans_roll(&args->trans, dp); |
| 1322 | if (error) | ||
| 1357 | goto out; | 1323 | goto out; |
| 1358 | 1324 | ||
| 1359 | goto restart; | 1325 | goto restart; |
| @@ -1404,7 +1370,8 @@ restart: | |||
| 1404 | * Commit the leaf addition or btree split and start the next | 1370 | * Commit the leaf addition or btree split and start the next |
| 1405 | * trans in the chain. | 1371 | * trans in the chain. |
| 1406 | */ | 1372 | */ |
| 1407 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1373 | error = xfs_trans_roll(&args->trans, dp); |
| 1374 | if (error) | ||
| 1408 | goto out; | 1375 | goto out; |
| 1409 | 1376 | ||
| 1410 | /* | 1377 | /* |
| @@ -1425,7 +1392,7 @@ restart: | |||
| 1425 | * so that one disappears and one appears atomically. Then we | 1392 | * so that one disappears and one appears atomically. Then we |
| 1426 | * must remove the "old" attribute/value pair. | 1393 | * must remove the "old" attribute/value pair. |
| 1427 | */ | 1394 | */ |
| 1428 | if (args->rename) { | 1395 | if (args->op_flags & XFS_DA_OP_RENAME) { |
| 1429 | /* | 1396 | /* |
| 1430 | * In a separate transaction, set the incomplete flag on the | 1397 | * In a separate transaction, set the incomplete flag on the |
| 1431 | * "old" attr and clear the incomplete flag on the "new" attr. | 1398 | * "old" attr and clear the incomplete flag on the "new" attr. |
| @@ -1504,7 +1471,8 @@ restart: | |||
| 1504 | /* | 1471 | /* |
| 1505 | * Commit and start the next trans in the chain. | 1472 | * Commit and start the next trans in the chain. |
| 1506 | */ | 1473 | */ |
| 1507 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1474 | error = xfs_trans_roll(&args->trans, dp); |
| 1475 | if (error) | ||
| 1508 | goto out; | 1476 | goto out; |
| 1509 | 1477 | ||
| 1510 | } else if (args->rmtblkno > 0) { | 1478 | } else if (args->rmtblkno > 0) { |
| @@ -1636,7 +1604,8 @@ xfs_attr_node_removename(xfs_da_args_t *args) | |||
| 1636 | /* | 1604 | /* |
| 1637 | * Commit the Btree join operation and start a new trans. | 1605 | * Commit the Btree join operation and start a new trans. |
| 1638 | */ | 1606 | */ |
| 1639 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 1607 | error = xfs_trans_roll(&args->trans, dp); |
| 1608 | if (error) | ||
| 1640 | goto out; | 1609 | goto out; |
| 1641 | } | 1610 | } |
| 1642 | 1611 | ||
| @@ -2137,7 +2106,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) | |||
| 2137 | /* | 2106 | /* |
| 2138 | * Start the next trans in the chain. | 2107 | * Start the next trans in the chain. |
| 2139 | */ | 2108 | */ |
| 2140 | if ((error = xfs_attr_rolltrans(&args->trans, dp))) | 2109 | error = xfs_trans_roll(&args->trans, dp); |
| 2110 | if (error) | ||
| 2141 | return (error); | 2111 | return (error); |
| 2142 | } | 2112 | } |
| 2143 | 2113 | ||
| @@ -2287,7 +2257,8 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
| 2287 | /* | 2257 | /* |
| 2288 | * Close out trans and start the next one in the chain. | 2258 | * Close out trans and start the next one in the chain. |
| 2289 | */ | 2259 | */ |
| 2290 | if ((error = xfs_attr_rolltrans(&args->trans, args->dp))) | 2260 | error = xfs_trans_roll(&args->trans, args->dp); |
| 2261 | if (error) | ||
| 2291 | return (error); | 2262 | return (error); |
| 2292 | } | 2263 | } |
| 2293 | return(0); | 2264 | return(0); |
| @@ -2300,23 +2271,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) | |||
| 2300 | void | 2271 | void |
| 2301 | xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) | 2272 | xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) |
| 2302 | { | 2273 | { |
| 2303 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, | 2274 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, context, |
| 2304 | (__psunsigned_t)context->dp, | ||
| 2305 | (__psunsigned_t)context->cursor->hashval, | ||
| 2306 | (__psunsigned_t)context->cursor->blkno, | ||
| 2307 | (__psunsigned_t)context->cursor->offset, | ||
| 2308 | (__psunsigned_t)context->alist, | ||
| 2309 | (__psunsigned_t)context->bufsize, | ||
| 2310 | (__psunsigned_t)context->count, | ||
| 2311 | (__psunsigned_t)context->firstu, | ||
| 2312 | (__psunsigned_t) | ||
| 2313 | ((context->count > 0) && | ||
| 2314 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
| 2315 | ? (ATTR_ENTRY(context->alist, | ||
| 2316 | context->count-1)->a_valuelen) | ||
| 2317 | : 0, | ||
| 2318 | (__psunsigned_t)context->dupcnt, | ||
| 2319 | (__psunsigned_t)context->flags, | ||
| 2320 | (__psunsigned_t)NULL, | 2275 | (__psunsigned_t)NULL, |
| 2321 | (__psunsigned_t)NULL, | 2276 | (__psunsigned_t)NULL, |
| 2322 | (__psunsigned_t)NULL); | 2277 | (__psunsigned_t)NULL); |
| @@ -2329,23 +2284,7 @@ void | |||
| 2329 | xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, | 2284 | xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, |
| 2330 | struct xfs_da_intnode *node) | 2285 | struct xfs_da_intnode *node) |
| 2331 | { | 2286 | { |
| 2332 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, | 2287 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, context, |
| 2333 | (__psunsigned_t)context->dp, | ||
| 2334 | (__psunsigned_t)context->cursor->hashval, | ||
| 2335 | (__psunsigned_t)context->cursor->blkno, | ||
| 2336 | (__psunsigned_t)context->cursor->offset, | ||
| 2337 | (__psunsigned_t)context->alist, | ||
| 2338 | (__psunsigned_t)context->bufsize, | ||
| 2339 | (__psunsigned_t)context->count, | ||
| 2340 | (__psunsigned_t)context->firstu, | ||
| 2341 | (__psunsigned_t) | ||
| 2342 | ((context->count > 0) && | ||
| 2343 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
| 2344 | ? (ATTR_ENTRY(context->alist, | ||
| 2345 | context->count-1)->a_valuelen) | ||
| 2346 | : 0, | ||
| 2347 | (__psunsigned_t)context->dupcnt, | ||
| 2348 | (__psunsigned_t)context->flags, | ||
| 2349 | (__psunsigned_t)be16_to_cpu(node->hdr.count), | 2288 | (__psunsigned_t)be16_to_cpu(node->hdr.count), |
| 2350 | (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), | 2289 | (__psunsigned_t)be32_to_cpu(node->btree[0].hashval), |
| 2351 | (__psunsigned_t)be32_to_cpu(node->btree[ | 2290 | (__psunsigned_t)be32_to_cpu(node->btree[ |
| @@ -2359,23 +2298,7 @@ void | |||
| 2359 | xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, | 2298 | xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, |
| 2360 | struct xfs_da_node_entry *btree) | 2299 | struct xfs_da_node_entry *btree) |
| 2361 | { | 2300 | { |
| 2362 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, | 2301 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, context, |
| 2363 | (__psunsigned_t)context->dp, | ||
| 2364 | (__psunsigned_t)context->cursor->hashval, | ||
| 2365 | (__psunsigned_t)context->cursor->blkno, | ||
| 2366 | (__psunsigned_t)context->cursor->offset, | ||
| 2367 | (__psunsigned_t)context->alist, | ||
| 2368 | (__psunsigned_t)context->bufsize, | ||
| 2369 | (__psunsigned_t)context->count, | ||
| 2370 | (__psunsigned_t)context->firstu, | ||
| 2371 | (__psunsigned_t) | ||
| 2372 | ((context->count > 0) && | ||
| 2373 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
| 2374 | ? (ATTR_ENTRY(context->alist, | ||
| 2375 | context->count-1)->a_valuelen) | ||
| 2376 | : 0, | ||
| 2377 | (__psunsigned_t)context->dupcnt, | ||
| 2378 | (__psunsigned_t)context->flags, | ||
| 2379 | (__psunsigned_t)be32_to_cpu(btree->hashval), | 2302 | (__psunsigned_t)be32_to_cpu(btree->hashval), |
| 2380 | (__psunsigned_t)be32_to_cpu(btree->before), | 2303 | (__psunsigned_t)be32_to_cpu(btree->before), |
| 2381 | (__psunsigned_t)NULL); | 2304 | (__psunsigned_t)NULL); |
| @@ -2388,23 +2311,7 @@ void | |||
| 2388 | xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | 2311 | xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, |
| 2389 | struct xfs_attr_leafblock *leaf) | 2312 | struct xfs_attr_leafblock *leaf) |
| 2390 | { | 2313 | { |
| 2391 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, | 2314 | xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, context, |
| 2392 | (__psunsigned_t)context->dp, | ||
| 2393 | (__psunsigned_t)context->cursor->hashval, | ||
| 2394 | (__psunsigned_t)context->cursor->blkno, | ||
| 2395 | (__psunsigned_t)context->cursor->offset, | ||
| 2396 | (__psunsigned_t)context->alist, | ||
| 2397 | (__psunsigned_t)context->bufsize, | ||
| 2398 | (__psunsigned_t)context->count, | ||
| 2399 | (__psunsigned_t)context->firstu, | ||
| 2400 | (__psunsigned_t) | ||
| 2401 | ((context->count > 0) && | ||
| 2402 | !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL))) | ||
| 2403 | ? (ATTR_ENTRY(context->alist, | ||
| 2404 | context->count-1)->a_valuelen) | ||
| 2405 | : 0, | ||
| 2406 | (__psunsigned_t)context->dupcnt, | ||
| 2407 | (__psunsigned_t)context->flags, | ||
| 2408 | (__psunsigned_t)be16_to_cpu(leaf->hdr.count), | 2315 | (__psunsigned_t)be16_to_cpu(leaf->hdr.count), |
| 2409 | (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), | 2316 | (__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval), |
| 2410 | (__psunsigned_t)be32_to_cpu(leaf->entries[ | 2317 | (__psunsigned_t)be32_to_cpu(leaf->entries[ |
| @@ -2417,329 +2324,24 @@ xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | |||
| 2417 | */ | 2324 | */ |
| 2418 | void | 2325 | void |
| 2419 | xfs_attr_trace_enter(int type, char *where, | 2326 | xfs_attr_trace_enter(int type, char *where, |
| 2420 | __psunsigned_t a2, __psunsigned_t a3, | 2327 | struct xfs_attr_list_context *context, |
| 2421 | __psunsigned_t a4, __psunsigned_t a5, | 2328 | __psunsigned_t a13, __psunsigned_t a14, |
| 2422 | __psunsigned_t a6, __psunsigned_t a7, | 2329 | __psunsigned_t a15) |
| 2423 | __psunsigned_t a8, __psunsigned_t a9, | ||
| 2424 | __psunsigned_t a10, __psunsigned_t a11, | ||
| 2425 | __psunsigned_t a12, __psunsigned_t a13, | ||
| 2426 | __psunsigned_t a14, __psunsigned_t a15) | ||
| 2427 | { | 2330 | { |
| 2428 | ASSERT(xfs_attr_trace_buf); | 2331 | ASSERT(xfs_attr_trace_buf); |
| 2429 | ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), | 2332 | ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), |
| 2430 | (void *)where, | 2333 | (void *)((__psunsigned_t)where), |
| 2431 | (void *)a2, (void *)a3, (void *)a4, | 2334 | (void *)((__psunsigned_t)context->dp), |
| 2432 | (void *)a5, (void *)a6, (void *)a7, | 2335 | (void *)((__psunsigned_t)context->cursor->hashval), |
| 2433 | (void *)a8, (void *)a9, (void *)a10, | 2336 | (void *)((__psunsigned_t)context->cursor->blkno), |
| 2434 | (void *)a11, (void *)a12, (void *)a13, | 2337 | (void *)((__psunsigned_t)context->cursor->offset), |
| 2435 | (void *)a14, (void *)a15); | 2338 | (void *)((__psunsigned_t)context->alist), |
| 2339 | (void *)((__psunsigned_t)context->bufsize), | ||
| 2340 | (void *)((__psunsigned_t)context->count), | ||
| 2341 | (void *)((__psunsigned_t)context->firstu), | ||
| 2342 | NULL, | ||
| 2343 | (void *)((__psunsigned_t)context->dupcnt), | ||
| 2344 | (void *)((__psunsigned_t)context->flags), | ||
| 2345 | (void *)a13, (void *)a14, (void *)a15); | ||
| 2436 | } | 2346 | } |
| 2437 | #endif /* XFS_ATTR_TRACE */ | 2347 | #endif /* XFS_ATTR_TRACE */ |
| 2438 | |||
| 2439 | |||
| 2440 | /*======================================================================== | ||
| 2441 | * System (pseudo) namespace attribute interface routines. | ||
| 2442 | *========================================================================*/ | ||
| 2443 | |||
| 2444 | STATIC int | ||
| 2445 | posix_acl_access_set( | ||
| 2446 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2447 | { | ||
| 2448 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS); | ||
| 2449 | } | ||
| 2450 | |||
| 2451 | STATIC int | ||
| 2452 | posix_acl_access_remove( | ||
| 2453 | bhv_vnode_t *vp, char *name, int xflags) | ||
| 2454 | { | ||
| 2455 | return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS); | ||
| 2456 | } | ||
| 2457 | |||
| 2458 | STATIC int | ||
| 2459 | posix_acl_access_get( | ||
| 2460 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2461 | { | ||
| 2462 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS); | ||
| 2463 | } | ||
| 2464 | |||
| 2465 | STATIC int | ||
| 2466 | posix_acl_access_exists( | ||
| 2467 | bhv_vnode_t *vp) | ||
| 2468 | { | ||
| 2469 | return xfs_acl_vhasacl_access(vp); | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | STATIC int | ||
| 2473 | posix_acl_default_set( | ||
| 2474 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2475 | { | ||
| 2476 | return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT); | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | STATIC int | ||
| 2480 | posix_acl_default_get( | ||
| 2481 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2482 | { | ||
| 2483 | return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT); | ||
| 2484 | } | ||
| 2485 | |||
| 2486 | STATIC int | ||
| 2487 | posix_acl_default_remove( | ||
| 2488 | bhv_vnode_t *vp, char *name, int xflags) | ||
| 2489 | { | ||
| 2490 | return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT); | ||
| 2491 | } | ||
| 2492 | |||
| 2493 | STATIC int | ||
| 2494 | posix_acl_default_exists( | ||
| 2495 | bhv_vnode_t *vp) | ||
| 2496 | { | ||
| 2497 | return xfs_acl_vhasacl_default(vp); | ||
| 2498 | } | ||
| 2499 | |||
| 2500 | static struct attrnames posix_acl_access = { | ||
| 2501 | .attr_name = "posix_acl_access", | ||
| 2502 | .attr_namelen = sizeof("posix_acl_access") - 1, | ||
| 2503 | .attr_get = posix_acl_access_get, | ||
| 2504 | .attr_set = posix_acl_access_set, | ||
| 2505 | .attr_remove = posix_acl_access_remove, | ||
| 2506 | .attr_exists = posix_acl_access_exists, | ||
| 2507 | }; | ||
| 2508 | |||
| 2509 | static struct attrnames posix_acl_default = { | ||
| 2510 | .attr_name = "posix_acl_default", | ||
| 2511 | .attr_namelen = sizeof("posix_acl_default") - 1, | ||
| 2512 | .attr_get = posix_acl_default_get, | ||
| 2513 | .attr_set = posix_acl_default_set, | ||
| 2514 | .attr_remove = posix_acl_default_remove, | ||
| 2515 | .attr_exists = posix_acl_default_exists, | ||
| 2516 | }; | ||
| 2517 | |||
| 2518 | static struct attrnames *attr_system_names[] = | ||
| 2519 | { &posix_acl_access, &posix_acl_default }; | ||
| 2520 | |||
| 2521 | |||
| 2522 | /*======================================================================== | ||
| 2523 | * Namespace-prefix-style attribute name interface routines. | ||
| 2524 | *========================================================================*/ | ||
| 2525 | |||
| 2526 | STATIC int | ||
| 2527 | attr_generic_set( | ||
| 2528 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2529 | { | ||
| 2530 | return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags); | ||
| 2531 | } | ||
| 2532 | |||
| 2533 | STATIC int | ||
| 2534 | attr_generic_get( | ||
| 2535 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2536 | { | ||
| 2537 | int error, asize = size; | ||
| 2538 | |||
| 2539 | error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags); | ||
| 2540 | if (!error) | ||
| 2541 | return asize; | ||
| 2542 | return -error; | ||
| 2543 | } | ||
| 2544 | |||
| 2545 | STATIC int | ||
| 2546 | attr_generic_remove( | ||
| 2547 | bhv_vnode_t *vp, char *name, int xflags) | ||
| 2548 | { | ||
| 2549 | return -xfs_attr_remove(xfs_vtoi(vp), name, xflags); | ||
| 2550 | } | ||
| 2551 | |||
| 2552 | STATIC int | ||
| 2553 | attr_generic_listadd( | ||
| 2554 | attrnames_t *prefix, | ||
| 2555 | attrnames_t *namesp, | ||
| 2556 | void *data, | ||
| 2557 | size_t size, | ||
| 2558 | ssize_t *result) | ||
| 2559 | { | ||
| 2560 | char *p = data + *result; | ||
| 2561 | |||
| 2562 | *result += prefix->attr_namelen; | ||
| 2563 | *result += namesp->attr_namelen + 1; | ||
| 2564 | if (!size) | ||
| 2565 | return 0; | ||
| 2566 | if (*result > size) | ||
| 2567 | return -ERANGE; | ||
| 2568 | strcpy(p, prefix->attr_name); | ||
| 2569 | p += prefix->attr_namelen; | ||
| 2570 | strcpy(p, namesp->attr_name); | ||
| 2571 | p += namesp->attr_namelen + 1; | ||
| 2572 | return 0; | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | STATIC int | ||
| 2576 | attr_system_list( | ||
| 2577 | bhv_vnode_t *vp, | ||
| 2578 | void *data, | ||
| 2579 | size_t size, | ||
| 2580 | ssize_t *result) | ||
| 2581 | { | ||
| 2582 | attrnames_t *namesp; | ||
| 2583 | int i, error = 0; | ||
| 2584 | |||
| 2585 | for (i = 0; i < ATTR_SYSCOUNT; i++) { | ||
| 2586 | namesp = attr_system_names[i]; | ||
| 2587 | if (!namesp->attr_exists || !namesp->attr_exists(vp)) | ||
| 2588 | continue; | ||
| 2589 | error = attr_generic_listadd(&attr_system, namesp, | ||
| 2590 | data, size, result); | ||
| 2591 | if (error) | ||
| 2592 | break; | ||
| 2593 | } | ||
| 2594 | return error; | ||
| 2595 | } | ||
| 2596 | |||
| 2597 | int | ||
| 2598 | attr_generic_list( | ||
| 2599 | bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result) | ||
| 2600 | { | ||
| 2601 | attrlist_cursor_kern_t cursor = { 0 }; | ||
| 2602 | int error; | ||
| 2603 | |||
| 2604 | error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor); | ||
| 2605 | if (error > 0) | ||
| 2606 | return -error; | ||
| 2607 | *result = -error; | ||
| 2608 | return attr_system_list(vp, data, size, result); | ||
| 2609 | } | ||
| 2610 | |||
| 2611 | attrnames_t * | ||
| 2612 | attr_lookup_namespace( | ||
| 2613 | char *name, | ||
| 2614 | struct attrnames **names, | ||
| 2615 | int nnames) | ||
| 2616 | { | ||
| 2617 | int i; | ||
| 2618 | |||
| 2619 | for (i = 0; i < nnames; i++) | ||
| 2620 | if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen)) | ||
| 2621 | return names[i]; | ||
| 2622 | return NULL; | ||
| 2623 | } | ||
| 2624 | |||
| 2625 | /* | ||
| 2626 | * Some checks to prevent people abusing EAs to get over quota: | ||
| 2627 | * - Don't allow modifying user EAs on devices/symlinks; | ||
| 2628 | * - Don't allow modifying user EAs if sticky bit set; | ||
| 2629 | */ | ||
| 2630 | STATIC int | ||
| 2631 | attr_user_capable( | ||
| 2632 | bhv_vnode_t *vp, | ||
| 2633 | cred_t *cred) | ||
| 2634 | { | ||
| 2635 | struct inode *inode = vn_to_inode(vp); | ||
| 2636 | |||
| 2637 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
| 2638 | return -EPERM; | ||
| 2639 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && | ||
| 2640 | !capable(CAP_SYS_ADMIN)) | ||
| 2641 | return -EPERM; | ||
| 2642 | if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && | ||
| 2643 | (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER)) | ||
| 2644 | return -EPERM; | ||
| 2645 | return 0; | ||
| 2646 | } | ||
| 2647 | |||
| 2648 | STATIC int | ||
| 2649 | attr_trusted_capable( | ||
| 2650 | bhv_vnode_t *vp, | ||
| 2651 | cred_t *cred) | ||
| 2652 | { | ||
| 2653 | struct inode *inode = vn_to_inode(vp); | ||
| 2654 | |||
| 2655 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | ||
| 2656 | return -EPERM; | ||
| 2657 | if (!capable(CAP_SYS_ADMIN)) | ||
| 2658 | return -EPERM; | ||
| 2659 | return 0; | ||
| 2660 | } | ||
| 2661 | |||
| 2662 | STATIC int | ||
| 2663 | attr_system_set( | ||
| 2664 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2665 | { | ||
| 2666 | attrnames_t *namesp; | ||
| 2667 | int error; | ||
| 2668 | |||
| 2669 | if (xflags & ATTR_CREATE) | ||
| 2670 | return -EINVAL; | ||
| 2671 | |||
| 2672 | namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); | ||
| 2673 | if (!namesp) | ||
| 2674 | return -EOPNOTSUPP; | ||
| 2675 | error = namesp->attr_set(vp, name, data, size, xflags); | ||
| 2676 | if (!error) | ||
| 2677 | error = vn_revalidate(vp); | ||
| 2678 | return error; | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | STATIC int | ||
| 2682 | attr_system_get( | ||
| 2683 | bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags) | ||
| 2684 | { | ||
| 2685 | attrnames_t *namesp; | ||
| 2686 | |||
| 2687 | namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); | ||
| 2688 | if (!namesp) | ||
| 2689 | return -EOPNOTSUPP; | ||
| 2690 | return namesp->attr_get(vp, name, data, size, xflags); | ||
| 2691 | } | ||
| 2692 | |||
| 2693 | STATIC int | ||
| 2694 | attr_system_remove( | ||
| 2695 | bhv_vnode_t *vp, char *name, int xflags) | ||
| 2696 | { | ||
| 2697 | attrnames_t *namesp; | ||
| 2698 | |||
| 2699 | namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT); | ||
| 2700 | if (!namesp) | ||
| 2701 | return -EOPNOTSUPP; | ||
| 2702 | return namesp->attr_remove(vp, name, xflags); | ||
| 2703 | } | ||
| 2704 | |||
| 2705 | struct attrnames attr_system = { | ||
| 2706 | .attr_name = "system.", | ||
| 2707 | .attr_namelen = sizeof("system.") - 1, | ||
| 2708 | .attr_flag = ATTR_SYSTEM, | ||
| 2709 | .attr_get = attr_system_get, | ||
| 2710 | .attr_set = attr_system_set, | ||
| 2711 | .attr_remove = attr_system_remove, | ||
| 2712 | .attr_capable = (attrcapable_t)fs_noerr, | ||
| 2713 | }; | ||
| 2714 | |||
| 2715 | struct attrnames attr_trusted = { | ||
| 2716 | .attr_name = "trusted.", | ||
| 2717 | .attr_namelen = sizeof("trusted.") - 1, | ||
| 2718 | .attr_flag = ATTR_ROOT, | ||
| 2719 | .attr_get = attr_generic_get, | ||
| 2720 | .attr_set = attr_generic_set, | ||
| 2721 | .attr_remove = attr_generic_remove, | ||
| 2722 | .attr_capable = attr_trusted_capable, | ||
| 2723 | }; | ||
| 2724 | |||
| 2725 | struct attrnames attr_secure = { | ||
| 2726 | .attr_name = "security.", | ||
| 2727 | .attr_namelen = sizeof("security.") - 1, | ||
| 2728 | .attr_flag = ATTR_SECURE, | ||
| 2729 | .attr_get = attr_generic_get, | ||
| 2730 | .attr_set = attr_generic_set, | ||
| 2731 | .attr_remove = attr_generic_remove, | ||
| 2732 | .attr_capable = (attrcapable_t)fs_noerr, | ||
| 2733 | }; | ||
| 2734 | |||
| 2735 | struct attrnames attr_user = { | ||
| 2736 | .attr_name = "user.", | ||
| 2737 | .attr_namelen = sizeof("user.") - 1, | ||
| 2738 | .attr_get = attr_generic_get, | ||
| 2739 | .attr_set = attr_generic_set, | ||
| 2740 | .attr_remove = attr_generic_remove, | ||
| 2741 | .attr_capable = attr_user_capable, | ||
| 2742 | }; | ||
| 2743 | |||
| 2744 | struct attrnames *attr_namespaces[] = | ||
| 2745 | { &attr_system, &attr_trusted, &attr_secure, &attr_user }; | ||
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h index 6cfc9384fe35..fb3b2a68b9b9 100644 --- a/fs/xfs/xfs_attr.h +++ b/fs/xfs/xfs_attr.h | |||
| @@ -18,9 +18,11 @@ | |||
| 18 | #ifndef __XFS_ATTR_H__ | 18 | #ifndef __XFS_ATTR_H__ |
| 19 | #define __XFS_ATTR_H__ | 19 | #define __XFS_ATTR_H__ |
| 20 | 20 | ||
| 21 | struct xfs_inode; | ||
| 22 | struct xfs_da_args; | ||
| 23 | struct xfs_attr_list_context; | ||
| 24 | |||
| 21 | /* | 25 | /* |
| 22 | * xfs_attr.h | ||
| 23 | * | ||
| 24 | * Large attribute lists are structured around Btrees where all the data | 26 | * Large attribute lists are structured around Btrees where all the data |
| 25 | * elements are in the leaf nodes. Attribute names are hashed into an int, | 27 | * elements are in the leaf nodes. Attribute names are hashed into an int, |
| 26 | * then that int is used as the index into the Btree. Since the hashval | 28 | * then that int is used as the index into the Btree. Since the hashval |
| @@ -35,35 +37,6 @@ | |||
| 35 | * External interfaces | 37 | * External interfaces |
| 36 | *========================================================================*/ | 38 | *========================================================================*/ |
| 37 | 39 | ||
| 38 | struct cred; | ||
| 39 | struct xfs_attr_list_context; | ||
| 40 | |||
| 41 | typedef int (*attrset_t)(bhv_vnode_t *, char *, void *, size_t, int); | ||
| 42 | typedef int (*attrget_t)(bhv_vnode_t *, char *, void *, size_t, int); | ||
| 43 | typedef int (*attrremove_t)(bhv_vnode_t *, char *, int); | ||
| 44 | typedef int (*attrexists_t)(bhv_vnode_t *); | ||
| 45 | typedef int (*attrcapable_t)(bhv_vnode_t *, struct cred *); | ||
| 46 | |||
| 47 | typedef struct attrnames { | ||
| 48 | char * attr_name; | ||
| 49 | unsigned int attr_namelen; | ||
| 50 | unsigned int attr_flag; | ||
| 51 | attrget_t attr_get; | ||
| 52 | attrset_t attr_set; | ||
| 53 | attrremove_t attr_remove; | ||
| 54 | attrexists_t attr_exists; | ||
| 55 | attrcapable_t attr_capable; | ||
| 56 | } attrnames_t; | ||
| 57 | |||
| 58 | #define ATTR_NAMECOUNT 4 | ||
| 59 | extern struct attrnames attr_user; | ||
| 60 | extern struct attrnames attr_secure; | ||
| 61 | extern struct attrnames attr_system; | ||
| 62 | extern struct attrnames attr_trusted; | ||
| 63 | extern struct attrnames *attr_namespaces[ATTR_NAMECOUNT]; | ||
| 64 | |||
| 65 | extern attrnames_t *attr_lookup_namespace(char *, attrnames_t **, int); | ||
| 66 | extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *); | ||
| 67 | 40 | ||
| 68 | #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ | 41 | #define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ |
| 69 | #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ | 42 | #define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ |
| @@ -71,16 +44,9 @@ extern int attr_generic_list(bhv_vnode_t *, void *, size_t, int, ssize_t *); | |||
| 71 | #define ATTR_SECURE 0x0008 /* use attrs in security namespace */ | 44 | #define ATTR_SECURE 0x0008 /* use attrs in security namespace */ |
| 72 | #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ | 45 | #define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ |
| 73 | #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ | 46 | #define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ |
| 74 | #define ATTR_SYSTEM 0x0100 /* use attrs in system (pseudo) namespace */ | ||
| 75 | 47 | ||
| 76 | #define ATTR_KERNACCESS 0x0400 /* [kernel] iaccess, inode held io-locked */ | ||
| 77 | #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ | 48 | #define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ |
| 78 | #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ | 49 | #define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ |
| 79 | #define ATTR_KERNAMELS 0x4000 /* [kernel] list attr names (simple list) */ | ||
| 80 | |||
| 81 | #define ATTR_KERNORMALS 0x0800 /* [kernel] normal attr list: user+secure */ | ||
| 82 | #define ATTR_KERNROOTLS 0x8000 /* [kernel] include root in the attr list */ | ||
| 83 | #define ATTR_KERNFULLS (ATTR_KERNORMALS|ATTR_KERNROOTLS) | ||
| 84 | 50 | ||
| 85 | /* | 51 | /* |
| 86 | * The maximum size (into the kernel or returned from the kernel) of an | 52 | * The maximum size (into the kernel or returned from the kernel) of an |
| @@ -119,22 +85,6 @@ typedef struct attrlist_ent { /* data from attr_list() */ | |||
| 119 | &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) | 85 | &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) |
| 120 | 86 | ||
| 121 | /* | 87 | /* |
| 122 | * Multi-attribute operation vector. | ||
| 123 | */ | ||
| 124 | typedef struct attr_multiop { | ||
| 125 | int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */ | ||
| 126 | int am_error; /* [out arg] result of this sub-op (an errno) */ | ||
| 127 | char *am_attrname; /* attribute name to work with */ | ||
| 128 | char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */ | ||
| 129 | int am_length; /* [in/out arg] length of value */ | ||
| 130 | int am_flags; /* bitwise OR of attr API flags defined above */ | ||
| 131 | } attr_multiop_t; | ||
| 132 | |||
| 133 | #define ATTR_OP_GET 1 /* return the indicated attr's value */ | ||
| 134 | #define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ | ||
| 135 | #define ATTR_OP_REMOVE 3 /* remove the indicated attr */ | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Kernel-internal version of the attrlist cursor. | 88 | * Kernel-internal version of the attrlist cursor. |
| 139 | */ | 89 | */ |
| 140 | typedef struct attrlist_cursor_kern { | 90 | typedef struct attrlist_cursor_kern { |
| @@ -148,20 +98,41 @@ typedef struct attrlist_cursor_kern { | |||
| 148 | 98 | ||
| 149 | 99 | ||
| 150 | /*======================================================================== | 100 | /*======================================================================== |
| 151 | * Function prototypes for the kernel. | 101 | * Structure used to pass context around among the routines. |
| 152 | *========================================================================*/ | 102 | *========================================================================*/ |
| 153 | 103 | ||
| 154 | struct xfs_inode; | 104 | |
| 155 | struct attrlist_cursor_kern; | 105 | typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int, |
| 156 | struct xfs_da_args; | 106 | char *, int, int, char *); |
| 107 | |||
| 108 | typedef struct xfs_attr_list_context { | ||
| 109 | struct xfs_inode *dp; /* inode */ | ||
| 110 | struct attrlist_cursor_kern *cursor; /* position in list */ | ||
| 111 | char *alist; /* output buffer */ | ||
| 112 | int seen_enough; /* T/F: seen enough of list? */ | ||
| 113 | ssize_t count; /* num used entries */ | ||
| 114 | int dupcnt; /* count dup hashvals seen */ | ||
| 115 | int bufsize; /* total buffer size */ | ||
| 116 | int firstu; /* first used byte in buffer */ | ||
| 117 | int flags; /* from VOP call */ | ||
| 118 | int resynch; /* T/F: resynch with cursor */ | ||
| 119 | int put_value; /* T/F: need value for listent */ | ||
| 120 | put_listent_func_t put_listent; /* list output fmt function */ | ||
| 121 | int index; /* index into output buffer */ | ||
| 122 | } xfs_attr_list_context_t; | ||
| 123 | |||
| 124 | |||
| 125 | /*======================================================================== | ||
| 126 | * Function prototypes for the kernel. | ||
| 127 | *========================================================================*/ | ||
| 157 | 128 | ||
| 158 | /* | 129 | /* |
| 159 | * Overall external interface routines. | 130 | * Overall external interface routines. |
| 160 | */ | 131 | */ |
| 132 | int xfs_attr_calc_size(struct xfs_inode *, int, int, int *); | ||
| 161 | int xfs_attr_inactive(struct xfs_inode *dp); | 133 | int xfs_attr_inactive(struct xfs_inode *dp); |
| 162 | |||
| 163 | int xfs_attr_shortform_getvalue(struct xfs_da_args *); | ||
| 164 | int xfs_attr_fetch(struct xfs_inode *, struct xfs_name *, char *, int *, int); | 134 | int xfs_attr_fetch(struct xfs_inode *, struct xfs_name *, char *, int *, int); |
| 165 | int xfs_attr_rmtval_get(struct xfs_da_args *args); | 135 | int xfs_attr_rmtval_get(struct xfs_da_args *args); |
| 136 | int xfs_attr_list_int(struct xfs_attr_list_context *); | ||
| 166 | 137 | ||
| 167 | #endif /* __XFS_ATTR_H__ */ | 138 | #endif /* __XFS_ATTR_H__ */ |
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 303d41e4217b..79da6b2ea99e 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c | |||
| @@ -94,13 +94,6 @@ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); | |||
| 94 | * Namespace helper routines | 94 | * Namespace helper routines |
| 95 | *========================================================================*/ | 95 | *========================================================================*/ |
| 96 | 96 | ||
| 97 | STATIC_INLINE attrnames_t * | ||
| 98 | xfs_attr_flags_namesp(int flags) | ||
| 99 | { | ||
| 100 | return ((flags & XFS_ATTR_SECURE) ? &attr_secure: | ||
| 101 | ((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user)); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | 97 | /* |
| 105 | * If namespace bits don't match return 0. | 98 | * If namespace bits don't match return 0. |
| 106 | * If all match then return 1. | 99 | * If all match then return 1. |
| @@ -111,25 +104,6 @@ xfs_attr_namesp_match(int arg_flags, int ondisk_flags) | |||
| 111 | return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); | 104 | return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); |
| 112 | } | 105 | } |
| 113 | 106 | ||
| 114 | /* | ||
| 115 | * If namespace bits don't match and we don't have an override for it | ||
| 116 | * then return 0. | ||
| 117 | * If all match or are overridable then return 1. | ||
| 118 | */ | ||
| 119 | STATIC_INLINE int | ||
| 120 | xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags) | ||
| 121 | { | ||
| 122 | if (((arg_flags & ATTR_SECURE) == 0) != | ||
| 123 | ((ondisk_flags & XFS_ATTR_SECURE) == 0) && | ||
| 124 | !(arg_flags & ATTR_KERNORMALS)) | ||
| 125 | return 0; | ||
| 126 | if (((arg_flags & ATTR_ROOT) == 0) != | ||
| 127 | ((ondisk_flags & XFS_ATTR_ROOT) == 0) && | ||
| 128 | !(arg_flags & ATTR_KERNROOTLS)) | ||
| 129 | return 0; | ||
| 130 | return 1; | ||
| 131 | } | ||
| 132 | |||
| 133 | 107 | ||
| 134 | /*======================================================================== | 108 | /*======================================================================== |
| 135 | * External routines when attribute fork size < XFS_LITINO(mp). | 109 | * External routines when attribute fork size < XFS_LITINO(mp). |
| @@ -369,9 +343,10 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) | |||
| 369 | * Fix up the start offset of the attribute fork | 343 | * Fix up the start offset of the attribute fork |
| 370 | */ | 344 | */ |
| 371 | totsize -= size; | 345 | totsize -= size; |
| 372 | if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && | 346 | if (totsize == sizeof(xfs_attr_sf_hdr_t) && |
| 373 | (mp->m_flags & XFS_MOUNT_ATTR2) && | 347 | !(args->op_flags & XFS_DA_OP_ADDNAME) && |
| 374 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) { | 348 | (mp->m_flags & XFS_MOUNT_ATTR2) && |
| 349 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) { | ||
| 375 | /* | 350 | /* |
| 376 | * Last attribute now removed, revert to original | 351 | * Last attribute now removed, revert to original |
| 377 | * inode format making all literal area available | 352 | * inode format making all literal area available |
| @@ -389,9 +364,10 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) | |||
| 389 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); | 364 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); |
| 390 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); | 365 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); |
| 391 | ASSERT(dp->i_d.di_forkoff); | 366 | ASSERT(dp->i_d.di_forkoff); |
| 392 | ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname || | 367 | ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || |
| 393 | !(mp->m_flags & XFS_MOUNT_ATTR2) || | 368 | (args->op_flags & XFS_DA_OP_ADDNAME) || |
| 394 | dp->i_d.di_format == XFS_DINODE_FMT_BTREE); | 369 | !(mp->m_flags & XFS_MOUNT_ATTR2) || |
| 370 | dp->i_d.di_format == XFS_DINODE_FMT_BTREE); | ||
| 395 | dp->i_afp->if_ext_max = | 371 | dp->i_afp->if_ext_max = |
| 396 | XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); | 372 | XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); |
| 397 | dp->i_df.if_ext_max = | 373 | dp->i_df.if_ext_max = |
| @@ -531,7 +507,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) | |||
| 531 | nargs.total = args->total; | 507 | nargs.total = args->total; |
| 532 | nargs.whichfork = XFS_ATTR_FORK; | 508 | nargs.whichfork = XFS_ATTR_FORK; |
| 533 | nargs.trans = args->trans; | 509 | nargs.trans = args->trans; |
| 534 | nargs.oknoent = 1; | 510 | nargs.op_flags = XFS_DA_OP_OKNOENT; |
| 535 | 511 | ||
| 536 | sfe = &sf->list[0]; | 512 | sfe = &sf->list[0]; |
| 537 | for (i = 0; i < sf->hdr.count; i++) { | 513 | for (i = 0; i < sf->hdr.count; i++) { |
| @@ -555,7 +531,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) | |||
| 555 | out: | 531 | out: |
| 556 | if(bp) | 532 | if(bp) |
| 557 | xfs_da_buf_done(bp); | 533 | xfs_da_buf_done(bp); |
| 558 | kmem_free(tmpbuffer, size); | 534 | kmem_free(tmpbuffer); |
| 559 | return(error); | 535 | return(error); |
| 560 | } | 536 | } |
| 561 | 537 | ||
| @@ -624,15 +600,8 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) | |||
| 624 | (XFS_ISRESET_CURSOR(cursor) && | 600 | (XFS_ISRESET_CURSOR(cursor) && |
| 625 | (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { | 601 | (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { |
| 626 | for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { | 602 | for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { |
| 627 | attrnames_t *namesp; | ||
| 628 | |||
| 629 | if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) { | ||
| 630 | sfe = XFS_ATTR_SF_NEXTENTRY(sfe); | ||
| 631 | continue; | ||
| 632 | } | ||
| 633 | namesp = xfs_attr_flags_namesp(sfe->flags); | ||
| 634 | error = context->put_listent(context, | 603 | error = context->put_listent(context, |
| 635 | namesp, | 604 | sfe->flags, |
| 636 | (char *)sfe->nameval, | 605 | (char *)sfe->nameval, |
| 637 | (int)sfe->namelen, | 606 | (int)sfe->namelen, |
| 638 | (int)sfe->valuelen, | 607 | (int)sfe->valuelen, |
| @@ -676,13 +645,10 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) | |||
| 676 | XFS_ERRLEVEL_LOW, | 645 | XFS_ERRLEVEL_LOW, |
| 677 | context->dp->i_mount, sfe); | 646 | context->dp->i_mount, sfe); |
| 678 | xfs_attr_trace_l_c("sf corrupted", context); | 647 | xfs_attr_trace_l_c("sf corrupted", context); |
| 679 | kmem_free(sbuf, sbsize); | 648 | kmem_free(sbuf); |
| 680 | return XFS_ERROR(EFSCORRUPTED); | 649 | return XFS_ERROR(EFSCORRUPTED); |
| 681 | } | 650 | } |
| 682 | if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) { | 651 | |
| 683 | sfe = XFS_ATTR_SF_NEXTENTRY(sfe); | ||
| 684 | continue; | ||
| 685 | } | ||
| 686 | sbp->entno = i; | 652 | sbp->entno = i; |
| 687 | sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen); | 653 | sbp->hash = xfs_da_hashname((char *)sfe->nameval, sfe->namelen); |
| 688 | sbp->name = (char *)sfe->nameval; | 654 | sbp->name = (char *)sfe->nameval; |
| @@ -717,7 +683,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) | |||
| 717 | } | 683 | } |
| 718 | } | 684 | } |
| 719 | if (i == nsbuf) { | 685 | if (i == nsbuf) { |
| 720 | kmem_free(sbuf, sbsize); | 686 | kmem_free(sbuf); |
| 721 | xfs_attr_trace_l_c("blk end", context); | 687 | xfs_attr_trace_l_c("blk end", context); |
| 722 | return(0); | 688 | return(0); |
| 723 | } | 689 | } |
| @@ -726,16 +692,12 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) | |||
| 726 | * Loop putting entries into the user buffer. | 692 | * Loop putting entries into the user buffer. |
| 727 | */ | 693 | */ |
| 728 | for ( ; i < nsbuf; i++, sbp++) { | 694 | for ( ; i < nsbuf; i++, sbp++) { |
| 729 | attrnames_t *namesp; | ||
| 730 | |||
| 731 | namesp = xfs_attr_flags_namesp(sbp->flags); | ||
| 732 | |||
| 733 | if (cursor->hashval != sbp->hash) { | 695 | if (cursor->hashval != sbp->hash) { |
| 734 | cursor->hashval = sbp->hash; | 696 | cursor->hashval = sbp->hash; |
| 735 | cursor->offset = 0; | 697 | cursor->offset = 0; |
| 736 | } | 698 | } |
| 737 | error = context->put_listent(context, | 699 | error = context->put_listent(context, |
| 738 | namesp, | 700 | sbp->flags, |
| 739 | sbp->name, | 701 | sbp->name, |
| 740 | sbp->namelen, | 702 | sbp->namelen, |
| 741 | sbp->valuelen, | 703 | sbp->valuelen, |
| @@ -747,7 +709,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) | |||
| 747 | cursor->offset++; | 709 | cursor->offset++; |
| 748 | } | 710 | } |
| 749 | 711 | ||
| 750 | kmem_free(sbuf, sbsize); | 712 | kmem_free(sbuf); |
| 751 | xfs_attr_trace_l_c("sf E-O-F", context); | 713 | xfs_attr_trace_l_c("sf E-O-F", context); |
| 752 | return(0); | 714 | return(0); |
| 753 | } | 715 | } |
| @@ -853,7 +815,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff) | |||
| 853 | nargs.total = args->total; | 815 | nargs.total = args->total; |
| 854 | nargs.whichfork = XFS_ATTR_FORK; | 816 | nargs.whichfork = XFS_ATTR_FORK; |
| 855 | nargs.trans = args->trans; | 817 | nargs.trans = args->trans; |
| 856 | nargs.oknoent = 1; | 818 | nargs.op_flags = XFS_DA_OP_OKNOENT; |
| 857 | entry = &leaf->entries[0]; | 819 | entry = &leaf->entries[0]; |
| 858 | for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) { | 820 | for (i = 0; i < be16_to_cpu(leaf->hdr.count); entry++, i++) { |
| 859 | if (entry->flags & XFS_ATTR_INCOMPLETE) | 821 | if (entry->flags & XFS_ATTR_INCOMPLETE) |
| @@ -873,7 +835,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff) | |||
| 873 | error = 0; | 835 | error = 0; |
| 874 | 836 | ||
| 875 | out: | 837 | out: |
| 876 | kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); | 838 | kmem_free(tmpbuffer); |
| 877 | return(error); | 839 | return(error); |
| 878 | } | 840 | } |
| 879 | 841 | ||
| @@ -1155,7 +1117,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) | |||
| 1155 | entry->hashval = cpu_to_be32(args->hashval); | 1117 | entry->hashval = cpu_to_be32(args->hashval); |
| 1156 | entry->flags = tmp ? XFS_ATTR_LOCAL : 0; | 1118 | entry->flags = tmp ? XFS_ATTR_LOCAL : 0; |
| 1157 | entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); | 1119 | entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); |
| 1158 | if (args->rename) { | 1120 | if (args->op_flags & XFS_DA_OP_RENAME) { |
| 1159 | entry->flags |= XFS_ATTR_INCOMPLETE; | 1121 | entry->flags |= XFS_ATTR_INCOMPLETE; |
| 1160 | if ((args->blkno2 == args->blkno) && | 1122 | if ((args->blkno2 == args->blkno) && |
| 1161 | (args->index2 <= args->index)) { | 1123 | (args->index2 <= args->index)) { |
| @@ -1271,7 +1233,7 @@ xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp) | |||
| 1271 | be16_to_cpu(hdr_s->count), mp); | 1233 | be16_to_cpu(hdr_s->count), mp); |
| 1272 | xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); | 1234 | xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); |
| 1273 | 1235 | ||
| 1274 | kmem_free(tmpbuffer, XFS_LBSIZE(mp)); | 1236 | kmem_free(tmpbuffer); |
| 1275 | } | 1237 | } |
| 1276 | 1238 | ||
| 1277 | /* | 1239 | /* |
| @@ -1921,7 +1883,7 @@ xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, | |||
| 1921 | be16_to_cpu(drop_hdr->count), mp); | 1883 | be16_to_cpu(drop_hdr->count), mp); |
| 1922 | } | 1884 | } |
| 1923 | memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize); | 1885 | memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize); |
| 1924 | kmem_free(tmpbuffer, state->blocksize); | 1886 | kmem_free(tmpbuffer); |
| 1925 | } | 1887 | } |
| 1926 | 1888 | ||
| 1927 | xfs_da_log_buf(state->args->trans, save_blk->bp, 0, | 1889 | xfs_da_log_buf(state->args->trans, save_blk->bp, 0, |
| @@ -2400,8 +2362,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) | |||
| 2400 | */ | 2362 | */ |
| 2401 | retval = 0; | 2363 | retval = 0; |
| 2402 | for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) { | 2364 | for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) { |
| 2403 | attrnames_t *namesp; | ||
| 2404 | |||
| 2405 | if (be32_to_cpu(entry->hashval) != cursor->hashval) { | 2365 | if (be32_to_cpu(entry->hashval) != cursor->hashval) { |
| 2406 | cursor->hashval = be32_to_cpu(entry->hashval); | 2366 | cursor->hashval = be32_to_cpu(entry->hashval); |
| 2407 | cursor->offset = 0; | 2367 | cursor->offset = 0; |
| @@ -2409,17 +2369,13 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) | |||
| 2409 | 2369 | ||
| 2410 | if (entry->flags & XFS_ATTR_INCOMPLETE) | 2370 | if (entry->flags & XFS_ATTR_INCOMPLETE) |
| 2411 | continue; /* skip incomplete entries */ | 2371 | continue; /* skip incomplete entries */ |
| 2412 | if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags)) | ||
| 2413 | continue; | ||
| 2414 | |||
| 2415 | namesp = xfs_attr_flags_namesp(entry->flags); | ||
| 2416 | 2372 | ||
| 2417 | if (entry->flags & XFS_ATTR_LOCAL) { | 2373 | if (entry->flags & XFS_ATTR_LOCAL) { |
| 2418 | xfs_attr_leaf_name_local_t *name_loc = | 2374 | xfs_attr_leaf_name_local_t *name_loc = |
| 2419 | XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); | 2375 | XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); |
| 2420 | 2376 | ||
| 2421 | retval = context->put_listent(context, | 2377 | retval = context->put_listent(context, |
| 2422 | namesp, | 2378 | entry->flags, |
| 2423 | (char *)name_loc->nameval, | 2379 | (char *)name_loc->nameval, |
| 2424 | (int)name_loc->namelen, | 2380 | (int)name_loc->namelen, |
| 2425 | be16_to_cpu(name_loc->valuelen), | 2381 | be16_to_cpu(name_loc->valuelen), |
| @@ -2446,16 +2402,15 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) | |||
| 2446 | if (retval) | 2402 | if (retval) |
| 2447 | return retval; | 2403 | return retval; |
| 2448 | retval = context->put_listent(context, | 2404 | retval = context->put_listent(context, |
| 2449 | namesp, | 2405 | entry->flags, |
| 2450 | (char *)name_rmt->name, | 2406 | (char *)name_rmt->name, |
| 2451 | (int)name_rmt->namelen, | 2407 | (int)name_rmt->namelen, |
| 2452 | valuelen, | 2408 | valuelen, |
| 2453 | (char*)args.value); | 2409 | (char*)args.value); |
| 2454 | kmem_free(args.value, valuelen); | 2410 | kmem_free(args.value); |
| 2455 | } | 2411 | } else { |
| 2456 | else { | ||
| 2457 | retval = context->put_listent(context, | 2412 | retval = context->put_listent(context, |
| 2458 | namesp, | 2413 | entry->flags, |
| 2459 | (char *)name_rmt->name, | 2414 | (char *)name_rmt->name, |
| 2460 | (int)name_rmt->namelen, | 2415 | (int)name_rmt->namelen, |
| 2461 | valuelen, | 2416 | valuelen, |
| @@ -2543,9 +2498,7 @@ xfs_attr_leaf_clearflag(xfs_da_args_t *args) | |||
| 2543 | /* | 2498 | /* |
| 2544 | * Commit the flag value change and start the next trans in series. | 2499 | * Commit the flag value change and start the next trans in series. |
| 2545 | */ | 2500 | */ |
| 2546 | error = xfs_attr_rolltrans(&args->trans, args->dp); | 2501 | return xfs_trans_roll(&args->trans, args->dp); |
| 2547 | |||
| 2548 | return(error); | ||
| 2549 | } | 2502 | } |
| 2550 | 2503 | ||
| 2551 | /* | 2504 | /* |
| @@ -2592,9 +2545,7 @@ xfs_attr_leaf_setflag(xfs_da_args_t *args) | |||
| 2592 | /* | 2545 | /* |
| 2593 | * Commit the flag value change and start the next trans in series. | 2546 | * Commit the flag value change and start the next trans in series. |
| 2594 | */ | 2547 | */ |
| 2595 | error = xfs_attr_rolltrans(&args->trans, args->dp); | 2548 | return xfs_trans_roll(&args->trans, args->dp); |
| 2596 | |||
| 2597 | return(error); | ||
| 2598 | } | 2549 | } |
| 2599 | 2550 | ||
| 2600 | /* | 2551 | /* |
| @@ -2710,7 +2661,7 @@ xfs_attr_leaf_flipflags(xfs_da_args_t *args) | |||
| 2710 | /* | 2661 | /* |
| 2711 | * Commit the flag value change and start the next trans in series. | 2662 | * Commit the flag value change and start the next trans in series. |
| 2712 | */ | 2663 | */ |
| 2713 | error = xfs_attr_rolltrans(&args->trans, args->dp); | 2664 | error = xfs_trans_roll(&args->trans, args->dp); |
| 2714 | 2665 | ||
| 2715 | return(error); | 2666 | return(error); |
| 2716 | } | 2667 | } |
| @@ -2768,7 +2719,7 @@ xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp) | |||
| 2768 | /* | 2719 | /* |
| 2769 | * Commit the invalidate and start the next transaction. | 2720 | * Commit the invalidate and start the next transaction. |
| 2770 | */ | 2721 | */ |
| 2771 | error = xfs_attr_rolltrans(trans, dp); | 2722 | error = xfs_trans_roll(trans, dp); |
| 2772 | 2723 | ||
| 2773 | return (error); | 2724 | return (error); |
| 2774 | } | 2725 | } |
| @@ -2870,7 +2821,8 @@ xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, | |||
| 2870 | /* | 2821 | /* |
| 2871 | * Atomically commit the whole invalidate stuff. | 2822 | * Atomically commit the whole invalidate stuff. |
| 2872 | */ | 2823 | */ |
| 2873 | if ((error = xfs_attr_rolltrans(trans, dp))) | 2824 | error = xfs_trans_roll(trans, dp); |
| 2825 | if (error) | ||
| 2874 | return (error); | 2826 | return (error); |
| 2875 | } | 2827 | } |
| 2876 | 2828 | ||
| @@ -2954,7 +2906,7 @@ xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) | |||
| 2954 | error = tmp; /* save only the 1st errno */ | 2906 | error = tmp; /* save only the 1st errno */ |
| 2955 | } | 2907 | } |
| 2956 | 2908 | ||
| 2957 | kmem_free((xfs_caddr_t)list, size); | 2909 | kmem_free((xfs_caddr_t)list); |
| 2958 | return(error); | 2910 | return(error); |
| 2959 | } | 2911 | } |
| 2960 | 2912 | ||
| @@ -3009,7 +2961,8 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, | |||
| 3009 | /* | 2961 | /* |
| 3010 | * Roll to next transaction. | 2962 | * Roll to next transaction. |
| 3011 | */ | 2963 | */ |
| 3012 | if ((error = xfs_attr_rolltrans(trans, dp))) | 2964 | error = xfs_trans_roll(trans, dp); |
| 2965 | if (error) | ||
| 3013 | return (error); | 2966 | return (error); |
| 3014 | } | 2967 | } |
| 3015 | 2968 | ||
| @@ -3019,60 +2972,3 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, | |||
| 3019 | 2972 | ||
| 3020 | return(0); | 2973 | return(0); |
| 3021 | } | 2974 | } |
| 3022 | |||
| 3023 | |||
| 3024 | /* | ||
| 3025 | * Roll from one trans in the sequence of PERMANENT transactions to the next. | ||
| 3026 | */ | ||
| 3027 | int | ||
| 3028 | xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp) | ||
| 3029 | { | ||
| 3030 | xfs_trans_t *trans; | ||
| 3031 | unsigned int logres, count; | ||
| 3032 | int error; | ||
| 3033 | |||
| 3034 | /* | ||
| 3035 | * Ensure that the inode is always logged. | ||
| 3036 | */ | ||
| 3037 | trans = *transp; | ||
| 3038 | xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); | ||
| 3039 | |||
| 3040 | /* | ||
| 3041 | * Copy the critical parameters from one trans to the next. | ||
| 3042 | */ | ||
| 3043 | logres = trans->t_log_res; | ||
| 3044 | count = trans->t_log_count; | ||
| 3045 | *transp = xfs_trans_dup(trans); | ||
| 3046 | |||
| 3047 | /* | ||
| 3048 | * Commit the current transaction. | ||
| 3049 | * If this commit failed, then it'd just unlock those items that | ||
| 3050 | * are not marked ihold. That also means that a filesystem shutdown | ||
| 3051 | * is in progress. The caller takes the responsibility to cancel | ||
| 3052 | * the duplicate transaction that gets returned. | ||
| 3053 | */ | ||
| 3054 | if ((error = xfs_trans_commit(trans, 0))) | ||
| 3055 | return (error); | ||
| 3056 | |||
| 3057 | trans = *transp; | ||
| 3058 | |||
| 3059 | /* | ||
| 3060 | * Reserve space in the log for th next transaction. | ||
| 3061 | * This also pushes items in the "AIL", the list of logged items, | ||
| 3062 | * out to disk if they are taking up space at the tail of the log | ||
| 3063 | * that we want to use. This requires that either nothing be locked | ||
| 3064 | * across this call, or that anything that is locked be logged in | ||
| 3065 | * the prior and the next transactions. | ||
| 3066 | */ | ||
| 3067 | error = xfs_trans_reserve(trans, 0, logres, 0, | ||
| 3068 | XFS_TRANS_PERM_LOG_RES, count); | ||
| 3069 | /* | ||
| 3070 | * Ensure that the inode is in the new transaction and locked. | ||
| 3071 | */ | ||
| 3072 | if (!error) { | ||
| 3073 | xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); | ||
| 3074 | xfs_trans_ihold(trans, dp); | ||
| 3075 | } | ||
| 3076 | return (error); | ||
| 3077 | |||
| 3078 | } | ||
diff --git a/fs/xfs/xfs_attr_leaf.h b/fs/xfs/xfs_attr_leaf.h index 040f732ce1e2..83e9af417ca2 100644 --- a/fs/xfs/xfs_attr_leaf.h +++ b/fs/xfs/xfs_attr_leaf.h | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | 30 | ||
| 31 | struct attrlist; | 31 | struct attrlist; |
| 32 | struct attrlist_cursor_kern; | 32 | struct attrlist_cursor_kern; |
| 33 | struct attrnames; | 33 | struct xfs_attr_list_context; |
| 34 | struct xfs_dabuf; | 34 | struct xfs_dabuf; |
| 35 | struct xfs_da_args; | 35 | struct xfs_da_args; |
| 36 | struct xfs_da_state; | 36 | struct xfs_da_state; |
| @@ -204,33 +204,6 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize) | |||
| 204 | return (((bsize) >> 1) + ((bsize) >> 2)); | 204 | return (((bsize) >> 1) + ((bsize) >> 2)); |
| 205 | } | 205 | } |
| 206 | 206 | ||
| 207 | |||
| 208 | /*======================================================================== | ||
| 209 | * Structure used to pass context around among the routines. | ||
| 210 | *========================================================================*/ | ||
| 211 | |||
| 212 | |||
| 213 | struct xfs_attr_list_context; | ||
| 214 | |||
| 215 | typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, struct attrnames *, | ||
| 216 | char *, int, int, char *); | ||
| 217 | |||
| 218 | typedef struct xfs_attr_list_context { | ||
| 219 | struct xfs_inode *dp; /* inode */ | ||
| 220 | struct attrlist_cursor_kern *cursor; /* position in list */ | ||
| 221 | struct attrlist *alist; /* output buffer */ | ||
| 222 | int seen_enough; /* T/F: seen enough of list? */ | ||
| 223 | int count; /* num used entries */ | ||
| 224 | int dupcnt; /* count dup hashvals seen */ | ||
| 225 | int bufsize; /* total buffer size */ | ||
| 226 | int firstu; /* first used byte in buffer */ | ||
| 227 | int flags; /* from VOP call */ | ||
| 228 | int resynch; /* T/F: resynch with cursor */ | ||
| 229 | int put_value; /* T/F: need value for listent */ | ||
| 230 | put_listent_func_t put_listent; /* list output fmt function */ | ||
| 231 | int index; /* index into output buffer */ | ||
| 232 | } xfs_attr_list_context_t; | ||
| 233 | |||
| 234 | /* | 207 | /* |
| 235 | * Used to keep a list of "remote value" extents when unlinking an inode. | 208 | * Used to keep a list of "remote value" extents when unlinking an inode. |
| 236 | */ | 209 | */ |
| @@ -301,6 +274,4 @@ int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp, | |||
| 301 | struct xfs_dabuf *leaf2_bp); | 274 | struct xfs_dabuf *leaf2_bp); |
| 302 | int xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, | 275 | int xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, |
| 303 | int *local); | 276 | int *local); |
| 304 | int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); | ||
| 305 | |||
| 306 | #endif /* __XFS_ATTR_LEAF_H__ */ | 277 | #endif /* __XFS_ATTR_LEAF_H__ */ |
diff --git a/fs/xfs/xfs_attr_sf.h b/fs/xfs/xfs_attr_sf.h index f67f917803b1..ea22839caed2 100644 --- a/fs/xfs/xfs_attr_sf.h +++ b/fs/xfs/xfs_attr_sf.h | |||
| @@ -97,13 +97,9 @@ void xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, | |||
| 97 | void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, | 97 | void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, |
| 98 | struct xfs_attr_leafblock *leaf); | 98 | struct xfs_attr_leafblock *leaf); |
| 99 | void xfs_attr_trace_enter(int type, char *where, | 99 | void xfs_attr_trace_enter(int type, char *where, |
| 100 | __psunsigned_t a2, __psunsigned_t a3, | 100 | struct xfs_attr_list_context *context, |
| 101 | __psunsigned_t a4, __psunsigned_t a5, | 101 | __psunsigned_t a13, __psunsigned_t a14, |
| 102 | __psunsigned_t a6, __psunsigned_t a7, | 102 | __psunsigned_t a15); |
| 103 | __psunsigned_t a8, __psunsigned_t a9, | ||
| 104 | __psunsigned_t a10, __psunsigned_t a11, | ||
| 105 | __psunsigned_t a12, __psunsigned_t a13, | ||
| 106 | __psunsigned_t a14, __psunsigned_t a15); | ||
| 107 | #else | 103 | #else |
| 108 | #define xfs_attr_trace_l_c(w,c) | 104 | #define xfs_attr_trace_l_c(w,c) |
| 109 | #define xfs_attr_trace_l_cn(w,c,n) | 105 | #define xfs_attr_trace_l_cn(w,c,n) |
diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c index fab0b6d5a41b..48228848f5ae 100644 --- a/fs/xfs/xfs_bit.c +++ b/fs/xfs/xfs_bit.c | |||
| @@ -25,109 +25,6 @@ | |||
| 25 | * XFS bit manipulation routines, used in non-realtime code. | 25 | * XFS bit manipulation routines, used in non-realtime code. |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #ifndef HAVE_ARCH_HIGHBIT | ||
| 29 | /* | ||
| 30 | * Index of high bit number in byte, -1 for none set, 0..7 otherwise. | ||
| 31 | */ | ||
| 32 | static const char xfs_highbit[256] = { | ||
| 33 | -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ | ||
| 34 | 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ | ||
| 35 | 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ | ||
| 36 | 4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */ | ||
| 37 | 5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */ | ||
| 38 | 5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */ | ||
| 39 | 5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */ | ||
| 40 | 5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */ | ||
| 41 | 6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */ | ||
| 42 | 6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */ | ||
| 43 | 6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */ | ||
| 44 | 6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */ | ||
| 45 | 6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */ | ||
| 46 | 6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */ | ||
| 47 | 6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */ | ||
| 48 | 6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */ | ||
| 49 | 7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */ | ||
| 50 | 7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */ | ||
| 51 | 7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */ | ||
| 52 | 7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */ | ||
| 53 | 7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */ | ||
| 54 | 7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */ | ||
| 55 | 7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */ | ||
| 56 | 7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */ | ||
| 57 | 7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */ | ||
| 58 | 7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */ | ||
| 59 | 7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */ | ||
| 60 | 7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */ | ||
| 61 | 7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */ | ||
| 62 | 7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */ | ||
| 63 | 7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */ | ||
| 64 | 7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */ | ||
| 65 | }; | ||
| 66 | #endif | ||
| 67 | |||
| 68 | /* | ||
| 69 | * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. | ||
| 70 | */ | ||
| 71 | inline int | ||
| 72 | xfs_highbit32( | ||
| 73 | __uint32_t v) | ||
| 74 | { | ||
| 75 | #ifdef HAVE_ARCH_HIGHBIT | ||
| 76 | return highbit32(v); | ||
| 77 | #else | ||
| 78 | int i; | ||
| 79 | |||
| 80 | if (v & 0xffff0000) | ||
| 81 | if (v & 0xff000000) | ||
| 82 | i = 24; | ||
| 83 | else | ||
| 84 | i = 16; | ||
| 85 | else if (v & 0x0000ffff) | ||
| 86 | if (v & 0x0000ff00) | ||
| 87 | i = 8; | ||
| 88 | else | ||
| 89 | i = 0; | ||
| 90 | else | ||
| 91 | return -1; | ||
| 92 | return i + xfs_highbit[(v >> i) & 0xff]; | ||
| 93 | #endif | ||
| 94 | } | ||
| 95 | |||
| 96 | /* | ||
| 97 | * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. | ||
| 98 | */ | ||
| 99 | int | ||
| 100 | xfs_lowbit64( | ||
| 101 | __uint64_t v) | ||
| 102 | { | ||
| 103 | __uint32_t w = (__uint32_t)v; | ||
| 104 | int n = 0; | ||
| 105 | |||
| 106 | if (w) { /* lower bits */ | ||
| 107 | n = ffs(w); | ||
| 108 | } else { /* upper bits */ | ||
| 109 | w = (__uint32_t)(v >> 32); | ||
| 110 | if (w && (n = ffs(w))) | ||
| 111 | n += 32; | ||
| 112 | } | ||
| 113 | return n - 1; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 117 | * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. | ||
| 118 | */ | ||
| 119 | int | ||
| 120 | xfs_highbit64( | ||
| 121 | __uint64_t v) | ||
| 122 | { | ||
| 123 | __uint32_t h = (__uint32_t)(v >> 32); | ||
| 124 | |||
| 125 | if (h) | ||
| 126 | return xfs_highbit32(h) + 32; | ||
| 127 | return xfs_highbit32((__uint32_t)v); | ||
| 128 | } | ||
| 129 | |||
| 130 | |||
| 131 | /* | 28 | /* |
| 132 | * Return whether bitmap is empty. | 29 | * Return whether bitmap is empty. |
| 133 | * Size is number of words in the bitmap, which is padded to word boundary | 30 | * Size is number of words in the bitmap, which is padded to word boundary |
diff --git a/fs/xfs/xfs_bit.h b/fs/xfs/xfs_bit.h index 082641a9782c..8e0e463dae2d 100644 --- a/fs/xfs/xfs_bit.h +++ b/fs/xfs/xfs_bit.h | |||
| @@ -47,13 +47,39 @@ static inline __uint64_t xfs_mask64lo(int n) | |||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | /* Get high bit set out of 32-bit argument, -1 if none set */ | 49 | /* Get high bit set out of 32-bit argument, -1 if none set */ |
| 50 | extern int xfs_highbit32(__uint32_t v); | 50 | static inline int xfs_highbit32(__uint32_t v) |
| 51 | { | ||
| 52 | return fls(v) - 1; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* Get high bit set out of 64-bit argument, -1 if none set */ | ||
| 56 | static inline int xfs_highbit64(__uint64_t v) | ||
| 57 | { | ||
| 58 | return fls64(v) - 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* Get low bit set out of 32-bit argument, -1 if none set */ | ||
| 62 | static inline int xfs_lowbit32(__uint32_t v) | ||
| 63 | { | ||
| 64 | unsigned long t = v; | ||
| 65 | return (v) ? find_first_bit(&t, 32) : -1; | ||
| 66 | } | ||
| 51 | 67 | ||
| 52 | /* Get low bit set out of 64-bit argument, -1 if none set */ | 68 | /* Get low bit set out of 64-bit argument, -1 if none set */ |
| 53 | extern int xfs_lowbit64(__uint64_t v); | 69 | static inline int xfs_lowbit64(__uint64_t v) |
| 70 | { | ||
| 71 | __uint32_t w = (__uint32_t)v; | ||
| 72 | int n = 0; | ||
| 54 | 73 | ||
| 55 | /* Get high bit set out of 64-bit argument, -1 if none set */ | 74 | if (w) { /* lower bits */ |
| 56 | extern int xfs_highbit64(__uint64_t); | 75 | n = ffs(w); |
| 76 | } else { /* upper bits */ | ||
| 77 | w = (__uint32_t)(v >> 32); | ||
| 78 | if (w && (n = ffs(w))) | ||
| 79 | n += 32; | ||
| 80 | } | ||
| 81 | return n - 1; | ||
| 82 | } | ||
| 57 | 83 | ||
| 58 | /* Return whether bitmap is empty (1 == empty) */ | 84 | /* Return whether bitmap is empty (1 == empty) */ |
| 59 | extern int xfs_bitmap_empty(uint *map, uint size); | 85 | extern int xfs_bitmap_empty(uint *map, uint size); |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 53c259f5a5af..a1aab9275d5a 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -384,14 +384,14 @@ xfs_bmap_count_tree( | |||
| 384 | int levelin, | 384 | int levelin, |
| 385 | int *count); | 385 | int *count); |
| 386 | 386 | ||
| 387 | STATIC int | 387 | STATIC void |
| 388 | xfs_bmap_count_leaves( | 388 | xfs_bmap_count_leaves( |
| 389 | xfs_ifork_t *ifp, | 389 | xfs_ifork_t *ifp, |
| 390 | xfs_extnum_t idx, | 390 | xfs_extnum_t idx, |
| 391 | int numrecs, | 391 | int numrecs, |
| 392 | int *count); | 392 | int *count); |
| 393 | 393 | ||
| 394 | STATIC int | 394 | STATIC void |
| 395 | xfs_bmap_disk_count_leaves( | 395 | xfs_bmap_disk_count_leaves( |
| 396 | xfs_extnum_t idx, | 396 | xfs_extnum_t idx, |
| 397 | xfs_bmbt_block_t *block, | 397 | xfs_bmbt_block_t *block, |
| @@ -428,7 +428,8 @@ xfs_bmap_add_attrfork_btree( | |||
| 428 | cur->bc_private.b.firstblock = *firstblock; | 428 | cur->bc_private.b.firstblock = *firstblock; |
| 429 | if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) | 429 | if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) |
| 430 | goto error0; | 430 | goto error0; |
| 431 | ASSERT(stat == 1); /* must be at least one entry */ | 431 | /* must be at least one entry */ |
| 432 | XFS_WANT_CORRUPTED_GOTO(stat == 1, error0); | ||
| 432 | if ((error = xfs_bmbt_newroot(cur, flags, &stat))) | 433 | if ((error = xfs_bmbt_newroot(cur, flags, &stat))) |
| 433 | goto error0; | 434 | goto error0; |
| 434 | if (stat == 0) { | 435 | if (stat == 0) { |
| @@ -816,13 +817,13 @@ xfs_bmap_add_extent_delay_real( | |||
| 816 | RIGHT.br_startblock, | 817 | RIGHT.br_startblock, |
| 817 | RIGHT.br_blockcount, &i))) | 818 | RIGHT.br_blockcount, &i))) |
| 818 | goto done; | 819 | goto done; |
| 819 | ASSERT(i == 1); | 820 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 820 | if ((error = xfs_bmbt_delete(cur, &i))) | 821 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 821 | goto done; | 822 | goto done; |
| 822 | ASSERT(i == 1); | 823 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 823 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | 824 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) |
| 824 | goto done; | 825 | goto done; |
| 825 | ASSERT(i == 1); | 826 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 826 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, | 827 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, |
| 827 | LEFT.br_startblock, | 828 | LEFT.br_startblock, |
| 828 | LEFT.br_blockcount + | 829 | LEFT.br_blockcount + |
| @@ -860,7 +861,7 @@ xfs_bmap_add_extent_delay_real( | |||
| 860 | LEFT.br_startblock, LEFT.br_blockcount, | 861 | LEFT.br_startblock, LEFT.br_blockcount, |
| 861 | &i))) | 862 | &i))) |
| 862 | goto done; | 863 | goto done; |
| 863 | ASSERT(i == 1); | 864 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 864 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, | 865 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, |
| 865 | LEFT.br_startblock, | 866 | LEFT.br_startblock, |
| 866 | LEFT.br_blockcount + | 867 | LEFT.br_blockcount + |
| @@ -895,7 +896,7 @@ xfs_bmap_add_extent_delay_real( | |||
| 895 | RIGHT.br_startblock, | 896 | RIGHT.br_startblock, |
| 896 | RIGHT.br_blockcount, &i))) | 897 | RIGHT.br_blockcount, &i))) |
| 897 | goto done; | 898 | goto done; |
| 898 | ASSERT(i == 1); | 899 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 899 | if ((error = xfs_bmbt_update(cur, PREV.br_startoff, | 900 | if ((error = xfs_bmbt_update(cur, PREV.br_startoff, |
| 900 | new->br_startblock, | 901 | new->br_startblock, |
| 901 | PREV.br_blockcount + | 902 | PREV.br_blockcount + |
| @@ -928,11 +929,11 @@ xfs_bmap_add_extent_delay_real( | |||
| 928 | new->br_startblock, new->br_blockcount, | 929 | new->br_startblock, new->br_blockcount, |
| 929 | &i))) | 930 | &i))) |
| 930 | goto done; | 931 | goto done; |
| 931 | ASSERT(i == 0); | 932 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 932 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 933 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
| 933 | if ((error = xfs_bmbt_insert(cur, &i))) | 934 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 934 | goto done; | 935 | goto done; |
| 935 | ASSERT(i == 1); | 936 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 936 | } | 937 | } |
| 937 | *dnew = 0; | 938 | *dnew = 0; |
| 938 | /* DELTA: The in-core extent described by new changed type. */ | 939 | /* DELTA: The in-core extent described by new changed type. */ |
| @@ -963,7 +964,7 @@ xfs_bmap_add_extent_delay_real( | |||
| 963 | LEFT.br_startblock, LEFT.br_blockcount, | 964 | LEFT.br_startblock, LEFT.br_blockcount, |
| 964 | &i))) | 965 | &i))) |
| 965 | goto done; | 966 | goto done; |
| 966 | ASSERT(i == 1); | 967 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 967 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, | 968 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, |
| 968 | LEFT.br_startblock, | 969 | LEFT.br_startblock, |
| 969 | LEFT.br_blockcount + | 970 | LEFT.br_blockcount + |
| @@ -1004,11 +1005,11 @@ xfs_bmap_add_extent_delay_real( | |||
| 1004 | new->br_startblock, new->br_blockcount, | 1005 | new->br_startblock, new->br_blockcount, |
| 1005 | &i))) | 1006 | &i))) |
| 1006 | goto done; | 1007 | goto done; |
| 1007 | ASSERT(i == 0); | 1008 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 1008 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1009 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
| 1009 | if ((error = xfs_bmbt_insert(cur, &i))) | 1010 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1010 | goto done; | 1011 | goto done; |
| 1011 | ASSERT(i == 1); | 1012 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1012 | } | 1013 | } |
| 1013 | if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && | 1014 | if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && |
| 1014 | ip->i_d.di_nextents > ip->i_df.if_ext_max) { | 1015 | ip->i_d.di_nextents > ip->i_df.if_ext_max) { |
| @@ -1054,7 +1055,7 @@ xfs_bmap_add_extent_delay_real( | |||
| 1054 | RIGHT.br_startblock, | 1055 | RIGHT.br_startblock, |
| 1055 | RIGHT.br_blockcount, &i))) | 1056 | RIGHT.br_blockcount, &i))) |
| 1056 | goto done; | 1057 | goto done; |
| 1057 | ASSERT(i == 1); | 1058 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1058 | if ((error = xfs_bmbt_update(cur, new->br_startoff, | 1059 | if ((error = xfs_bmbt_update(cur, new->br_startoff, |
| 1059 | new->br_startblock, | 1060 | new->br_startblock, |
| 1060 | new->br_blockcount + | 1061 | new->br_blockcount + |
| @@ -1094,11 +1095,11 @@ xfs_bmap_add_extent_delay_real( | |||
| 1094 | new->br_startblock, new->br_blockcount, | 1095 | new->br_startblock, new->br_blockcount, |
| 1095 | &i))) | 1096 | &i))) |
| 1096 | goto done; | 1097 | goto done; |
| 1097 | ASSERT(i == 0); | 1098 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 1098 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1099 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
| 1099 | if ((error = xfs_bmbt_insert(cur, &i))) | 1100 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1100 | goto done; | 1101 | goto done; |
| 1101 | ASSERT(i == 1); | 1102 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1102 | } | 1103 | } |
| 1103 | if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && | 1104 | if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && |
| 1104 | ip->i_d.di_nextents > ip->i_df.if_ext_max) { | 1105 | ip->i_d.di_nextents > ip->i_df.if_ext_max) { |
| @@ -1149,11 +1150,11 @@ xfs_bmap_add_extent_delay_real( | |||
| 1149 | new->br_startblock, new->br_blockcount, | 1150 | new->br_startblock, new->br_blockcount, |
| 1150 | &i))) | 1151 | &i))) |
| 1151 | goto done; | 1152 | goto done; |
| 1152 | ASSERT(i == 0); | 1153 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 1153 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1154 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
| 1154 | if ((error = xfs_bmbt_insert(cur, &i))) | 1155 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1155 | goto done; | 1156 | goto done; |
| 1156 | ASSERT(i == 1); | 1157 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1157 | } | 1158 | } |
| 1158 | if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && | 1159 | if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && |
| 1159 | ip->i_d.di_nextents > ip->i_df.if_ext_max) { | 1160 | ip->i_d.di_nextents > ip->i_df.if_ext_max) { |
| @@ -1377,19 +1378,19 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1377 | RIGHT.br_startblock, | 1378 | RIGHT.br_startblock, |
| 1378 | RIGHT.br_blockcount, &i))) | 1379 | RIGHT.br_blockcount, &i))) |
| 1379 | goto done; | 1380 | goto done; |
| 1380 | ASSERT(i == 1); | 1381 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1381 | if ((error = xfs_bmbt_delete(cur, &i))) | 1382 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 1382 | goto done; | 1383 | goto done; |
| 1383 | ASSERT(i == 1); | 1384 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1384 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | 1385 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) |
| 1385 | goto done; | 1386 | goto done; |
| 1386 | ASSERT(i == 1); | 1387 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1387 | if ((error = xfs_bmbt_delete(cur, &i))) | 1388 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 1388 | goto done; | 1389 | goto done; |
| 1389 | ASSERT(i == 1); | 1390 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1390 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | 1391 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) |
| 1391 | goto done; | 1392 | goto done; |
| 1392 | ASSERT(i == 1); | 1393 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1393 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, | 1394 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, |
| 1394 | LEFT.br_startblock, | 1395 | LEFT.br_startblock, |
| 1395 | LEFT.br_blockcount + PREV.br_blockcount + | 1396 | LEFT.br_blockcount + PREV.br_blockcount + |
| @@ -1426,13 +1427,13 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1426 | PREV.br_startblock, PREV.br_blockcount, | 1427 | PREV.br_startblock, PREV.br_blockcount, |
| 1427 | &i))) | 1428 | &i))) |
| 1428 | goto done; | 1429 | goto done; |
| 1429 | ASSERT(i == 1); | 1430 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1430 | if ((error = xfs_bmbt_delete(cur, &i))) | 1431 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 1431 | goto done; | 1432 | goto done; |
| 1432 | ASSERT(i == 1); | 1433 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1433 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | 1434 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) |
| 1434 | goto done; | 1435 | goto done; |
| 1435 | ASSERT(i == 1); | 1436 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1436 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, | 1437 | if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, |
| 1437 | LEFT.br_startblock, | 1438 | LEFT.br_startblock, |
| 1438 | LEFT.br_blockcount + PREV.br_blockcount, | 1439 | LEFT.br_blockcount + PREV.br_blockcount, |
| @@ -1469,13 +1470,13 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1469 | RIGHT.br_startblock, | 1470 | RIGHT.br_startblock, |
| 1470 | RIGHT.br_blockcount, &i))) | 1471 | RIGHT.br_blockcount, &i))) |
| 1471 | goto done; | 1472 | goto done; |
| 1472 | ASSERT(i == 1); | 1473 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1473 | if ((error = xfs_bmbt_delete(cur, &i))) | 1474 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 1474 | goto done; | 1475 | goto done; |
| 1475 | ASSERT(i == 1); | 1476 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1476 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | 1477 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) |
| 1477 | goto done; | 1478 | goto done; |
| 1478 | ASSERT(i == 1); | 1479 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1479 | if ((error = xfs_bmbt_update(cur, new->br_startoff, | 1480 | if ((error = xfs_bmbt_update(cur, new->br_startoff, |
| 1480 | new->br_startblock, | 1481 | new->br_startblock, |
| 1481 | new->br_blockcount + RIGHT.br_blockcount, | 1482 | new->br_blockcount + RIGHT.br_blockcount, |
| @@ -1508,7 +1509,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1508 | new->br_startblock, new->br_blockcount, | 1509 | new->br_startblock, new->br_blockcount, |
| 1509 | &i))) | 1510 | &i))) |
| 1510 | goto done; | 1511 | goto done; |
| 1511 | ASSERT(i == 1); | 1512 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1512 | if ((error = xfs_bmbt_update(cur, new->br_startoff, | 1513 | if ((error = xfs_bmbt_update(cur, new->br_startoff, |
| 1513 | new->br_startblock, new->br_blockcount, | 1514 | new->br_startblock, new->br_blockcount, |
| 1514 | newext))) | 1515 | newext))) |
| @@ -1549,7 +1550,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1549 | PREV.br_startblock, PREV.br_blockcount, | 1550 | PREV.br_startblock, PREV.br_blockcount, |
| 1550 | &i))) | 1551 | &i))) |
| 1551 | goto done; | 1552 | goto done; |
| 1552 | ASSERT(i == 1); | 1553 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1553 | if ((error = xfs_bmbt_update(cur, | 1554 | if ((error = xfs_bmbt_update(cur, |
| 1554 | PREV.br_startoff + new->br_blockcount, | 1555 | PREV.br_startoff + new->br_blockcount, |
| 1555 | PREV.br_startblock + new->br_blockcount, | 1556 | PREV.br_startblock + new->br_blockcount, |
| @@ -1596,7 +1597,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1596 | PREV.br_startblock, PREV.br_blockcount, | 1597 | PREV.br_startblock, PREV.br_blockcount, |
| 1597 | &i))) | 1598 | &i))) |
| 1598 | goto done; | 1599 | goto done; |
| 1599 | ASSERT(i == 1); | 1600 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1600 | if ((error = xfs_bmbt_update(cur, | 1601 | if ((error = xfs_bmbt_update(cur, |
| 1601 | PREV.br_startoff + new->br_blockcount, | 1602 | PREV.br_startoff + new->br_blockcount, |
| 1602 | PREV.br_startblock + new->br_blockcount, | 1603 | PREV.br_startblock + new->br_blockcount, |
| @@ -1606,7 +1607,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1606 | cur->bc_rec.b = *new; | 1607 | cur->bc_rec.b = *new; |
| 1607 | if ((error = xfs_bmbt_insert(cur, &i))) | 1608 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1608 | goto done; | 1609 | goto done; |
| 1609 | ASSERT(i == 1); | 1610 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1610 | } | 1611 | } |
| 1611 | /* DELTA: One in-core extent is split in two. */ | 1612 | /* DELTA: One in-core extent is split in two. */ |
| 1612 | temp = PREV.br_startoff; | 1613 | temp = PREV.br_startoff; |
| @@ -1640,7 +1641,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1640 | PREV.br_startblock, | 1641 | PREV.br_startblock, |
| 1641 | PREV.br_blockcount, &i))) | 1642 | PREV.br_blockcount, &i))) |
| 1642 | goto done; | 1643 | goto done; |
| 1643 | ASSERT(i == 1); | 1644 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1644 | if ((error = xfs_bmbt_update(cur, PREV.br_startoff, | 1645 | if ((error = xfs_bmbt_update(cur, PREV.br_startoff, |
| 1645 | PREV.br_startblock, | 1646 | PREV.br_startblock, |
| 1646 | PREV.br_blockcount - new->br_blockcount, | 1647 | PREV.br_blockcount - new->br_blockcount, |
| @@ -1682,7 +1683,7 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1682 | PREV.br_startblock, PREV.br_blockcount, | 1683 | PREV.br_startblock, PREV.br_blockcount, |
| 1683 | &i))) | 1684 | &i))) |
| 1684 | goto done; | 1685 | goto done; |
| 1685 | ASSERT(i == 1); | 1686 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1686 | if ((error = xfs_bmbt_update(cur, PREV.br_startoff, | 1687 | if ((error = xfs_bmbt_update(cur, PREV.br_startoff, |
| 1687 | PREV.br_startblock, | 1688 | PREV.br_startblock, |
| 1688 | PREV.br_blockcount - new->br_blockcount, | 1689 | PREV.br_blockcount - new->br_blockcount, |
| @@ -1692,11 +1693,11 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1692 | new->br_startblock, new->br_blockcount, | 1693 | new->br_startblock, new->br_blockcount, |
| 1693 | &i))) | 1694 | &i))) |
| 1694 | goto done; | 1695 | goto done; |
| 1695 | ASSERT(i == 0); | 1696 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 1696 | cur->bc_rec.b.br_state = XFS_EXT_NORM; | 1697 | cur->bc_rec.b.br_state = XFS_EXT_NORM; |
| 1697 | if ((error = xfs_bmbt_insert(cur, &i))) | 1698 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1698 | goto done; | 1699 | goto done; |
| 1699 | ASSERT(i == 1); | 1700 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1700 | } | 1701 | } |
| 1701 | /* DELTA: One in-core extent is split in two. */ | 1702 | /* DELTA: One in-core extent is split in two. */ |
| 1702 | temp = PREV.br_startoff; | 1703 | temp = PREV.br_startoff; |
| @@ -1732,27 +1733,34 @@ xfs_bmap_add_extent_unwritten_real( | |||
| 1732 | PREV.br_startblock, PREV.br_blockcount, | 1733 | PREV.br_startblock, PREV.br_blockcount, |
| 1733 | &i))) | 1734 | &i))) |
| 1734 | goto done; | 1735 | goto done; |
| 1735 | ASSERT(i == 1); | 1736 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1736 | /* new right extent - oldext */ | 1737 | /* new right extent - oldext */ |
| 1737 | if ((error = xfs_bmbt_update(cur, r[1].br_startoff, | 1738 | if ((error = xfs_bmbt_update(cur, r[1].br_startoff, |
| 1738 | r[1].br_startblock, r[1].br_blockcount, | 1739 | r[1].br_startblock, r[1].br_blockcount, |
| 1739 | r[1].br_state))) | 1740 | r[1].br_state))) |
| 1740 | goto done; | 1741 | goto done; |
| 1741 | /* new left extent - oldext */ | 1742 | /* new left extent - oldext */ |
| 1742 | PREV.br_blockcount = | ||
| 1743 | new->br_startoff - PREV.br_startoff; | ||
| 1744 | cur->bc_rec.b = PREV; | 1743 | cur->bc_rec.b = PREV; |
| 1744 | cur->bc_rec.b.br_blockcount = | ||
| 1745 | new->br_startoff - PREV.br_startoff; | ||
| 1745 | if ((error = xfs_bmbt_insert(cur, &i))) | 1746 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1746 | goto done; | 1747 | goto done; |
| 1747 | ASSERT(i == 1); | 1748 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1748 | if ((error = xfs_bmbt_increment(cur, 0, &i))) | 1749 | /* |
| 1750 | * Reset the cursor to the position of the new extent | ||
| 1751 | * we are about to insert as we can't trust it after | ||
| 1752 | * the previous insert. | ||
| 1753 | */ | ||
| 1754 | if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, | ||
| 1755 | new->br_startblock, new->br_blockcount, | ||
| 1756 | &i))) | ||
| 1749 | goto done; | 1757 | goto done; |
| 1750 | ASSERT(i == 1); | 1758 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 1751 | /* new middle extent - newext */ | 1759 | /* new middle extent - newext */ |
| 1752 | cur->bc_rec.b = *new; | 1760 | cur->bc_rec.b.br_state = new->br_state; |
| 1753 | if ((error = xfs_bmbt_insert(cur, &i))) | 1761 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 1754 | goto done; | 1762 | goto done; |
| 1755 | ASSERT(i == 1); | 1763 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 1756 | } | 1764 | } |
| 1757 | /* DELTA: One in-core extent is split in three. */ | 1765 | /* DELTA: One in-core extent is split in three. */ |
| 1758 | temp = PREV.br_startoff; | 1766 | temp = PREV.br_startoff; |
| @@ -2097,13 +2105,13 @@ xfs_bmap_add_extent_hole_real( | |||
| 2097 | right.br_startblock, | 2105 | right.br_startblock, |
| 2098 | right.br_blockcount, &i))) | 2106 | right.br_blockcount, &i))) |
| 2099 | goto done; | 2107 | goto done; |
| 2100 | ASSERT(i == 1); | 2108 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 2101 | if ((error = xfs_bmbt_delete(cur, &i))) | 2109 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 2102 | goto done; | 2110 | goto done; |
| 2103 | ASSERT(i == 1); | 2111 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 2104 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) | 2112 | if ((error = xfs_bmbt_decrement(cur, 0, &i))) |
| 2105 | goto done; | 2113 | goto done; |
| 2106 | ASSERT(i == 1); | 2114 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 2107 | if ((error = xfs_bmbt_update(cur, left.br_startoff, | 2115 | if ((error = xfs_bmbt_update(cur, left.br_startoff, |
| 2108 | left.br_startblock, | 2116 | left.br_startblock, |
| 2109 | left.br_blockcount + | 2117 | left.br_blockcount + |
| @@ -2139,7 +2147,7 @@ xfs_bmap_add_extent_hole_real( | |||
| 2139 | left.br_startblock, | 2147 | left.br_startblock, |
| 2140 | left.br_blockcount, &i))) | 2148 | left.br_blockcount, &i))) |
| 2141 | goto done; | 2149 | goto done; |
| 2142 | ASSERT(i == 1); | 2150 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 2143 | if ((error = xfs_bmbt_update(cur, left.br_startoff, | 2151 | if ((error = xfs_bmbt_update(cur, left.br_startoff, |
| 2144 | left.br_startblock, | 2152 | left.br_startblock, |
| 2145 | left.br_blockcount + | 2153 | left.br_blockcount + |
| @@ -2174,7 +2182,7 @@ xfs_bmap_add_extent_hole_real( | |||
| 2174 | right.br_startblock, | 2182 | right.br_startblock, |
| 2175 | right.br_blockcount, &i))) | 2183 | right.br_blockcount, &i))) |
| 2176 | goto done; | 2184 | goto done; |
| 2177 | ASSERT(i == 1); | 2185 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 2178 | if ((error = xfs_bmbt_update(cur, new->br_startoff, | 2186 | if ((error = xfs_bmbt_update(cur, new->br_startoff, |
| 2179 | new->br_startblock, | 2187 | new->br_startblock, |
| 2180 | new->br_blockcount + | 2188 | new->br_blockcount + |
| @@ -2208,11 +2216,11 @@ xfs_bmap_add_extent_hole_real( | |||
| 2208 | new->br_startblock, | 2216 | new->br_startblock, |
| 2209 | new->br_blockcount, &i))) | 2217 | new->br_blockcount, &i))) |
| 2210 | goto done; | 2218 | goto done; |
| 2211 | ASSERT(i == 0); | 2219 | XFS_WANT_CORRUPTED_GOTO(i == 0, done); |
| 2212 | cur->bc_rec.b.br_state = new->br_state; | 2220 | cur->bc_rec.b.br_state = new->br_state; |
| 2213 | if ((error = xfs_bmbt_insert(cur, &i))) | 2221 | if ((error = xfs_bmbt_insert(cur, &i))) |
| 2214 | goto done; | 2222 | goto done; |
| 2215 | ASSERT(i == 1); | 2223 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 2216 | } | 2224 | } |
| 2217 | /* DELTA: A new extent was added in a hole. */ | 2225 | /* DELTA: A new extent was added in a hole. */ |
| 2218 | temp = new->br_startoff; | 2226 | temp = new->br_startoff; |
| @@ -3131,7 +3139,7 @@ xfs_bmap_del_extent( | |||
| 3131 | got.br_startblock, got.br_blockcount, | 3139 | got.br_startblock, got.br_blockcount, |
| 3132 | &i))) | 3140 | &i))) |
| 3133 | goto done; | 3141 | goto done; |
| 3134 | ASSERT(i == 1); | 3142 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 3135 | } | 3143 | } |
| 3136 | da_old = da_new = 0; | 3144 | da_old = da_new = 0; |
| 3137 | } else { | 3145 | } else { |
| @@ -3164,7 +3172,7 @@ xfs_bmap_del_extent( | |||
| 3164 | } | 3172 | } |
| 3165 | if ((error = xfs_bmbt_delete(cur, &i))) | 3173 | if ((error = xfs_bmbt_delete(cur, &i))) |
| 3166 | goto done; | 3174 | goto done; |
| 3167 | ASSERT(i == 1); | 3175 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 3168 | break; | 3176 | break; |
| 3169 | 3177 | ||
| 3170 | case 2: | 3178 | case 2: |
| @@ -3268,7 +3276,7 @@ xfs_bmap_del_extent( | |||
| 3268 | got.br_startblock, | 3276 | got.br_startblock, |
| 3269 | temp, &i))) | 3277 | temp, &i))) |
| 3270 | goto done; | 3278 | goto done; |
| 3271 | ASSERT(i == 1); | 3279 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 3272 | /* | 3280 | /* |
| 3273 | * Update the btree record back | 3281 | * Update the btree record back |
| 3274 | * to the original value. | 3282 | * to the original value. |
| @@ -3289,7 +3297,7 @@ xfs_bmap_del_extent( | |||
| 3289 | error = XFS_ERROR(ENOSPC); | 3297 | error = XFS_ERROR(ENOSPC); |
| 3290 | goto done; | 3298 | goto done; |
| 3291 | } | 3299 | } |
| 3292 | ASSERT(i == 1); | 3300 | XFS_WANT_CORRUPTED_GOTO(i == 1, done); |
| 3293 | } else | 3301 | } else |
| 3294 | flags |= XFS_ILOG_FEXT(whichfork); | 3302 | flags |= XFS_ILOG_FEXT(whichfork); |
| 3295 | XFS_IFORK_NEXT_SET(ip, whichfork, | 3303 | XFS_IFORK_NEXT_SET(ip, whichfork, |
| @@ -3992,7 +4000,7 @@ xfs_bmap_add_attrfork( | |||
| 3992 | ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; | 4000 | ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; |
| 3993 | } | 4001 | } |
| 3994 | ASSERT(ip->i_d.di_anextents == 0); | 4002 | ASSERT(ip->i_d.di_anextents == 0); |
| 3995 | VN_HOLD(XFS_ITOV(ip)); | 4003 | IHOLD(ip); |
| 3996 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 4004 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
| 3997 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 4005 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 3998 | switch (ip->i_d.di_format) { | 4006 | switch (ip->i_d.di_format) { |
| @@ -5970,7 +5978,7 @@ unlock_and_return: | |||
| 5970 | xfs_iunlock_map_shared(ip, lock); | 5978 | xfs_iunlock_map_shared(ip, lock); |
| 5971 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 5979 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
| 5972 | 5980 | ||
| 5973 | kmem_free(map, subnex * sizeof(*map)); | 5981 | kmem_free(map); |
| 5974 | 5982 | ||
| 5975 | return error; | 5983 | return error; |
| 5976 | } | 5984 | } |
| @@ -6088,7 +6096,7 @@ xfs_bmap_get_bp( | |||
| 6088 | tp = cur->bc_tp; | 6096 | tp = cur->bc_tp; |
| 6089 | licp = &tp->t_items; | 6097 | licp = &tp->t_items; |
| 6090 | while (!bp && licp != NULL) { | 6098 | while (!bp && licp != NULL) { |
| 6091 | if (XFS_LIC_ARE_ALL_FREE(licp)) { | 6099 | if (xfs_lic_are_all_free(licp)) { |
| 6092 | licp = licp->lic_next; | 6100 | licp = licp->lic_next; |
| 6093 | continue; | 6101 | continue; |
| 6094 | } | 6102 | } |
| @@ -6098,11 +6106,11 @@ xfs_bmap_get_bp( | |||
| 6098 | xfs_buf_log_item_t *bip; | 6106 | xfs_buf_log_item_t *bip; |
| 6099 | xfs_buf_t *lbp; | 6107 | xfs_buf_t *lbp; |
| 6100 | 6108 | ||
| 6101 | if (XFS_LIC_ISFREE(licp, i)) { | 6109 | if (xfs_lic_isfree(licp, i)) { |
| 6102 | continue; | 6110 | continue; |
| 6103 | } | 6111 | } |
| 6104 | 6112 | ||
| 6105 | lidp = XFS_LIC_SLOT(licp, i); | 6113 | lidp = xfs_lic_slot(licp, i); |
| 6106 | lip = lidp->lid_item; | 6114 | lip = lidp->lid_item; |
| 6107 | if (lip->li_type != XFS_LI_BUF) | 6115 | if (lip->li_type != XFS_LI_BUF) |
| 6108 | continue; | 6116 | continue; |
| @@ -6359,13 +6367,9 @@ xfs_bmap_count_blocks( | |||
| 6359 | mp = ip->i_mount; | 6367 | mp = ip->i_mount; |
| 6360 | ifp = XFS_IFORK_PTR(ip, whichfork); | 6368 | ifp = XFS_IFORK_PTR(ip, whichfork); |
| 6361 | if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) { | 6369 | if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) { |
| 6362 | if (unlikely(xfs_bmap_count_leaves(ifp, 0, | 6370 | xfs_bmap_count_leaves(ifp, 0, |
| 6363 | ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t), | 6371 | ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t), |
| 6364 | count) < 0)) { | 6372 | count); |
| 6365 | XFS_ERROR_REPORT("xfs_bmap_count_blocks(1)", | ||
| 6366 | XFS_ERRLEVEL_LOW, mp); | ||
| 6367 | return XFS_ERROR(EFSCORRUPTED); | ||
| 6368 | } | ||
| 6369 | return 0; | 6373 | return 0; |
| 6370 | } | 6374 | } |
| 6371 | 6375 | ||
| @@ -6446,13 +6450,7 @@ xfs_bmap_count_tree( | |||
| 6446 | for (;;) { | 6450 | for (;;) { |
| 6447 | nextbno = be64_to_cpu(block->bb_rightsib); | 6451 | nextbno = be64_to_cpu(block->bb_rightsib); |
| 6448 | numrecs = be16_to_cpu(block->bb_numrecs); | 6452 | numrecs = be16_to_cpu(block->bb_numrecs); |
| 6449 | if (unlikely(xfs_bmap_disk_count_leaves(0, | 6453 | xfs_bmap_disk_count_leaves(0, block, numrecs, count); |
| 6450 | block, numrecs, count) < 0)) { | ||
| 6451 | xfs_trans_brelse(tp, bp); | ||
| 6452 | XFS_ERROR_REPORT("xfs_bmap_count_tree(2)", | ||
| 6453 | XFS_ERRLEVEL_LOW, mp); | ||
| 6454 | return XFS_ERROR(EFSCORRUPTED); | ||
| 6455 | } | ||
| 6456 | xfs_trans_brelse(tp, bp); | 6454 | xfs_trans_brelse(tp, bp); |
| 6457 | if (nextbno == NULLFSBLOCK) | 6455 | if (nextbno == NULLFSBLOCK) |
| 6458 | break; | 6456 | break; |
| @@ -6470,7 +6468,7 @@ xfs_bmap_count_tree( | |||
| 6470 | /* | 6468 | /* |
| 6471 | * Count leaf blocks given a range of extent records. | 6469 | * Count leaf blocks given a range of extent records. |
| 6472 | */ | 6470 | */ |
| 6473 | STATIC int | 6471 | STATIC void |
| 6474 | xfs_bmap_count_leaves( | 6472 | xfs_bmap_count_leaves( |
| 6475 | xfs_ifork_t *ifp, | 6473 | xfs_ifork_t *ifp, |
| 6476 | xfs_extnum_t idx, | 6474 | xfs_extnum_t idx, |
| @@ -6483,14 +6481,13 @@ xfs_bmap_count_leaves( | |||
| 6483 | xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, idx + b); | 6481 | xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, idx + b); |
| 6484 | *count += xfs_bmbt_get_blockcount(frp); | 6482 | *count += xfs_bmbt_get_blockcount(frp); |
| 6485 | } | 6483 | } |
| 6486 | return 0; | ||
| 6487 | } | 6484 | } |
| 6488 | 6485 | ||
| 6489 | /* | 6486 | /* |
| 6490 | * Count leaf blocks given a range of extent records originally | 6487 | * Count leaf blocks given a range of extent records originally |
| 6491 | * in btree format. | 6488 | * in btree format. |
| 6492 | */ | 6489 | */ |
| 6493 | STATIC int | 6490 | STATIC void |
| 6494 | xfs_bmap_disk_count_leaves( | 6491 | xfs_bmap_disk_count_leaves( |
| 6495 | xfs_extnum_t idx, | 6492 | xfs_extnum_t idx, |
| 6496 | xfs_bmbt_block_t *block, | 6493 | xfs_bmbt_block_t *block, |
| @@ -6504,5 +6501,4 @@ xfs_bmap_disk_count_leaves( | |||
| 6504 | frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, idx + b); | 6501 | frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, idx + b); |
| 6505 | *count += xfs_bmbt_disk_get_blockcount(frp); | 6502 | *count += xfs_bmbt_disk_get_blockcount(frp); |
| 6506 | } | 6503 | } |
| 6507 | return 0; | ||
| 6508 | } | 6504 | } |
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 6ff70cda451c..9f3e3a836d15 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h | |||
| @@ -54,12 +54,23 @@ typedef struct xfs_bmap_free_item | |||
| 54 | 54 | ||
| 55 | /* | 55 | /* |
| 56 | * Header for free extent list. | 56 | * Header for free extent list. |
| 57 | * | ||
| 58 | * xbf_low is used by the allocator to activate the lowspace algorithm - | ||
| 59 | * when free space is running low the extent allocator may choose to | ||
| 60 | * allocate an extent from an AG without leaving sufficient space for | ||
| 61 | * a btree split when inserting the new extent. In this case the allocator | ||
| 62 | * will enable the lowspace algorithm which is supposed to allow further | ||
| 63 | * allocations (such as btree splits and newroots) to allocate from | ||
| 64 | * sequential AGs. In order to avoid locking AGs out of order the lowspace | ||
| 65 | * algorithm will start searching for free space from AG 0. If the correct | ||
| 66 | * transaction reservations have been made then this algorithm will eventually | ||
| 67 | * find all the space it needs. | ||
| 57 | */ | 68 | */ |
| 58 | typedef struct xfs_bmap_free | 69 | typedef struct xfs_bmap_free |
| 59 | { | 70 | { |
| 60 | xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ | 71 | xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ |
| 61 | int xbf_count; /* count of items on list */ | 72 | int xbf_count; /* count of items on list */ |
| 62 | int xbf_low; /* kludge: alloc in low mode */ | 73 | int xbf_low; /* alloc in low mode */ |
| 63 | } xfs_bmap_free_t; | 74 | } xfs_bmap_free_t; |
| 64 | 75 | ||
| 65 | #define XFS_BMAP_MAX_NMAP 4 | 76 | #define XFS_BMAP_MAX_NMAP 4 |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index 4f0e849d973e..23efad29a5cd 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
| @@ -1493,12 +1493,27 @@ xfs_bmbt_split( | |||
| 1493 | left = XFS_BUF_TO_BMBT_BLOCK(lbp); | 1493 | left = XFS_BUF_TO_BMBT_BLOCK(lbp); |
| 1494 | args.fsbno = cur->bc_private.b.firstblock; | 1494 | args.fsbno = cur->bc_private.b.firstblock; |
| 1495 | args.firstblock = args.fsbno; | 1495 | args.firstblock = args.fsbno; |
| 1496 | args.minleft = 0; | ||
| 1496 | if (args.fsbno == NULLFSBLOCK) { | 1497 | if (args.fsbno == NULLFSBLOCK) { |
| 1497 | args.fsbno = lbno; | 1498 | args.fsbno = lbno; |
| 1498 | args.type = XFS_ALLOCTYPE_START_BNO; | 1499 | args.type = XFS_ALLOCTYPE_START_BNO; |
| 1499 | } else | 1500 | /* |
| 1501 | * Make sure there is sufficient room left in the AG to | ||
| 1502 | * complete a full tree split for an extent insert. If | ||
| 1503 | * we are converting the middle part of an extent then | ||
| 1504 | * we may need space for two tree splits. | ||
| 1505 | * | ||
| 1506 | * We are relying on the caller to make the correct block | ||
| 1507 | * reservation for this operation to succeed. If the | ||
| 1508 | * reservation amount is insufficient then we may fail a | ||
| 1509 | * block allocation here and corrupt the filesystem. | ||
| 1510 | */ | ||
| 1511 | args.minleft = xfs_trans_get_block_res(args.tp); | ||
| 1512 | } else if (cur->bc_private.b.flist->xbf_low) | ||
| 1513 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
| 1514 | else | ||
| 1500 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 1515 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
| 1501 | args.mod = args.minleft = args.alignment = args.total = args.isfl = | 1516 | args.mod = args.alignment = args.total = args.isfl = |
| 1502 | args.userdata = args.minalignslop = 0; | 1517 | args.userdata = args.minalignslop = 0; |
| 1503 | args.minlen = args.maxlen = args.prod = 1; | 1518 | args.minlen = args.maxlen = args.prod = 1; |
| 1504 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; | 1519 | args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; |
| @@ -1510,6 +1525,21 @@ xfs_bmbt_split( | |||
| 1510 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 1525 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
| 1511 | return error; | 1526 | return error; |
| 1512 | } | 1527 | } |
| 1528 | if (args.fsbno == NULLFSBLOCK && args.minleft) { | ||
| 1529 | /* | ||
| 1530 | * Could not find an AG with enough free space to satisfy | ||
| 1531 | * a full btree split. Try again without minleft and if | ||
| 1532 | * successful activate the lowspace algorithm. | ||
| 1533 | */ | ||
| 1534 | args.fsbno = 0; | ||
| 1535 | args.type = XFS_ALLOCTYPE_FIRST_AG; | ||
| 1536 | args.minleft = 0; | ||
| 1537 | if ((error = xfs_alloc_vextent(&args))) { | ||
| 1538 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | ||
| 1539 | return error; | ||
| 1540 | } | ||
| 1541 | cur->bc_private.b.flist->xbf_low = 1; | ||
| 1542 | } | ||
| 1513 | if (args.fsbno == NULLFSBLOCK) { | 1543 | if (args.fsbno == NULLFSBLOCK) { |
| 1514 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | 1544 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); |
| 1515 | *stat = 0; | 1545 | *stat = 0; |
| @@ -2029,22 +2059,8 @@ xfs_bmbt_increment( | |||
| 2029 | * Insert the current record at the point referenced by cur. | 2059 | * Insert the current record at the point referenced by cur. |
| 2030 | * | 2060 | * |
| 2031 | * A multi-level split of the tree on insert will invalidate the original | 2061 | * A multi-level split of the tree on insert will invalidate the original |
| 2032 | * cursor. It appears, however, that some callers assume that the cursor is | 2062 | * cursor. All callers of this function should assume that the cursor is |
| 2033 | * always valid. Hence if we do a multi-level split we need to revalidate the | 2063 | * no longer valid and revalidate it. |
| 2034 | * cursor. | ||
| 2035 | * | ||
| 2036 | * When a split occurs, we will see a new cursor returned. Use that as a | ||
| 2037 | * trigger to determine if we need to revalidate the original cursor. If we get | ||
| 2038 | * a split, then use the original irec to lookup up the path of the record we | ||
| 2039 | * just inserted. | ||
| 2040 | * | ||
| 2041 | * Note that the fact that the btree root is in the inode means that we can | ||
| 2042 | * have the level of the tree change without a "split" occurring at the root | ||
| 2043 | * level. What happens is that the root is migrated to an allocated block and | ||
| 2044 | * the inode root is pointed to it. This means a single split can change the | ||
| 2045 | * level of the tree (level 2 -> level 3) and invalidate the old cursor. Hence | ||
| 2046 | * the level change should be accounted as a split so as to correctly trigger a | ||
| 2047 | * revalidation of the old cursor. | ||
| 2048 | */ | 2064 | */ |
| 2049 | int /* error */ | 2065 | int /* error */ |
| 2050 | xfs_bmbt_insert( | 2066 | xfs_bmbt_insert( |
| @@ -2057,14 +2073,11 @@ xfs_bmbt_insert( | |||
| 2057 | xfs_fsblock_t nbno; | 2073 | xfs_fsblock_t nbno; |
| 2058 | xfs_btree_cur_t *ncur; | 2074 | xfs_btree_cur_t *ncur; |
| 2059 | xfs_bmbt_rec_t nrec; | 2075 | xfs_bmbt_rec_t nrec; |
| 2060 | xfs_bmbt_irec_t oirec; /* original irec */ | ||
| 2061 | xfs_btree_cur_t *pcur; | 2076 | xfs_btree_cur_t *pcur; |
| 2062 | int splits = 0; | ||
| 2063 | 2077 | ||
| 2064 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); | 2078 | XFS_BMBT_TRACE_CURSOR(cur, ENTRY); |
| 2065 | level = 0; | 2079 | level = 0; |
| 2066 | nbno = NULLFSBLOCK; | 2080 | nbno = NULLFSBLOCK; |
| 2067 | oirec = cur->bc_rec.b; | ||
| 2068 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); | 2081 | xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b); |
| 2069 | ncur = NULL; | 2082 | ncur = NULL; |
| 2070 | pcur = cur; | 2083 | pcur = cur; |
| @@ -2073,13 +2086,11 @@ xfs_bmbt_insert( | |||
| 2073 | &i))) { | 2086 | &i))) { |
| 2074 | if (pcur != cur) | 2087 | if (pcur != cur) |
| 2075 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); | 2088 | xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); |
| 2076 | goto error0; | 2089 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
| 2090 | return error; | ||
| 2077 | } | 2091 | } |
| 2078 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); | 2092 | XFS_WANT_CORRUPTED_GOTO(i == 1, error0); |
| 2079 | if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { | 2093 | if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { |
| 2080 | /* allocating a new root is effectively a split */ | ||
| 2081 | if (cur->bc_nlevels != pcur->bc_nlevels) | ||
| 2082 | splits++; | ||
| 2083 | cur->bc_nlevels = pcur->bc_nlevels; | 2094 | cur->bc_nlevels = pcur->bc_nlevels; |
| 2084 | cur->bc_private.b.allocated += | 2095 | cur->bc_private.b.allocated += |
| 2085 | pcur->bc_private.b.allocated; | 2096 | pcur->bc_private.b.allocated; |
| @@ -2093,21 +2104,10 @@ xfs_bmbt_insert( | |||
| 2093 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); | 2104 | xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); |
| 2094 | } | 2105 | } |
| 2095 | if (ncur) { | 2106 | if (ncur) { |
| 2096 | splits++; | ||
| 2097 | pcur = ncur; | 2107 | pcur = ncur; |
| 2098 | ncur = NULL; | 2108 | ncur = NULL; |
| 2099 | } | 2109 | } |
| 2100 | } while (nbno != NULLFSBLOCK); | 2110 | } while (nbno != NULLFSBLOCK); |
| 2101 | |||
| 2102 | if (splits > 1) { | ||
| 2103 | /* revalidate the old cursor as we had a multi-level split */ | ||
| 2104 | error = xfs_bmbt_lookup_eq(cur, oirec.br_startoff, | ||
| 2105 | oirec.br_startblock, oirec.br_blockcount, &i); | ||
| 2106 | if (error) | ||
| 2107 | goto error0; | ||
| 2108 | ASSERT(i == 1); | ||
| 2109 | } | ||
| 2110 | |||
| 2111 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); | 2111 | XFS_BMBT_TRACE_CURSOR(cur, EXIT); |
| 2112 | *stat = i; | 2112 | *stat = i; |
| 2113 | return 0; | 2113 | return 0; |
| @@ -2254,7 +2254,9 @@ xfs_bmbt_newroot( | |||
| 2254 | #endif | 2254 | #endif |
| 2255 | args.fsbno = be64_to_cpu(*pp); | 2255 | args.fsbno = be64_to_cpu(*pp); |
| 2256 | args.type = XFS_ALLOCTYPE_START_BNO; | 2256 | args.type = XFS_ALLOCTYPE_START_BNO; |
| 2257 | } else | 2257 | } else if (cur->bc_private.b.flist->xbf_low) |
| 2258 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
| 2259 | else | ||
| 2258 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 2260 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
| 2259 | if ((error = xfs_alloc_vextent(&args))) { | 2261 | if ((error = xfs_alloc_vextent(&args))) { |
| 2260 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); | 2262 | XFS_BMBT_TRACE_CURSOR(cur, ERROR); |
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index aeb87ca69fcc..cc593a84c345 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
| @@ -46,38 +46,11 @@ kmem_zone_t *xfs_btree_cur_zone; | |||
| 46 | /* | 46 | /* |
| 47 | * Btree magic numbers. | 47 | * Btree magic numbers. |
| 48 | */ | 48 | */ |
| 49 | const __uint32_t xfs_magics[XFS_BTNUM_MAX] = | 49 | const __uint32_t xfs_magics[XFS_BTNUM_MAX] = { |
| 50 | { | ||
| 51 | XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC | 50 | XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC |
| 52 | }; | 51 | }; |
| 53 | 52 | ||
| 54 | /* | 53 | /* |
| 55 | * Prototypes for internal routines. | ||
| 56 | */ | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Checking routine: return maxrecs for the block. | ||
| 60 | */ | ||
| 61 | STATIC int /* number of records fitting in block */ | ||
| 62 | xfs_btree_maxrecs( | ||
| 63 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
| 64 | xfs_btree_block_t *block);/* generic btree block pointer */ | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Internal routines. | ||
| 68 | */ | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Retrieve the block pointer from the cursor at the given level. | ||
| 72 | * This may be a bmap btree root or from a buffer. | ||
| 73 | */ | ||
| 74 | STATIC xfs_btree_block_t * /* generic btree block pointer */ | ||
| 75 | xfs_btree_get_block( | ||
| 76 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
| 77 | int level, /* level in btree */ | ||
| 78 | struct xfs_buf **bpp); /* buffer containing the block */ | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Checking routine: return maxrecs for the block. | 54 | * Checking routine: return maxrecs for the block. |
| 82 | */ | 55 | */ |
| 83 | STATIC int /* number of records fitting in block */ | 56 | STATIC int /* number of records fitting in block */ |
| @@ -457,35 +430,6 @@ xfs_btree_dup_cursor( | |||
| 457 | } | 430 | } |
| 458 | 431 | ||
| 459 | /* | 432 | /* |
| 460 | * Change the cursor to point to the first record at the given level. | ||
| 461 | * Other levels are unaffected. | ||
| 462 | */ | ||
| 463 | int /* success=1, failure=0 */ | ||
| 464 | xfs_btree_firstrec( | ||
| 465 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
| 466 | int level) /* level to change */ | ||
| 467 | { | ||
| 468 | xfs_btree_block_t *block; /* generic btree block pointer */ | ||
| 469 | xfs_buf_t *bp; /* buffer containing block */ | ||
| 470 | |||
| 471 | /* | ||
| 472 | * Get the block pointer for this level. | ||
| 473 | */ | ||
| 474 | block = xfs_btree_get_block(cur, level, &bp); | ||
| 475 | xfs_btree_check_block(cur, block, level, bp); | ||
| 476 | /* | ||
| 477 | * It's empty, there is no such record. | ||
| 478 | */ | ||
| 479 | if (!block->bb_h.bb_numrecs) | ||
| 480 | return 0; | ||
| 481 | /* | ||
| 482 | * Set the ptr value to 1, that's the first record/key. | ||
| 483 | */ | ||
| 484 | cur->bc_ptrs[level] = 1; | ||
| 485 | return 1; | ||
| 486 | } | ||
| 487 | |||
| 488 | /* | ||
| 489 | * Retrieve the block pointer from the cursor at the given level. | 433 | * Retrieve the block pointer from the cursor at the given level. |
| 490 | * This may be a bmap btree root or from a buffer. | 434 | * This may be a bmap btree root or from a buffer. |
| 491 | */ | 435 | */ |
| @@ -626,6 +570,13 @@ xfs_btree_init_cursor( | |||
| 626 | cur->bc_private.a.agbp = agbp; | 570 | cur->bc_private.a.agbp = agbp; |
| 627 | cur->bc_private.a.agno = agno; | 571 | cur->bc_private.a.agno = agno; |
| 628 | break; | 572 | break; |
| 573 | case XFS_BTNUM_INO: | ||
| 574 | /* | ||
| 575 | * Inode allocation btree fields. | ||
| 576 | */ | ||
| 577 | cur->bc_private.a.agbp = agbp; | ||
| 578 | cur->bc_private.a.agno = agno; | ||
| 579 | break; | ||
| 629 | case XFS_BTNUM_BMAP: | 580 | case XFS_BTNUM_BMAP: |
| 630 | /* | 581 | /* |
| 631 | * Bmap btree fields. | 582 | * Bmap btree fields. |
| @@ -638,13 +589,6 @@ xfs_btree_init_cursor( | |||
| 638 | cur->bc_private.b.flags = 0; | 589 | cur->bc_private.b.flags = 0; |
| 639 | cur->bc_private.b.whichfork = whichfork; | 590 | cur->bc_private.b.whichfork = whichfork; |
| 640 | break; | 591 | break; |
| 641 | case XFS_BTNUM_INO: | ||
| 642 | /* | ||
| 643 | * Inode allocation btree fields. | ||
| 644 | */ | ||
| 645 | cur->bc_private.i.agbp = agbp; | ||
| 646 | cur->bc_private.i.agno = agno; | ||
| 647 | break; | ||
| 648 | default: | 592 | default: |
| 649 | ASSERT(0); | 593 | ASSERT(0); |
| 650 | } | 594 | } |
| @@ -671,6 +615,35 @@ xfs_btree_islastblock( | |||
| 671 | } | 615 | } |
| 672 | 616 | ||
| 673 | /* | 617 | /* |
| 618 | * Change the cursor to point to the first record at the given level. | ||
| 619 | * Other levels are unaffected. | ||
| 620 | */ | ||
| 621 | int /* success=1, failure=0 */ | ||
| 622 | xfs_btree_firstrec( | ||
| 623 | xfs_btree_cur_t *cur, /* btree cursor */ | ||
| 624 | int level) /* level to change */ | ||
| 625 | { | ||
| 626 | xfs_btree_block_t *block; /* generic btree block pointer */ | ||
| 627 | xfs_buf_t *bp; /* buffer containing block */ | ||
| 628 | |||
| 629 | /* | ||
| 630 | * Get the block pointer for this level. | ||
| 631 | */ | ||
| 632 | block = xfs_btree_get_block(cur, level, &bp); | ||
| 633 | xfs_btree_check_block(cur, block, level, bp); | ||
| 634 | /* | ||
| 635 | * It's empty, there is no such record. | ||
| 636 | */ | ||
| 637 | if (!block->bb_h.bb_numrecs) | ||
| 638 | return 0; | ||
| 639 | /* | ||
| 640 | * Set the ptr value to 1, that's the first record/key. | ||
| 641 | */ | ||
| 642 | cur->bc_ptrs[level] = 1; | ||
| 643 | return 1; | ||
| 644 | } | ||
| 645 | |||
| 646 | /* | ||
| 674 | * Change the cursor to point to the last record in the current block | 647 | * Change the cursor to point to the last record in the current block |
| 675 | * at the given level. Other levels are unaffected. | 648 | * at the given level. Other levels are unaffected. |
| 676 | */ | 649 | */ |
| @@ -890,12 +863,12 @@ xfs_btree_readahead_core( | |||
| 890 | case XFS_BTNUM_INO: | 863 | case XFS_BTNUM_INO: |
| 891 | i = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); | 864 | i = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); |
| 892 | if ((lr & XFS_BTCUR_LEFTRA) && be32_to_cpu(i->bb_leftsib) != NULLAGBLOCK) { | 865 | if ((lr & XFS_BTCUR_LEFTRA) && be32_to_cpu(i->bb_leftsib) != NULLAGBLOCK) { |
| 893 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, | 866 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, |
| 894 | be32_to_cpu(i->bb_leftsib), 1); | 867 | be32_to_cpu(i->bb_leftsib), 1); |
| 895 | rval++; | 868 | rval++; |
| 896 | } | 869 | } |
| 897 | if ((lr & XFS_BTCUR_RIGHTRA) && be32_to_cpu(i->bb_rightsib) != NULLAGBLOCK) { | 870 | if ((lr & XFS_BTCUR_RIGHTRA) && be32_to_cpu(i->bb_rightsib) != NULLAGBLOCK) { |
| 898 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, | 871 | xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, |
| 899 | be32_to_cpu(i->bb_rightsib), 1); | 872 | be32_to_cpu(i->bb_rightsib), 1); |
| 900 | rval++; | 873 | rval++; |
| 901 | } | 874 | } |
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 7440b78f9cec..1f528a2a3754 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
| @@ -158,8 +158,8 @@ typedef struct xfs_btree_cur | |||
| 158 | __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ | 158 | __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ |
| 159 | xfs_btnum_t bc_btnum; /* identifies which btree type */ | 159 | xfs_btnum_t bc_btnum; /* identifies which btree type */ |
| 160 | union { | 160 | union { |
| 161 | struct { /* needed for BNO, CNT */ | 161 | struct { /* needed for BNO, CNT, INO */ |
| 162 | struct xfs_buf *agbp; /* agf buffer pointer */ | 162 | struct xfs_buf *agbp; /* agf/agi buffer pointer */ |
| 163 | xfs_agnumber_t agno; /* ag number */ | 163 | xfs_agnumber_t agno; /* ag number */ |
| 164 | } a; | 164 | } a; |
| 165 | struct { /* needed for BMAP */ | 165 | struct { /* needed for BMAP */ |
| @@ -172,10 +172,6 @@ typedef struct xfs_btree_cur | |||
| 172 | char flags; /* flags */ | 172 | char flags; /* flags */ |
| 173 | #define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ | 173 | #define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ |
| 174 | } b; | 174 | } b; |
| 175 | struct { /* needed for INO */ | ||
| 176 | struct xfs_buf *agbp; /* agi buffer pointer */ | ||
| 177 | xfs_agnumber_t agno; /* ag number */ | ||
| 178 | } i; | ||
| 179 | } bc_private; /* per-btree type data */ | 175 | } bc_private; /* per-btree type data */ |
| 180 | } xfs_btree_cur_t; | 176 | } xfs_btree_cur_t; |
| 181 | 177 | ||
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 53a71c62025d..002fc2617c8e 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
| @@ -732,12 +732,13 @@ xfs_buf_item_init( | |||
| 732 | bip->bli_item.li_ops = &xfs_buf_item_ops; | 732 | bip->bli_item.li_ops = &xfs_buf_item_ops; |
| 733 | bip->bli_item.li_mountp = mp; | 733 | bip->bli_item.li_mountp = mp; |
| 734 | bip->bli_buf = bp; | 734 | bip->bli_buf = bp; |
| 735 | xfs_buf_hold(bp); | ||
| 735 | bip->bli_format.blf_type = XFS_LI_BUF; | 736 | bip->bli_format.blf_type = XFS_LI_BUF; |
| 736 | bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); | 737 | bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); |
| 737 | bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp)); | 738 | bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp)); |
| 738 | bip->bli_format.blf_map_size = map_size; | 739 | bip->bli_format.blf_map_size = map_size; |
| 739 | #ifdef XFS_BLI_TRACE | 740 | #ifdef XFS_BLI_TRACE |
| 740 | bip->bli_trace = ktrace_alloc(XFS_BLI_TRACE_SIZE, KM_SLEEP); | 741 | bip->bli_trace = ktrace_alloc(XFS_BLI_TRACE_SIZE, KM_NOFS); |
| 741 | #endif | 742 | #endif |
| 742 | 743 | ||
| 743 | #ifdef XFS_TRANS_DEBUG | 744 | #ifdef XFS_TRANS_DEBUG |
| @@ -867,6 +868,21 @@ xfs_buf_item_dirty( | |||
| 867 | return (bip->bli_flags & XFS_BLI_DIRTY); | 868 | return (bip->bli_flags & XFS_BLI_DIRTY); |
| 868 | } | 869 | } |
| 869 | 870 | ||
| 871 | STATIC void | ||
| 872 | xfs_buf_item_free( | ||
| 873 | xfs_buf_log_item_t *bip) | ||
| 874 | { | ||
| 875 | #ifdef XFS_TRANS_DEBUG | ||
| 876 | kmem_free(bip->bli_orig); | ||
| 877 | kmem_free(bip->bli_logged); | ||
| 878 | #endif /* XFS_TRANS_DEBUG */ | ||
| 879 | |||
| 880 | #ifdef XFS_BLI_TRACE | ||
| 881 | ktrace_free(bip->bli_trace); | ||
| 882 | #endif | ||
| 883 | kmem_zone_free(xfs_buf_item_zone, bip); | ||
| 884 | } | ||
| 885 | |||
| 870 | /* | 886 | /* |
| 871 | * This is called when the buf log item is no longer needed. It should | 887 | * This is called when the buf log item is no longer needed. It should |
| 872 | * free the buf log item associated with the given buffer and clear | 888 | * free the buf log item associated with the given buffer and clear |
| @@ -887,18 +903,8 @@ xfs_buf_item_relse( | |||
| 887 | (XFS_BUF_IODONE_FUNC(bp) != NULL)) { | 903 | (XFS_BUF_IODONE_FUNC(bp) != NULL)) { |
| 888 | XFS_BUF_CLR_IODONE_FUNC(bp); | 904 | XFS_BUF_CLR_IODONE_FUNC(bp); |
| 889 | } | 905 | } |
| 890 | 906 | xfs_buf_rele(bp); | |
| 891 | #ifdef XFS_TRANS_DEBUG | 907 | xfs_buf_item_free(bip); |
| 892 | kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); | ||
| 893 | bip->bli_orig = NULL; | ||
| 894 | kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); | ||
| 895 | bip->bli_logged = NULL; | ||
| 896 | #endif /* XFS_TRANS_DEBUG */ | ||
| 897 | |||
| 898 | #ifdef XFS_BLI_TRACE | ||
| 899 | ktrace_free(bip->bli_trace); | ||
| 900 | #endif | ||
| 901 | kmem_zone_free(xfs_buf_item_zone, bip); | ||
| 902 | } | 908 | } |
| 903 | 909 | ||
| 904 | 910 | ||
| @@ -1056,7 +1062,7 @@ xfs_buf_iodone_callbacks( | |||
| 1056 | anyway. */ | 1062 | anyway. */ |
| 1057 | XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse); | 1063 | XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse); |
| 1058 | XFS_BUF_DONE(bp); | 1064 | XFS_BUF_DONE(bp); |
| 1059 | XFS_BUF_V_IODONESEMA(bp); | 1065 | XFS_BUF_FINISH_IOWAIT(bp); |
| 1060 | } | 1066 | } |
| 1061 | return; | 1067 | return; |
| 1062 | } | 1068 | } |
| @@ -1120,6 +1126,7 @@ xfs_buf_iodone( | |||
| 1120 | 1126 | ||
| 1121 | ASSERT(bip->bli_buf == bp); | 1127 | ASSERT(bip->bli_buf == bp); |
| 1122 | 1128 | ||
| 1129 | xfs_buf_rele(bp); | ||
| 1123 | mp = bip->bli_item.li_mountp; | 1130 | mp = bip->bli_item.li_mountp; |
| 1124 | 1131 | ||
| 1125 | /* | 1132 | /* |
| @@ -1136,18 +1143,7 @@ xfs_buf_iodone( | |||
| 1136 | * xfs_trans_delete_ail() drops the AIL lock. | 1143 | * xfs_trans_delete_ail() drops the AIL lock. |
| 1137 | */ | 1144 | */ |
| 1138 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); | 1145 | xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip); |
| 1139 | 1146 | xfs_buf_item_free(bip); | |
| 1140 | #ifdef XFS_TRANS_DEBUG | ||
| 1141 | kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); | ||
| 1142 | bip->bli_orig = NULL; | ||
| 1143 | kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); | ||
| 1144 | bip->bli_logged = NULL; | ||
| 1145 | #endif /* XFS_TRANS_DEBUG */ | ||
| 1146 | |||
| 1147 | #ifdef XFS_BLI_TRACE | ||
| 1148 | ktrace_free(bip->bli_trace); | ||
| 1149 | #endif | ||
| 1150 | kmem_zone_free(xfs_buf_item_zone, bip); | ||
| 1151 | } | 1147 | } |
| 1152 | 1148 | ||
| 1153 | #if defined(XFS_BLI_TRACE) | 1149 | #if defined(XFS_BLI_TRACE) |
diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h index d5d1e60ee224..d2ce5dd70d87 100644 --- a/fs/xfs/xfs_clnt.h +++ b/fs/xfs/xfs_clnt.h | |||
| @@ -78,6 +78,7 @@ struct xfs_mount_args { | |||
| 78 | #define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */ | 78 | #define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */ |
| 79 | #define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */ | 79 | #define XFSMNT_OSYNCISOSYNC 0x00004000 /* o_sync is REALLY o_sync */ |
| 80 | /* (osyncisdsync is default) */ | 80 | /* (osyncisdsync is default) */ |
| 81 | #define XFSMNT_NOATTR2 0x00008000 /* turn off ATTR2 EA format */ | ||
| 81 | #define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32 | 82 | #define XFSMNT_32BITINODES 0x00200000 /* restrict inodes to 32 |
| 82 | * bits of address space */ | 83 | * bits of address space */ |
| 83 | #define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */ | 84 | #define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */ |
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 021a8f7e563f..9e561a9cefca 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c | |||
| @@ -1431,7 +1431,7 @@ xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, | |||
| 1431 | } | 1431 | } |
| 1432 | if (level < 0) { | 1432 | if (level < 0) { |
| 1433 | *result = XFS_ERROR(ENOENT); /* we're out of our tree */ | 1433 | *result = XFS_ERROR(ENOENT); /* we're out of our tree */ |
| 1434 | ASSERT(args->oknoent); | 1434 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); |
| 1435 | return(0); | 1435 | return(0); |
| 1436 | } | 1436 | } |
| 1437 | 1437 | ||
| @@ -1530,6 +1530,28 @@ xfs_da_hashname(const uchar_t *name, int namelen) | |||
| 1530 | } | 1530 | } |
| 1531 | } | 1531 | } |
| 1532 | 1532 | ||
| 1533 | enum xfs_dacmp | ||
| 1534 | xfs_da_compname( | ||
| 1535 | struct xfs_da_args *args, | ||
| 1536 | const char *name, | ||
| 1537 | int len) | ||
| 1538 | { | ||
| 1539 | return (args->namelen == len && memcmp(args->name, name, len) == 0) ? | ||
| 1540 | XFS_CMP_EXACT : XFS_CMP_DIFFERENT; | ||
| 1541 | } | ||
| 1542 | |||
| 1543 | static xfs_dahash_t | ||
| 1544 | xfs_default_hashname( | ||
| 1545 | struct xfs_name *name) | ||
| 1546 | { | ||
| 1547 | return xfs_da_hashname(name->name, name->len); | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | const struct xfs_nameops xfs_default_nameops = { | ||
| 1551 | .hashname = xfs_default_hashname, | ||
| 1552 | .compname = xfs_da_compname | ||
| 1553 | }; | ||
| 1554 | |||
| 1533 | /* | 1555 | /* |
| 1534 | * Add a block to the btree ahead of the file. | 1556 | * Add a block to the btree ahead of the file. |
| 1535 | * Return the new block number to the caller. | 1557 | * Return the new block number to the caller. |
| @@ -1598,7 +1620,7 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1598 | args->firstblock, args->total, | 1620 | args->firstblock, args->total, |
| 1599 | &mapp[mapi], &nmap, args->flist, | 1621 | &mapp[mapi], &nmap, args->flist, |
| 1600 | NULL))) { | 1622 | NULL))) { |
| 1601 | kmem_free(mapp, sizeof(*mapp) * count); | 1623 | kmem_free(mapp); |
| 1602 | return error; | 1624 | return error; |
| 1603 | } | 1625 | } |
| 1604 | if (nmap < 1) | 1626 | if (nmap < 1) |
| @@ -1620,11 +1642,11 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
| 1620 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != | 1642 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != |
| 1621 | bno + count) { | 1643 | bno + count) { |
| 1622 | if (mapp != &map) | 1644 | if (mapp != &map) |
| 1623 | kmem_free(mapp, sizeof(*mapp) * count); | 1645 | kmem_free(mapp); |
| 1624 | return XFS_ERROR(ENOSPC); | 1646 | return XFS_ERROR(ENOSPC); |
| 1625 | } | 1647 | } |
| 1626 | if (mapp != &map) | 1648 | if (mapp != &map) |
| 1627 | kmem_free(mapp, sizeof(*mapp) * count); | 1649 | kmem_free(mapp); |
| 1628 | *new_blkno = (xfs_dablk_t)bno; | 1650 | *new_blkno = (xfs_dablk_t)bno; |
| 1629 | return 0; | 1651 | return 0; |
| 1630 | } | 1652 | } |
| @@ -2090,10 +2112,10 @@ xfs_da_do_buf( | |||
| 2090 | } | 2112 | } |
| 2091 | } | 2113 | } |
| 2092 | if (bplist) { | 2114 | if (bplist) { |
| 2093 | kmem_free(bplist, sizeof(*bplist) * nmap); | 2115 | kmem_free(bplist); |
| 2094 | } | 2116 | } |
| 2095 | if (mapp != &map) { | 2117 | if (mapp != &map) { |
| 2096 | kmem_free(mapp, sizeof(*mapp) * nfsb); | 2118 | kmem_free(mapp); |
| 2097 | } | 2119 | } |
| 2098 | if (bpp) | 2120 | if (bpp) |
| 2099 | *bpp = rbp; | 2121 | *bpp = rbp; |
| @@ -2102,11 +2124,11 @@ exit1: | |||
| 2102 | if (bplist) { | 2124 | if (bplist) { |
| 2103 | for (i = 0; i < nbplist; i++) | 2125 | for (i = 0; i < nbplist; i++) |
| 2104 | xfs_trans_brelse(trans, bplist[i]); | 2126 | xfs_trans_brelse(trans, bplist[i]); |
| 2105 | kmem_free(bplist, sizeof(*bplist) * nmap); | 2127 | kmem_free(bplist); |
| 2106 | } | 2128 | } |
| 2107 | exit0: | 2129 | exit0: |
| 2108 | if (mapp != &map) | 2130 | if (mapp != &map) |
| 2109 | kmem_free(mapp, sizeof(*mapp) * nfsb); | 2131 | kmem_free(mapp); |
| 2110 | if (bpp) | 2132 | if (bpp) |
| 2111 | *bpp = NULL; | 2133 | *bpp = NULL; |
| 2112 | return error; | 2134 | return error; |
| @@ -2218,7 +2240,7 @@ xfs_da_state_free(xfs_da_state_t *state) | |||
| 2218 | 2240 | ||
| 2219 | #ifdef XFS_DABUF_DEBUG | 2241 | #ifdef XFS_DABUF_DEBUG |
| 2220 | xfs_dabuf_t *xfs_dabuf_global_list; | 2242 | xfs_dabuf_t *xfs_dabuf_global_list; |
| 2221 | spinlock_t xfs_dabuf_global_lock; | 2243 | static DEFINE_SPINLOCK(xfs_dabuf_global_lock); |
| 2222 | #endif | 2244 | #endif |
| 2223 | 2245 | ||
| 2224 | /* | 2246 | /* |
| @@ -2315,7 +2337,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf) | |||
| 2315 | if (dabuf->dirty) | 2337 | if (dabuf->dirty) |
| 2316 | xfs_da_buf_clean(dabuf); | 2338 | xfs_da_buf_clean(dabuf); |
| 2317 | if (dabuf->nbuf > 1) | 2339 | if (dabuf->nbuf > 1) |
| 2318 | kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); | 2340 | kmem_free(dabuf->data); |
| 2319 | #ifdef XFS_DABUF_DEBUG | 2341 | #ifdef XFS_DABUF_DEBUG |
| 2320 | { | 2342 | { |
| 2321 | spin_lock(&xfs_dabuf_global_lock); | 2343 | spin_lock(&xfs_dabuf_global_lock); |
| @@ -2332,7 +2354,7 @@ xfs_da_buf_done(xfs_dabuf_t *dabuf) | |||
| 2332 | if (dabuf->nbuf == 1) | 2354 | if (dabuf->nbuf == 1) |
| 2333 | kmem_zone_free(xfs_dabuf_zone, dabuf); | 2355 | kmem_zone_free(xfs_dabuf_zone, dabuf); |
| 2334 | else | 2356 | else |
| 2335 | kmem_free(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); | 2357 | kmem_free(dabuf); |
| 2336 | } | 2358 | } |
| 2337 | 2359 | ||
| 2338 | /* | 2360 | /* |
| @@ -2403,7 +2425,7 @@ xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf) | |||
| 2403 | for (i = 0; i < nbuf; i++) | 2425 | for (i = 0; i < nbuf; i++) |
| 2404 | xfs_trans_brelse(tp, bplist[i]); | 2426 | xfs_trans_brelse(tp, bplist[i]); |
| 2405 | if (bplist != &bp) | 2427 | if (bplist != &bp) |
| 2406 | kmem_free(bplist, nbuf * sizeof(*bplist)); | 2428 | kmem_free(bplist); |
| 2407 | } | 2429 | } |
| 2408 | 2430 | ||
| 2409 | /* | 2431 | /* |
| @@ -2429,7 +2451,7 @@ xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf) | |||
| 2429 | for (i = 0; i < nbuf; i++) | 2451 | for (i = 0; i < nbuf; i++) |
| 2430 | xfs_trans_binval(tp, bplist[i]); | 2452 | xfs_trans_binval(tp, bplist[i]); |
| 2431 | if (bplist != &bp) | 2453 | if (bplist != &bp) |
| 2432 | kmem_free(bplist, nbuf * sizeof(*bplist)); | 2454 | kmem_free(bplist); |
| 2433 | } | 2455 | } |
| 2434 | 2456 | ||
| 2435 | /* | 2457 | /* |
diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 7facf86f74f9..8be0b00ede9a 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h | |||
| @@ -99,6 +99,15 @@ typedef struct xfs_da_node_entry xfs_da_node_entry_t; | |||
| 99 | *========================================================================*/ | 99 | *========================================================================*/ |
| 100 | 100 | ||
| 101 | /* | 101 | /* |
| 102 | * Search comparison results | ||
| 103 | */ | ||
| 104 | enum xfs_dacmp { | ||
| 105 | XFS_CMP_DIFFERENT, /* names are completely different */ | ||
| 106 | XFS_CMP_EXACT, /* names are exactly the same */ | ||
| 107 | XFS_CMP_CASE /* names are same but differ in case */ | ||
| 108 | }; | ||
| 109 | |||
| 110 | /* | ||
| 102 | * Structure to ease passing around component names. | 111 | * Structure to ease passing around component names. |
| 103 | */ | 112 | */ |
| 104 | typedef struct xfs_da_args { | 113 | typedef struct xfs_da_args { |
| @@ -123,13 +132,20 @@ typedef struct xfs_da_args { | |||
| 123 | int index2; /* index of 2nd attr in blk */ | 132 | int index2; /* index of 2nd attr in blk */ |
| 124 | xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ | 133 | xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ |
| 125 | int rmtblkcnt2; /* remote attr value block count */ | 134 | int rmtblkcnt2; /* remote attr value block count */ |
| 126 | unsigned char justcheck; /* T/F: check for ok with no space */ | 135 | int op_flags; /* operation flags */ |
| 127 | unsigned char rename; /* T/F: this is an atomic rename op */ | 136 | enum xfs_dacmp cmpresult; /* name compare result for lookups */ |
| 128 | unsigned char addname; /* T/F: this is an add operation */ | ||
| 129 | unsigned char oknoent; /* T/F: ok to return ENOENT, else die */ | ||
| 130 | } xfs_da_args_t; | 137 | } xfs_da_args_t; |
| 131 | 138 | ||
| 132 | /* | 139 | /* |
| 140 | * Operation flags: | ||
| 141 | */ | ||
| 142 | #define XFS_DA_OP_JUSTCHECK 0x0001 /* check for ok with no space */ | ||
| 143 | #define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */ | ||
| 144 | #define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */ | ||
| 145 | #define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ | ||
| 146 | #define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */ | ||
| 147 | |||
| 148 | /* | ||
| 133 | * Structure to describe buffer(s) for a block. | 149 | * Structure to describe buffer(s) for a block. |
| 134 | * This is needed in the directory version 2 format case, when | 150 | * This is needed in the directory version 2 format case, when |
| 135 | * multiple non-contiguous fsblocks might be needed to cover one | 151 | * multiple non-contiguous fsblocks might be needed to cover one |
| @@ -201,6 +217,14 @@ typedef struct xfs_da_state { | |||
| 201 | (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ | 217 | (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ |
| 202 | (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) | 218 | (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) |
| 203 | 219 | ||
| 220 | /* | ||
| 221 | * Name ops for directory and/or attr name operations | ||
| 222 | */ | ||
| 223 | struct xfs_nameops { | ||
| 224 | xfs_dahash_t (*hashname)(struct xfs_name *); | ||
| 225 | enum xfs_dacmp (*compname)(struct xfs_da_args *, const char *, int); | ||
| 226 | }; | ||
| 227 | |||
| 204 | 228 | ||
| 205 | #ifdef __KERNEL__ | 229 | #ifdef __KERNEL__ |
| 206 | /*======================================================================== | 230 | /*======================================================================== |
| @@ -249,6 +273,10 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, | |||
| 249 | xfs_dabuf_t *dead_buf); | 273 | xfs_dabuf_t *dead_buf); |
| 250 | 274 | ||
| 251 | uint xfs_da_hashname(const uchar_t *name_string, int name_length); | 275 | uint xfs_da_hashname(const uchar_t *name_string, int name_length); |
| 276 | enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, | ||
| 277 | const char *name, int len); | ||
| 278 | |||
| 279 | |||
| 252 | xfs_da_state_t *xfs_da_state_alloc(void); | 280 | xfs_da_state_t *xfs_da_state_alloc(void); |
| 253 | void xfs_da_state_free(xfs_da_state_t *state); | 281 | void xfs_da_state_free(xfs_da_state_t *state); |
| 254 | 282 | ||
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 5f3647cb9885..75b0cd4da0ea 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c | |||
| @@ -116,7 +116,7 @@ xfs_swapext( | |||
| 116 | out_put_file: | 116 | out_put_file: |
| 117 | fput(file); | 117 | fput(file); |
| 118 | out_free_sxp: | 118 | out_free_sxp: |
| 119 | kmem_free(sxp, sizeof(xfs_swapext_t)); | 119 | kmem_free(sxp); |
| 120 | out: | 120 | out: |
| 121 | return error; | 121 | return error; |
| 122 | } | 122 | } |
| @@ -128,10 +128,8 @@ xfs_swap_extents( | |||
| 128 | xfs_swapext_t *sxp) | 128 | xfs_swapext_t *sxp) |
| 129 | { | 129 | { |
| 130 | xfs_mount_t *mp; | 130 | xfs_mount_t *mp; |
| 131 | xfs_inode_t *ips[2]; | ||
| 132 | xfs_trans_t *tp; | 131 | xfs_trans_t *tp; |
| 133 | xfs_bstat_t *sbp = &sxp->sx_stat; | 132 | xfs_bstat_t *sbp = &sxp->sx_stat; |
| 134 | bhv_vnode_t *vp, *tvp; | ||
| 135 | xfs_ifork_t *tempifp, *ifp, *tifp; | 133 | xfs_ifork_t *tempifp, *ifp, *tifp; |
| 136 | int ilf_fields, tilf_fields; | 134 | int ilf_fields, tilf_fields; |
| 137 | static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; | 135 | static uint lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; |
| @@ -150,19 +148,15 @@ xfs_swap_extents( | |||
| 150 | } | 148 | } |
| 151 | 149 | ||
| 152 | sbp = &sxp->sx_stat; | 150 | sbp = &sxp->sx_stat; |
| 153 | vp = XFS_ITOV(ip); | ||
| 154 | tvp = XFS_ITOV(tip); | ||
| 155 | |||
| 156 | /* Lock in i_ino order */ | ||
| 157 | if (ip->i_ino < tip->i_ino) { | ||
| 158 | ips[0] = ip; | ||
| 159 | ips[1] = tip; | ||
| 160 | } else { | ||
| 161 | ips[0] = tip; | ||
| 162 | ips[1] = ip; | ||
| 163 | } | ||
| 164 | 151 | ||
| 165 | xfs_lock_inodes(ips, 2, lock_flags); | 152 | /* |
| 153 | * we have to do two separate lock calls here to keep lockdep | ||
| 154 | * happy. If we try to get all the locks in one call, lock will | ||
| 155 | * report false positives when we drop the ILOCK and regain them | ||
| 156 | * below. | ||
| 157 | */ | ||
| 158 | xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL); | ||
| 159 | xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); | ||
| 166 | locked = 1; | 160 | locked = 1; |
| 167 | 161 | ||
| 168 | /* Verify that both files have the same format */ | 162 | /* Verify that both files have the same format */ |
| @@ -184,7 +178,7 @@ xfs_swap_extents( | |||
| 184 | goto error0; | 178 | goto error0; |
| 185 | } | 179 | } |
| 186 | 180 | ||
| 187 | if (VN_CACHED(tvp) != 0) { | 181 | if (VN_CACHED(VFS_I(tip)) != 0) { |
| 188 | xfs_inval_cached_trace(tip, 0, -1, 0, -1); | 182 | xfs_inval_cached_trace(tip, 0, -1, 0, -1); |
| 189 | error = xfs_flushinval_pages(tip, 0, -1, | 183 | error = xfs_flushinval_pages(tip, 0, -1, |
| 190 | FI_REMAPF_LOCKED); | 184 | FI_REMAPF_LOCKED); |
| @@ -193,7 +187,7 @@ xfs_swap_extents( | |||
| 193 | } | 187 | } |
| 194 | 188 | ||
| 195 | /* Verify O_DIRECT for ftmp */ | 189 | /* Verify O_DIRECT for ftmp */ |
| 196 | if (VN_CACHED(tvp) != 0) { | 190 | if (VN_CACHED(VFS_I(tip)) != 0) { |
| 197 | error = XFS_ERROR(EINVAL); | 191 | error = XFS_ERROR(EINVAL); |
| 198 | goto error0; | 192 | goto error0; |
| 199 | } | 193 | } |
| @@ -237,7 +231,7 @@ xfs_swap_extents( | |||
| 237 | * vop_read (or write in the case of autogrow) they block on the iolock | 231 | * vop_read (or write in the case of autogrow) they block on the iolock |
| 238 | * until we have switched the extents. | 232 | * until we have switched the extents. |
| 239 | */ | 233 | */ |
| 240 | if (VN_MAPPED(vp)) { | 234 | if (VN_MAPPED(VFS_I(ip))) { |
| 241 | error = XFS_ERROR(EBUSY); | 235 | error = XFS_ERROR(EBUSY); |
| 242 | goto error0; | 236 | goto error0; |
| 243 | } | 237 | } |
| @@ -265,7 +259,7 @@ xfs_swap_extents( | |||
| 265 | locked = 0; | 259 | locked = 0; |
| 266 | goto error0; | 260 | goto error0; |
| 267 | } | 261 | } |
| 268 | xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL); | 262 | xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); |
| 269 | 263 | ||
| 270 | /* | 264 | /* |
| 271 | * Count the number of extended attribute blocks | 265 | * Count the number of extended attribute blocks |
| @@ -350,15 +344,11 @@ xfs_swap_extents( | |||
| 350 | break; | 344 | break; |
| 351 | } | 345 | } |
| 352 | 346 | ||
| 353 | /* | ||
| 354 | * Increment vnode ref counts since xfs_trans_commit & | ||
| 355 | * xfs_trans_cancel will both unlock the inodes and | ||
| 356 | * decrement the associated ref counts. | ||
| 357 | */ | ||
| 358 | VN_HOLD(vp); | ||
| 359 | VN_HOLD(tvp); | ||
| 360 | 347 | ||
| 348 | IHOLD(ip); | ||
| 361 | xfs_trans_ijoin(tp, ip, lock_flags); | 349 | xfs_trans_ijoin(tp, ip, lock_flags); |
| 350 | |||
| 351 | IHOLD(tip); | ||
| 362 | xfs_trans_ijoin(tp, tip, lock_flags); | 352 | xfs_trans_ijoin(tp, tip, lock_flags); |
| 363 | 353 | ||
| 364 | xfs_trans_log_inode(tp, ip, ilf_fields); | 354 | xfs_trans_log_inode(tp, ip, ilf_fields); |
| @@ -381,6 +371,6 @@ xfs_swap_extents( | |||
| 381 | xfs_iunlock(tip, lock_flags); | 371 | xfs_iunlock(tip, lock_flags); |
| 382 | } | 372 | } |
| 383 | if (tempifp != NULL) | 373 | if (tempifp != NULL) |
| 384 | kmem_free(tempifp, sizeof(xfs_ifork_t)); | 374 | kmem_free(tempifp); |
| 385 | return error; | 375 | return error; |
| 386 | } | 376 | } |
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 7cb26529766b..80e0dc51361c 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c | |||
| @@ -46,6 +46,54 @@ | |||
| 46 | 46 | ||
| 47 | struct xfs_name xfs_name_dotdot = {"..", 2}; | 47 | struct xfs_name xfs_name_dotdot = {"..", 2}; |
| 48 | 48 | ||
| 49 | extern const struct xfs_nameops xfs_default_nameops; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * ASCII case-insensitive (ie. A-Z) support for directories that was | ||
| 53 | * used in IRIX. | ||
| 54 | */ | ||
| 55 | STATIC xfs_dahash_t | ||
| 56 | xfs_ascii_ci_hashname( | ||
| 57 | struct xfs_name *name) | ||
| 58 | { | ||
| 59 | xfs_dahash_t hash; | ||
| 60 | int i; | ||
| 61 | |||
| 62 | for (i = 0, hash = 0; i < name->len; i++) | ||
| 63 | hash = tolower(name->name[i]) ^ rol32(hash, 7); | ||
| 64 | |||
| 65 | return hash; | ||
| 66 | } | ||
| 67 | |||
| 68 | STATIC enum xfs_dacmp | ||
| 69 | xfs_ascii_ci_compname( | ||
| 70 | struct xfs_da_args *args, | ||
| 71 | const char *name, | ||
| 72 | int len) | ||
| 73 | { | ||
| 74 | enum xfs_dacmp result; | ||
| 75 | int i; | ||
| 76 | |||
| 77 | if (args->namelen != len) | ||
| 78 | return XFS_CMP_DIFFERENT; | ||
| 79 | |||
| 80 | result = XFS_CMP_EXACT; | ||
| 81 | for (i = 0; i < len; i++) { | ||
| 82 | if (args->name[i] == name[i]) | ||
| 83 | continue; | ||
| 84 | if (tolower(args->name[i]) != tolower(name[i])) | ||
| 85 | return XFS_CMP_DIFFERENT; | ||
| 86 | result = XFS_CMP_CASE; | ||
| 87 | } | ||
| 88 | |||
| 89 | return result; | ||
| 90 | } | ||
| 91 | |||
| 92 | static struct xfs_nameops xfs_ascii_ci_nameops = { | ||
| 93 | .hashname = xfs_ascii_ci_hashname, | ||
| 94 | .compname = xfs_ascii_ci_compname, | ||
| 95 | }; | ||
| 96 | |||
| 49 | void | 97 | void |
| 50 | xfs_dir_mount( | 98 | xfs_dir_mount( |
| 51 | xfs_mount_t *mp) | 99 | xfs_mount_t *mp) |
| @@ -65,6 +113,10 @@ xfs_dir_mount( | |||
| 65 | (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / | 113 | (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / |
| 66 | (uint)sizeof(xfs_da_node_entry_t); | 114 | (uint)sizeof(xfs_da_node_entry_t); |
| 67 | mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; | 115 | mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; |
| 116 | if (xfs_sb_version_hasasciici(&mp->m_sb)) | ||
| 117 | mp->m_dirnameops = &xfs_ascii_ci_nameops; | ||
| 118 | else | ||
| 119 | mp->m_dirnameops = &xfs_default_nameops; | ||
| 68 | } | 120 | } |
| 69 | 121 | ||
| 70 | /* | 122 | /* |
| @@ -162,9 +214,10 @@ xfs_dir_createname( | |||
| 162 | return rval; | 214 | return rval; |
| 163 | XFS_STATS_INC(xs_dir_create); | 215 | XFS_STATS_INC(xs_dir_create); |
| 164 | 216 | ||
| 217 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 165 | args.name = name->name; | 218 | args.name = name->name; |
| 166 | args.namelen = name->len; | 219 | args.namelen = name->len; |
| 167 | args.hashval = xfs_da_hashname(name->name, name->len); | 220 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
| 168 | args.inumber = inum; | 221 | args.inumber = inum; |
| 169 | args.dp = dp; | 222 | args.dp = dp; |
| 170 | args.firstblock = first; | 223 | args.firstblock = first; |
| @@ -172,8 +225,7 @@ xfs_dir_createname( | |||
| 172 | args.total = total; | 225 | args.total = total; |
| 173 | args.whichfork = XFS_DATA_FORK; | 226 | args.whichfork = XFS_DATA_FORK; |
| 174 | args.trans = tp; | 227 | args.trans = tp; |
| 175 | args.justcheck = 0; | 228 | args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; |
| 176 | args.addname = args.oknoent = 1; | ||
| 177 | 229 | ||
| 178 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 230 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 179 | rval = xfs_dir2_sf_addname(&args); | 231 | rval = xfs_dir2_sf_addname(&args); |
| @@ -191,14 +243,43 @@ xfs_dir_createname( | |||
| 191 | } | 243 | } |
| 192 | 244 | ||
| 193 | /* | 245 | /* |
| 246 | * If doing a CI lookup and case-insensitive match, dup actual name into | ||
| 247 | * args.value. Return EEXIST for success (ie. name found) or an error. | ||
| 248 | */ | ||
| 249 | int | ||
| 250 | xfs_dir_cilookup_result( | ||
| 251 | struct xfs_da_args *args, | ||
| 252 | const char *name, | ||
| 253 | int len) | ||
| 254 | { | ||
| 255 | if (args->cmpresult == XFS_CMP_DIFFERENT) | ||
| 256 | return ENOENT; | ||
| 257 | if (args->cmpresult != XFS_CMP_CASE || | ||
| 258 | !(args->op_flags & XFS_DA_OP_CILOOKUP)) | ||
| 259 | return EEXIST; | ||
| 260 | |||
| 261 | args->value = kmem_alloc(len, KM_MAYFAIL); | ||
| 262 | if (!args->value) | ||
| 263 | return ENOMEM; | ||
| 264 | |||
| 265 | memcpy(args->value, name, len); | ||
| 266 | args->valuelen = len; | ||
| 267 | return EEXIST; | ||
| 268 | } | ||
| 269 | |||
| 270 | /* | ||
| 194 | * Lookup a name in a directory, give back the inode number. | 271 | * Lookup a name in a directory, give back the inode number. |
| 272 | * If ci_name is not NULL, returns the actual name in ci_name if it differs | ||
| 273 | * to name, or ci_name->name is set to NULL for an exact match. | ||
| 195 | */ | 274 | */ |
| 275 | |||
| 196 | int | 276 | int |
| 197 | xfs_dir_lookup( | 277 | xfs_dir_lookup( |
| 198 | xfs_trans_t *tp, | 278 | xfs_trans_t *tp, |
| 199 | xfs_inode_t *dp, | 279 | xfs_inode_t *dp, |
| 200 | struct xfs_name *name, | 280 | struct xfs_name *name, |
| 201 | xfs_ino_t *inum) /* out: inode number */ | 281 | xfs_ino_t *inum, /* out: inode number */ |
| 282 | struct xfs_name *ci_name) /* out: actual name if CI match */ | ||
| 202 | { | 283 | { |
| 203 | xfs_da_args_t args; | 284 | xfs_da_args_t args; |
| 204 | int rval; | 285 | int rval; |
| @@ -206,15 +287,17 @@ xfs_dir_lookup( | |||
| 206 | 287 | ||
| 207 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 288 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 208 | XFS_STATS_INC(xs_dir_lookup); | 289 | XFS_STATS_INC(xs_dir_lookup); |
| 209 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 210 | 290 | ||
| 291 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 211 | args.name = name->name; | 292 | args.name = name->name; |
| 212 | args.namelen = name->len; | 293 | args.namelen = name->len; |
| 213 | args.hashval = xfs_da_hashname(name->name, name->len); | 294 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
| 214 | args.dp = dp; | 295 | args.dp = dp; |
| 215 | args.whichfork = XFS_DATA_FORK; | 296 | args.whichfork = XFS_DATA_FORK; |
| 216 | args.trans = tp; | 297 | args.trans = tp; |
| 217 | args.oknoent = 1; | 298 | args.op_flags = XFS_DA_OP_OKNOENT; |
| 299 | if (ci_name) | ||
| 300 | args.op_flags |= XFS_DA_OP_CILOOKUP; | ||
| 218 | 301 | ||
| 219 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 302 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 220 | rval = xfs_dir2_sf_lookup(&args); | 303 | rval = xfs_dir2_sf_lookup(&args); |
| @@ -230,8 +313,13 @@ xfs_dir_lookup( | |||
| 230 | rval = xfs_dir2_node_lookup(&args); | 313 | rval = xfs_dir2_node_lookup(&args); |
| 231 | if (rval == EEXIST) | 314 | if (rval == EEXIST) |
| 232 | rval = 0; | 315 | rval = 0; |
| 233 | if (rval == 0) | 316 | if (!rval) { |
| 234 | *inum = args.inumber; | 317 | *inum = args.inumber; |
| 318 | if (ci_name) { | ||
| 319 | ci_name->name = args.value; | ||
| 320 | ci_name->len = args.valuelen; | ||
| 321 | } | ||
| 322 | } | ||
| 235 | return rval; | 323 | return rval; |
| 236 | } | 324 | } |
| 237 | 325 | ||
| @@ -255,9 +343,10 @@ xfs_dir_removename( | |||
| 255 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 343 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 256 | XFS_STATS_INC(xs_dir_remove); | 344 | XFS_STATS_INC(xs_dir_remove); |
| 257 | 345 | ||
| 346 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 258 | args.name = name->name; | 347 | args.name = name->name; |
| 259 | args.namelen = name->len; | 348 | args.namelen = name->len; |
| 260 | args.hashval = xfs_da_hashname(name->name, name->len); | 349 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
| 261 | args.inumber = ino; | 350 | args.inumber = ino; |
| 262 | args.dp = dp; | 351 | args.dp = dp; |
| 263 | args.firstblock = first; | 352 | args.firstblock = first; |
| @@ -265,7 +354,6 @@ xfs_dir_removename( | |||
| 265 | args.total = total; | 354 | args.total = total; |
| 266 | args.whichfork = XFS_DATA_FORK; | 355 | args.whichfork = XFS_DATA_FORK; |
| 267 | args.trans = tp; | 356 | args.trans = tp; |
| 268 | args.justcheck = args.addname = args.oknoent = 0; | ||
| 269 | 357 | ||
| 270 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 358 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 271 | rval = xfs_dir2_sf_removename(&args); | 359 | rval = xfs_dir2_sf_removename(&args); |
| @@ -338,9 +426,10 @@ xfs_dir_replace( | |||
| 338 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) | 426 | if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) |
| 339 | return rval; | 427 | return rval; |
| 340 | 428 | ||
| 429 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 341 | args.name = name->name; | 430 | args.name = name->name; |
| 342 | args.namelen = name->len; | 431 | args.namelen = name->len; |
| 343 | args.hashval = xfs_da_hashname(name->name, name->len); | 432 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
| 344 | args.inumber = inum; | 433 | args.inumber = inum; |
| 345 | args.dp = dp; | 434 | args.dp = dp; |
| 346 | args.firstblock = first; | 435 | args.firstblock = first; |
| @@ -348,7 +437,6 @@ xfs_dir_replace( | |||
| 348 | args.total = total; | 437 | args.total = total; |
| 349 | args.whichfork = XFS_DATA_FORK; | 438 | args.whichfork = XFS_DATA_FORK; |
| 350 | args.trans = tp; | 439 | args.trans = tp; |
| 351 | args.justcheck = args.addname = args.oknoent = 0; | ||
| 352 | 440 | ||
| 353 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 441 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 354 | rval = xfs_dir2_sf_replace(&args); | 442 | rval = xfs_dir2_sf_replace(&args); |
| @@ -384,15 +472,16 @@ xfs_dir_canenter( | |||
| 384 | return 0; | 472 | return 0; |
| 385 | 473 | ||
| 386 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); | 474 | ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); |
| 387 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 388 | 475 | ||
| 476 | memset(&args, 0, sizeof(xfs_da_args_t)); | ||
| 389 | args.name = name->name; | 477 | args.name = name->name; |
| 390 | args.namelen = name->len; | 478 | args.namelen = name->len; |
| 391 | args.hashval = xfs_da_hashname(name->name, name->len); | 479 | args.hashval = dp->i_mount->m_dirnameops->hashname(name); |
| 392 | args.dp = dp; | 480 | args.dp = dp; |
| 393 | args.whichfork = XFS_DATA_FORK; | 481 | args.whichfork = XFS_DATA_FORK; |
| 394 | args.trans = tp; | 482 | args.trans = tp; |
| 395 | args.justcheck = args.addname = args.oknoent = 1; | 483 | args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME | |
| 484 | XFS_DA_OP_OKNOENT; | ||
| 396 | 485 | ||
| 397 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) | 486 | if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) |
| 398 | rval = xfs_dir2_sf_addname(&args); | 487 | rval = xfs_dir2_sf_addname(&args); |
| @@ -493,7 +582,7 @@ xfs_dir2_grow_inode( | |||
| 493 | args->firstblock, args->total, | 582 | args->firstblock, args->total, |
| 494 | &mapp[mapi], &nmap, args->flist, | 583 | &mapp[mapi], &nmap, args->flist, |
| 495 | NULL))) { | 584 | NULL))) { |
| 496 | kmem_free(mapp, sizeof(*mapp) * count); | 585 | kmem_free(mapp); |
| 497 | return error; | 586 | return error; |
| 498 | } | 587 | } |
| 499 | if (nmap < 1) | 588 | if (nmap < 1) |
| @@ -525,14 +614,14 @@ xfs_dir2_grow_inode( | |||
| 525 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != | 614 | mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != |
| 526 | bno + count) { | 615 | bno + count) { |
| 527 | if (mapp != &map) | 616 | if (mapp != &map) |
| 528 | kmem_free(mapp, sizeof(*mapp) * count); | 617 | kmem_free(mapp); |
| 529 | return XFS_ERROR(ENOSPC); | 618 | return XFS_ERROR(ENOSPC); |
| 530 | } | 619 | } |
| 531 | /* | 620 | /* |
| 532 | * Done with the temporary mapping table. | 621 | * Done with the temporary mapping table. |
| 533 | */ | 622 | */ |
| 534 | if (mapp != &map) | 623 | if (mapp != &map) |
| 535 | kmem_free(mapp, sizeof(*mapp) * count); | 624 | kmem_free(mapp); |
| 536 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); | 625 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); |
| 537 | /* | 626 | /* |
| 538 | * Update file's size if this is the data space and it grew. | 627 | * Update file's size if this is the data space and it grew. |
diff --git a/fs/xfs/xfs_dir2.h b/fs/xfs/xfs_dir2.h index 6392f939029f..1d9ef96f33aa 100644 --- a/fs/xfs/xfs_dir2.h +++ b/fs/xfs/xfs_dir2.h | |||
| @@ -74,7 +74,8 @@ extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp, | |||
| 74 | xfs_fsblock_t *first, | 74 | xfs_fsblock_t *first, |
| 75 | struct xfs_bmap_free *flist, xfs_extlen_t tot); | 75 | struct xfs_bmap_free *flist, xfs_extlen_t tot); |
| 76 | extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, | 76 | extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, |
| 77 | struct xfs_name *name, xfs_ino_t *inum); | 77 | struct xfs_name *name, xfs_ino_t *inum, |
| 78 | struct xfs_name *ci_name); | ||
| 78 | extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, | 79 | extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, |
| 79 | struct xfs_name *name, xfs_ino_t ino, | 80 | struct xfs_name *name, xfs_ino_t ino, |
| 80 | xfs_fsblock_t *first, | 81 | xfs_fsblock_t *first, |
| @@ -99,4 +100,7 @@ extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, | |||
| 99 | extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, | 100 | extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, |
| 100 | struct xfs_dabuf *bp); | 101 | struct xfs_dabuf *bp); |
| 101 | 102 | ||
| 103 | extern int xfs_dir_cilookup_result(struct xfs_da_args *args, const char *name, | ||
| 104 | int len); | ||
| 105 | |||
| 102 | #endif /* __XFS_DIR2_H__ */ | 106 | #endif /* __XFS_DIR2_H__ */ |
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index fb5a556725b3..e2fa0a1d8e96 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c | |||
| @@ -215,7 +215,7 @@ xfs_dir2_block_addname( | |||
| 215 | /* | 215 | /* |
| 216 | * If this isn't a real add, we're done with the buffer. | 216 | * If this isn't a real add, we're done with the buffer. |
| 217 | */ | 217 | */ |
| 218 | if (args->justcheck) | 218 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) |
| 219 | xfs_da_brelse(tp, bp); | 219 | xfs_da_brelse(tp, bp); |
| 220 | /* | 220 | /* |
| 221 | * If we don't have space for the new entry & leaf ... | 221 | * If we don't have space for the new entry & leaf ... |
| @@ -225,7 +225,7 @@ xfs_dir2_block_addname( | |||
| 225 | * Not trying to actually do anything, or don't have | 225 | * Not trying to actually do anything, or don't have |
| 226 | * a space reservation: return no-space. | 226 | * a space reservation: return no-space. |
| 227 | */ | 227 | */ |
| 228 | if (args->justcheck || args->total == 0) | 228 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) |
| 229 | return XFS_ERROR(ENOSPC); | 229 | return XFS_ERROR(ENOSPC); |
| 230 | /* | 230 | /* |
| 231 | * Convert to the next larger format. | 231 | * Convert to the next larger format. |
| @@ -240,7 +240,7 @@ xfs_dir2_block_addname( | |||
| 240 | /* | 240 | /* |
| 241 | * Just checking, and it would work, so say so. | 241 | * Just checking, and it would work, so say so. |
| 242 | */ | 242 | */ |
| 243 | if (args->justcheck) | 243 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) |
| 244 | return 0; | 244 | return 0; |
| 245 | needlog = needscan = 0; | 245 | needlog = needscan = 0; |
| 246 | /* | 246 | /* |
| @@ -610,14 +610,15 @@ xfs_dir2_block_lookup( | |||
| 610 | /* | 610 | /* |
| 611 | * Get the offset from the leaf entry, to point to the data. | 611 | * Get the offset from the leaf entry, to point to the data. |
| 612 | */ | 612 | */ |
| 613 | dep = (xfs_dir2_data_entry_t *) | 613 | dep = (xfs_dir2_data_entry_t *)((char *)block + |
| 614 | ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address))); | 614 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address))); |
| 615 | /* | 615 | /* |
| 616 | * Fill in inode number, release the block. | 616 | * Fill in inode number, CI name if appropriate, release the block. |
| 617 | */ | 617 | */ |
| 618 | args->inumber = be64_to_cpu(dep->inumber); | 618 | args->inumber = be64_to_cpu(dep->inumber); |
| 619 | error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); | ||
| 619 | xfs_da_brelse(args->trans, bp); | 620 | xfs_da_brelse(args->trans, bp); |
| 620 | return XFS_ERROR(EEXIST); | 621 | return XFS_ERROR(error); |
| 621 | } | 622 | } |
| 622 | 623 | ||
| 623 | /* | 624 | /* |
| @@ -643,6 +644,7 @@ xfs_dir2_block_lookup_int( | |||
| 643 | int mid; /* binary search current idx */ | 644 | int mid; /* binary search current idx */ |
| 644 | xfs_mount_t *mp; /* filesystem mount point */ | 645 | xfs_mount_t *mp; /* filesystem mount point */ |
| 645 | xfs_trans_t *tp; /* transaction pointer */ | 646 | xfs_trans_t *tp; /* transaction pointer */ |
| 647 | enum xfs_dacmp cmp; /* comparison result */ | ||
| 646 | 648 | ||
| 647 | dp = args->dp; | 649 | dp = args->dp; |
| 648 | tp = args->trans; | 650 | tp = args->trans; |
| @@ -673,7 +675,7 @@ xfs_dir2_block_lookup_int( | |||
| 673 | else | 675 | else |
| 674 | high = mid - 1; | 676 | high = mid - 1; |
| 675 | if (low > high) { | 677 | if (low > high) { |
| 676 | ASSERT(args->oknoent); | 678 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); |
| 677 | xfs_da_brelse(tp, bp); | 679 | xfs_da_brelse(tp, bp); |
| 678 | return XFS_ERROR(ENOENT); | 680 | return XFS_ERROR(ENOENT); |
| 679 | } | 681 | } |
| @@ -697,20 +699,31 @@ xfs_dir2_block_lookup_int( | |||
| 697 | dep = (xfs_dir2_data_entry_t *) | 699 | dep = (xfs_dir2_data_entry_t *) |
| 698 | ((char *)block + xfs_dir2_dataptr_to_off(mp, addr)); | 700 | ((char *)block + xfs_dir2_dataptr_to_off(mp, addr)); |
| 699 | /* | 701 | /* |
| 700 | * Compare, if it's right give back buffer & entry number. | 702 | * Compare name and if it's an exact match, return the index |
| 703 | * and buffer. If it's the first case-insensitive match, store | ||
| 704 | * the index and buffer and continue looking for an exact match. | ||
| 701 | */ | 705 | */ |
| 702 | if (dep->namelen == args->namelen && | 706 | cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); |
| 703 | dep->name[0] == args->name[0] && | 707 | if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { |
| 704 | memcmp(dep->name, args->name, args->namelen) == 0) { | 708 | args->cmpresult = cmp; |
| 705 | *bpp = bp; | 709 | *bpp = bp; |
| 706 | *entno = mid; | 710 | *entno = mid; |
| 707 | return 0; | 711 | if (cmp == XFS_CMP_EXACT) |
| 712 | return 0; | ||
| 708 | } | 713 | } |
| 709 | } while (++mid < be32_to_cpu(btp->count) && be32_to_cpu(blp[mid].hashval) == hash); | 714 | } while (++mid < be32_to_cpu(btp->count) && |
| 715 | be32_to_cpu(blp[mid].hashval) == hash); | ||
| 716 | |||
| 717 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); | ||
| 718 | /* | ||
| 719 | * Here, we can only be doing a lookup (not a rename or replace). | ||
| 720 | * If a case-insensitive match was found earlier, return success. | ||
| 721 | */ | ||
| 722 | if (args->cmpresult == XFS_CMP_CASE) | ||
| 723 | return 0; | ||
| 710 | /* | 724 | /* |
| 711 | * No match, release the buffer and return ENOENT. | 725 | * No match, release the buffer and return ENOENT. |
| 712 | */ | 726 | */ |
| 713 | ASSERT(args->oknoent); | ||
| 714 | xfs_da_brelse(tp, bp); | 727 | xfs_da_brelse(tp, bp); |
| 715 | return XFS_ERROR(ENOENT); | 728 | return XFS_ERROR(ENOENT); |
| 716 | } | 729 | } |
| @@ -1033,6 +1046,7 @@ xfs_dir2_sf_to_block( | |||
| 1033 | xfs_dir2_sf_t *sfp; /* shortform structure */ | 1046 | xfs_dir2_sf_t *sfp; /* shortform structure */ |
| 1034 | __be16 *tagp; /* end of data entry */ | 1047 | __be16 *tagp; /* end of data entry */ |
| 1035 | xfs_trans_t *tp; /* transaction pointer */ | 1048 | xfs_trans_t *tp; /* transaction pointer */ |
| 1049 | struct xfs_name name; | ||
| 1036 | 1050 | ||
| 1037 | xfs_dir2_trace_args("sf_to_block", args); | 1051 | xfs_dir2_trace_args("sf_to_block", args); |
| 1038 | dp = args->dp; | 1052 | dp = args->dp; |
| @@ -1071,7 +1085,7 @@ xfs_dir2_sf_to_block( | |||
| 1071 | */ | 1085 | */ |
| 1072 | error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); | 1086 | error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); |
| 1073 | if (error) { | 1087 | if (error) { |
| 1074 | kmem_free(buf, buf_len); | 1088 | kmem_free(buf); |
| 1075 | return error; | 1089 | return error; |
| 1076 | } | 1090 | } |
| 1077 | /* | 1091 | /* |
| @@ -1079,7 +1093,7 @@ xfs_dir2_sf_to_block( | |||
| 1079 | */ | 1093 | */ |
| 1080 | error = xfs_dir2_data_init(args, blkno, &bp); | 1094 | error = xfs_dir2_data_init(args, blkno, &bp); |
| 1081 | if (error) { | 1095 | if (error) { |
| 1082 | kmem_free(buf, buf_len); | 1096 | kmem_free(buf); |
| 1083 | return error; | 1097 | return error; |
| 1084 | } | 1098 | } |
| 1085 | block = bp->data; | 1099 | block = bp->data; |
| @@ -1187,8 +1201,10 @@ xfs_dir2_sf_to_block( | |||
| 1187 | tagp = xfs_dir2_data_entry_tag_p(dep); | 1201 | tagp = xfs_dir2_data_entry_tag_p(dep); |
| 1188 | *tagp = cpu_to_be16((char *)dep - (char *)block); | 1202 | *tagp = cpu_to_be16((char *)dep - (char *)block); |
| 1189 | xfs_dir2_data_log_entry(tp, bp, dep); | 1203 | xfs_dir2_data_log_entry(tp, bp, dep); |
| 1190 | blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname( | 1204 | name.name = sfep->name; |
| 1191 | (char *)sfep->name, sfep->namelen)); | 1205 | name.len = sfep->namelen; |
| 1206 | blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops-> | ||
| 1207 | hashname(&name)); | ||
| 1192 | blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, | 1208 | blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, |
| 1193 | (char *)dep - (char *)block)); | 1209 | (char *)dep - (char *)block)); |
| 1194 | offset = (int)((char *)(tagp + 1) - (char *)block); | 1210 | offset = (int)((char *)(tagp + 1) - (char *)block); |
| @@ -1198,7 +1214,7 @@ xfs_dir2_sf_to_block( | |||
| 1198 | sfep = xfs_dir2_sf_nextentry(sfp, sfep); | 1214 | sfep = xfs_dir2_sf_nextentry(sfp, sfep); |
| 1199 | } | 1215 | } |
| 1200 | /* Done with the temporary buffer */ | 1216 | /* Done with the temporary buffer */ |
| 1201 | kmem_free(buf, buf_len); | 1217 | kmem_free(buf); |
| 1202 | /* | 1218 | /* |
| 1203 | * Sort the leaf entries by hash value. | 1219 | * Sort the leaf entries by hash value. |
| 1204 | */ | 1220 | */ |
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index fb8c9e08b23d..498f8d694330 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c | |||
| @@ -65,6 +65,7 @@ xfs_dir2_data_check( | |||
| 65 | xfs_mount_t *mp; /* filesystem mount point */ | 65 | xfs_mount_t *mp; /* filesystem mount point */ |
| 66 | char *p; /* current data position */ | 66 | char *p; /* current data position */ |
| 67 | int stale; /* count of stale leaves */ | 67 | int stale; /* count of stale leaves */ |
| 68 | struct xfs_name name; | ||
| 68 | 69 | ||
| 69 | mp = dp->i_mount; | 70 | mp = dp->i_mount; |
| 70 | d = bp->data; | 71 | d = bp->data; |
| @@ -140,7 +141,9 @@ xfs_dir2_data_check( | |||
| 140 | addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, | 141 | addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk, |
| 141 | (xfs_dir2_data_aoff_t) | 142 | (xfs_dir2_data_aoff_t) |
| 142 | ((char *)dep - (char *)d)); | 143 | ((char *)dep - (char *)d)); |
| 143 | hash = xfs_da_hashname((char *)dep->name, dep->namelen); | 144 | name.name = dep->name; |
| 145 | name.len = dep->namelen; | ||
| 146 | hash = mp->m_dirnameops->hashname(&name); | ||
| 144 | for (i = 0; i < be32_to_cpu(btp->count); i++) { | 147 | for (i = 0; i < be32_to_cpu(btp->count); i++) { |
| 145 | if (be32_to_cpu(lep[i].address) == addr && | 148 | if (be32_to_cpu(lep[i].address) == addr && |
| 146 | be32_to_cpu(lep[i].hashval) == hash) | 149 | be32_to_cpu(lep[i].hashval) == hash) |
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index bc52b803d79b..93535992cb60 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c | |||
| @@ -263,20 +263,21 @@ xfs_dir2_leaf_addname( | |||
| 263 | * If we don't have enough free bytes but we can make enough | 263 | * If we don't have enough free bytes but we can make enough |
| 264 | * by compacting out stale entries, we'll do that. | 264 | * by compacting out stale entries, we'll do that. |
| 265 | */ | 265 | */ |
| 266 | if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < needbytes && | 266 | if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < |
| 267 | be16_to_cpu(leaf->hdr.stale) > 1) { | 267 | needbytes && be16_to_cpu(leaf->hdr.stale) > 1) { |
| 268 | compact = 1; | 268 | compact = 1; |
| 269 | } | 269 | } |
| 270 | /* | 270 | /* |
| 271 | * Otherwise if we don't have enough free bytes we need to | 271 | * Otherwise if we don't have enough free bytes we need to |
| 272 | * convert to node form. | 272 | * convert to node form. |
| 273 | */ | 273 | */ |
| 274 | else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] < | 274 | else if ((char *)bestsp - (char *)&leaf->ents[be16_to_cpu( |
| 275 | needbytes) { | 275 | leaf->hdr.count)] < needbytes) { |
| 276 | /* | 276 | /* |
| 277 | * Just checking or no space reservation, give up. | 277 | * Just checking or no space reservation, give up. |
| 278 | */ | 278 | */ |
| 279 | if (args->justcheck || args->total == 0) { | 279 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || |
| 280 | args->total == 0) { | ||
| 280 | xfs_da_brelse(tp, lbp); | 281 | xfs_da_brelse(tp, lbp); |
| 281 | return XFS_ERROR(ENOSPC); | 282 | return XFS_ERROR(ENOSPC); |
| 282 | } | 283 | } |
| @@ -301,7 +302,7 @@ xfs_dir2_leaf_addname( | |||
| 301 | * If just checking, then it will fit unless we needed to allocate | 302 | * If just checking, then it will fit unless we needed to allocate |
| 302 | * a new data block. | 303 | * a new data block. |
| 303 | */ | 304 | */ |
| 304 | if (args->justcheck) { | 305 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) { |
| 305 | xfs_da_brelse(tp, lbp); | 306 | xfs_da_brelse(tp, lbp); |
| 306 | return use_block == -1 ? XFS_ERROR(ENOSPC) : 0; | 307 | return use_block == -1 ? XFS_ERROR(ENOSPC) : 0; |
| 307 | } | 308 | } |
| @@ -1110,7 +1111,7 @@ xfs_dir2_leaf_getdents( | |||
| 1110 | *offset = XFS_DIR2_MAX_DATAPTR; | 1111 | *offset = XFS_DIR2_MAX_DATAPTR; |
| 1111 | else | 1112 | else |
| 1112 | *offset = xfs_dir2_byte_to_dataptr(mp, curoff); | 1113 | *offset = xfs_dir2_byte_to_dataptr(mp, curoff); |
| 1113 | kmem_free(map, map_size * sizeof(*map)); | 1114 | kmem_free(map); |
| 1114 | if (bp) | 1115 | if (bp) |
| 1115 | xfs_da_brelse(NULL, bp); | 1116 | xfs_da_brelse(NULL, bp); |
| 1116 | return error; | 1117 | return error; |
| @@ -1298,12 +1299,13 @@ xfs_dir2_leaf_lookup( | |||
| 1298 | ((char *)dbp->data + | 1299 | ((char *)dbp->data + |
| 1299 | xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address))); | 1300 | xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address))); |
| 1300 | /* | 1301 | /* |
| 1301 | * Return the found inode number. | 1302 | * Return the found inode number & CI name if appropriate |
| 1302 | */ | 1303 | */ |
| 1303 | args->inumber = be64_to_cpu(dep->inumber); | 1304 | args->inumber = be64_to_cpu(dep->inumber); |
| 1305 | error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); | ||
| 1304 | xfs_da_brelse(tp, dbp); | 1306 | xfs_da_brelse(tp, dbp); |
| 1305 | xfs_da_brelse(tp, lbp); | 1307 | xfs_da_brelse(tp, lbp); |
| 1306 | return XFS_ERROR(EEXIST); | 1308 | return XFS_ERROR(error); |
| 1307 | } | 1309 | } |
| 1308 | 1310 | ||
| 1309 | /* | 1311 | /* |
| @@ -1319,8 +1321,8 @@ xfs_dir2_leaf_lookup_int( | |||
| 1319 | int *indexp, /* out: index in leaf block */ | 1321 | int *indexp, /* out: index in leaf block */ |
| 1320 | xfs_dabuf_t **dbpp) /* out: data buffer */ | 1322 | xfs_dabuf_t **dbpp) /* out: data buffer */ |
| 1321 | { | 1323 | { |
| 1322 | xfs_dir2_db_t curdb; /* current data block number */ | 1324 | xfs_dir2_db_t curdb = -1; /* current data block number */ |
| 1323 | xfs_dabuf_t *dbp; /* data buffer */ | 1325 | xfs_dabuf_t *dbp = NULL; /* data buffer */ |
| 1324 | xfs_dir2_data_entry_t *dep; /* data entry */ | 1326 | xfs_dir2_data_entry_t *dep; /* data entry */ |
| 1325 | xfs_inode_t *dp; /* incore directory inode */ | 1327 | xfs_inode_t *dp; /* incore directory inode */ |
| 1326 | int error; /* error return code */ | 1328 | int error; /* error return code */ |
| @@ -1331,6 +1333,8 @@ xfs_dir2_leaf_lookup_int( | |||
| 1331 | xfs_mount_t *mp; /* filesystem mount point */ | 1333 | xfs_mount_t *mp; /* filesystem mount point */ |
| 1332 | xfs_dir2_db_t newdb; /* new data block number */ | 1334 | xfs_dir2_db_t newdb; /* new data block number */ |
| 1333 | xfs_trans_t *tp; /* transaction pointer */ | 1335 | xfs_trans_t *tp; /* transaction pointer */ |
| 1336 | xfs_dir2_db_t cidb = -1; /* case match data block no. */ | ||
| 1337 | enum xfs_dacmp cmp; /* name compare result */ | ||
| 1334 | 1338 | ||
| 1335 | dp = args->dp; | 1339 | dp = args->dp; |
| 1336 | tp = args->trans; | 1340 | tp = args->trans; |
| @@ -1338,11 +1342,10 @@ xfs_dir2_leaf_lookup_int( | |||
| 1338 | /* | 1342 | /* |
| 1339 | * Read the leaf block into the buffer. | 1343 | * Read the leaf block into the buffer. |
| 1340 | */ | 1344 | */ |
| 1341 | if ((error = | 1345 | error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, |
| 1342 | xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, | 1346 | XFS_DATA_FORK); |
| 1343 | XFS_DATA_FORK))) { | 1347 | if (error) |
| 1344 | return error; | 1348 | return error; |
| 1345 | } | ||
| 1346 | *lbpp = lbp; | 1349 | *lbpp = lbp; |
| 1347 | leaf = lbp->data; | 1350 | leaf = lbp->data; |
| 1348 | xfs_dir2_leaf_check(dp, lbp); | 1351 | xfs_dir2_leaf_check(dp, lbp); |
| @@ -1354,9 +1357,9 @@ xfs_dir2_leaf_lookup_int( | |||
| 1354 | * Loop over all the entries with the right hash value | 1357 | * Loop over all the entries with the right hash value |
| 1355 | * looking to match the name. | 1358 | * looking to match the name. |
| 1356 | */ | 1359 | */ |
| 1357 | for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; | 1360 | for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && |
| 1358 | index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; | 1361 | be32_to_cpu(lep->hashval) == args->hashval; |
| 1359 | lep++, index++) { | 1362 | lep++, index++) { |
| 1360 | /* | 1363 | /* |
| 1361 | * Skip over stale leaf entries. | 1364 | * Skip over stale leaf entries. |
| 1362 | */ | 1365 | */ |
| @@ -1373,10 +1376,10 @@ xfs_dir2_leaf_lookup_int( | |||
| 1373 | if (newdb != curdb) { | 1376 | if (newdb != curdb) { |
| 1374 | if (dbp) | 1377 | if (dbp) |
| 1375 | xfs_da_brelse(tp, dbp); | 1378 | xfs_da_brelse(tp, dbp); |
| 1376 | if ((error = | 1379 | error = xfs_da_read_buf(tp, dp, |
| 1377 | xfs_da_read_buf(tp, dp, | 1380 | xfs_dir2_db_to_da(mp, newdb), |
| 1378 | xfs_dir2_db_to_da(mp, newdb), -1, &dbp, | 1381 | -1, &dbp, XFS_DATA_FORK); |
| 1379 | XFS_DATA_FORK))) { | 1382 | if (error) { |
| 1380 | xfs_da_brelse(tp, lbp); | 1383 | xfs_da_brelse(tp, lbp); |
| 1381 | return error; | 1384 | return error; |
| 1382 | } | 1385 | } |
| @@ -1386,24 +1389,50 @@ xfs_dir2_leaf_lookup_int( | |||
| 1386 | /* | 1389 | /* |
| 1387 | * Point to the data entry. | 1390 | * Point to the data entry. |
| 1388 | */ | 1391 | */ |
| 1389 | dep = (xfs_dir2_data_entry_t *) | 1392 | dep = (xfs_dir2_data_entry_t *)((char *)dbp->data + |
| 1390 | ((char *)dbp->data + | 1393 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); |
| 1391 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); | ||
| 1392 | /* | 1394 | /* |
| 1393 | * If it matches then return it. | 1395 | * Compare name and if it's an exact match, return the index |
| 1396 | * and buffer. If it's the first case-insensitive match, store | ||
| 1397 | * the index and buffer and continue looking for an exact match. | ||
| 1394 | */ | 1398 | */ |
| 1395 | if (dep->namelen == args->namelen && | 1399 | cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); |
| 1396 | dep->name[0] == args->name[0] && | 1400 | if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { |
| 1397 | memcmp(dep->name, args->name, args->namelen) == 0) { | 1401 | args->cmpresult = cmp; |
| 1398 | *dbpp = dbp; | ||
| 1399 | *indexp = index; | 1402 | *indexp = index; |
| 1400 | return 0; | 1403 | /* case exact match: return the current buffer. */ |
| 1404 | if (cmp == XFS_CMP_EXACT) { | ||
| 1405 | *dbpp = dbp; | ||
| 1406 | return 0; | ||
| 1407 | } | ||
| 1408 | cidb = curdb; | ||
| 1401 | } | 1409 | } |
| 1402 | } | 1410 | } |
| 1411 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); | ||
| 1412 | /* | ||
| 1413 | * Here, we can only be doing a lookup (not a rename or remove). | ||
| 1414 | * If a case-insensitive match was found earlier, re-read the | ||
| 1415 | * appropriate data block if required and return it. | ||
| 1416 | */ | ||
| 1417 | if (args->cmpresult == XFS_CMP_CASE) { | ||
| 1418 | ASSERT(cidb != -1); | ||
| 1419 | if (cidb != curdb) { | ||
| 1420 | xfs_da_brelse(tp, dbp); | ||
| 1421 | error = xfs_da_read_buf(tp, dp, | ||
| 1422 | xfs_dir2_db_to_da(mp, cidb), | ||
| 1423 | -1, &dbp, XFS_DATA_FORK); | ||
| 1424 | if (error) { | ||
| 1425 | xfs_da_brelse(tp, lbp); | ||
| 1426 | return error; | ||
| 1427 | } | ||
| 1428 | } | ||
| 1429 | *dbpp = dbp; | ||
| 1430 | return 0; | ||
| 1431 | } | ||
| 1403 | /* | 1432 | /* |
| 1404 | * No match found, return ENOENT. | 1433 | * No match found, return ENOENT. |
| 1405 | */ | 1434 | */ |
| 1406 | ASSERT(args->oknoent); | 1435 | ASSERT(cidb == -1); |
| 1407 | if (dbp) | 1436 | if (dbp) |
| 1408 | xfs_da_brelse(tp, dbp); | 1437 | xfs_da_brelse(tp, dbp); |
| 1409 | xfs_da_brelse(tp, lbp); | 1438 | xfs_da_brelse(tp, lbp); |
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index 8dade711f099..fa6c3a5ddbc6 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c | |||
| @@ -226,7 +226,7 @@ xfs_dir2_leafn_add( | |||
| 226 | ASSERT(index == be16_to_cpu(leaf->hdr.count) || | 226 | ASSERT(index == be16_to_cpu(leaf->hdr.count) || |
| 227 | be32_to_cpu(leaf->ents[index].hashval) >= args->hashval); | 227 | be32_to_cpu(leaf->ents[index].hashval) >= args->hashval); |
| 228 | 228 | ||
| 229 | if (args->justcheck) | 229 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) |
| 230 | return 0; | 230 | return 0; |
| 231 | 231 | ||
| 232 | /* | 232 | /* |
| @@ -387,28 +387,26 @@ xfs_dir2_leafn_lasthash( | |||
| 387 | } | 387 | } |
| 388 | 388 | ||
| 389 | /* | 389 | /* |
| 390 | * Look up a leaf entry in a node-format leaf block. | 390 | * Look up a leaf entry for space to add a name in a node-format leaf block. |
| 391 | * If this is an addname then the extrablk in state is a freespace block, | 391 | * The extrablk in state is a freespace block. |
| 392 | * otherwise it's a data block. | ||
| 393 | */ | 392 | */ |
| 394 | int | 393 | STATIC int |
| 395 | xfs_dir2_leafn_lookup_int( | 394 | xfs_dir2_leafn_lookup_for_addname( |
| 396 | xfs_dabuf_t *bp, /* leaf buffer */ | 395 | xfs_dabuf_t *bp, /* leaf buffer */ |
| 397 | xfs_da_args_t *args, /* operation arguments */ | 396 | xfs_da_args_t *args, /* operation arguments */ |
| 398 | int *indexp, /* out: leaf entry index */ | 397 | int *indexp, /* out: leaf entry index */ |
| 399 | xfs_da_state_t *state) /* state to fill in */ | 398 | xfs_da_state_t *state) /* state to fill in */ |
| 400 | { | 399 | { |
| 401 | xfs_dabuf_t *curbp; /* current data/free buffer */ | 400 | xfs_dabuf_t *curbp = NULL; /* current data/free buffer */ |
| 402 | xfs_dir2_db_t curdb; /* current data block number */ | 401 | xfs_dir2_db_t curdb = -1; /* current data block number */ |
| 403 | xfs_dir2_db_t curfdb; /* current free block number */ | 402 | xfs_dir2_db_t curfdb = -1; /* current free block number */ |
| 404 | xfs_dir2_data_entry_t *dep; /* data block entry */ | ||
| 405 | xfs_inode_t *dp; /* incore directory inode */ | 403 | xfs_inode_t *dp; /* incore directory inode */ |
| 406 | int error; /* error return value */ | 404 | int error; /* error return value */ |
| 407 | int fi; /* free entry index */ | 405 | int fi; /* free entry index */ |
| 408 | xfs_dir2_free_t *free=NULL; /* free block structure */ | 406 | xfs_dir2_free_t *free = NULL; /* free block structure */ |
| 409 | int index; /* leaf entry index */ | 407 | int index; /* leaf entry index */ |
| 410 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | 408 | xfs_dir2_leaf_t *leaf; /* leaf structure */ |
| 411 | int length=0; /* length of new data entry */ | 409 | int length; /* length of new data entry */ |
| 412 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | 410 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ |
| 413 | xfs_mount_t *mp; /* filesystem mount point */ | 411 | xfs_mount_t *mp; /* filesystem mount point */ |
| 414 | xfs_dir2_db_t newdb; /* new data block number */ | 412 | xfs_dir2_db_t newdb; /* new data block number */ |
| @@ -431,33 +429,20 @@ xfs_dir2_leafn_lookup_int( | |||
| 431 | /* | 429 | /* |
| 432 | * Do we have a buffer coming in? | 430 | * Do we have a buffer coming in? |
| 433 | */ | 431 | */ |
| 434 | if (state->extravalid) | 432 | if (state->extravalid) { |
| 433 | /* If so, it's a free block buffer, get the block number. */ | ||
| 435 | curbp = state->extrablk.bp; | 434 | curbp = state->extrablk.bp; |
| 436 | else | 435 | curfdb = state->extrablk.blkno; |
| 437 | curbp = NULL; | 436 | free = curbp->data; |
| 438 | /* | 437 | ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC); |
| 439 | * For addname, it's a free block buffer, get the block number. | ||
| 440 | */ | ||
| 441 | if (args->addname) { | ||
| 442 | curfdb = curbp ? state->extrablk.blkno : -1; | ||
| 443 | curdb = -1; | ||
| 444 | length = xfs_dir2_data_entsize(args->namelen); | ||
| 445 | if ((free = (curbp ? curbp->data : NULL))) | ||
| 446 | ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC); | ||
| 447 | } | ||
| 448 | /* | ||
| 449 | * For others, it's a data block buffer, get the block number. | ||
| 450 | */ | ||
| 451 | else { | ||
| 452 | curfdb = -1; | ||
| 453 | curdb = curbp ? state->extrablk.blkno : -1; | ||
| 454 | } | 438 | } |
| 439 | length = xfs_dir2_data_entsize(args->namelen); | ||
| 455 | /* | 440 | /* |
| 456 | * Loop over leaf entries with the right hash value. | 441 | * Loop over leaf entries with the right hash value. |
| 457 | */ | 442 | */ |
| 458 | for (lep = &leaf->ents[index]; | 443 | for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && |
| 459 | index < be16_to_cpu(leaf->hdr.count) && be32_to_cpu(lep->hashval) == args->hashval; | 444 | be32_to_cpu(lep->hashval) == args->hashval; |
| 460 | lep++, index++) { | 445 | lep++, index++) { |
| 461 | /* | 446 | /* |
| 462 | * Skip stale leaf entries. | 447 | * Skip stale leaf entries. |
| 463 | */ | 448 | */ |
| @@ -471,161 +456,244 @@ xfs_dir2_leafn_lookup_int( | |||
| 471 | * For addname, we're looking for a place to put the new entry. | 456 | * For addname, we're looking for a place to put the new entry. |
| 472 | * We want to use a data block with an entry of equal | 457 | * We want to use a data block with an entry of equal |
| 473 | * hash value to ours if there is one with room. | 458 | * hash value to ours if there is one with room. |
| 459 | * | ||
| 460 | * If this block isn't the data block we already have | ||
| 461 | * in hand, take a look at it. | ||
| 474 | */ | 462 | */ |
| 475 | if (args->addname) { | 463 | if (newdb != curdb) { |
| 464 | curdb = newdb; | ||
| 476 | /* | 465 | /* |
| 477 | * If this block isn't the data block we already have | 466 | * Convert the data block to the free block |
| 478 | * in hand, take a look at it. | 467 | * holding its freespace information. |
| 479 | */ | 468 | */ |
| 480 | if (newdb != curdb) { | 469 | newfdb = xfs_dir2_db_to_fdb(mp, newdb); |
| 481 | curdb = newdb; | ||
| 482 | /* | ||
| 483 | * Convert the data block to the free block | ||
| 484 | * holding its freespace information. | ||
| 485 | */ | ||
| 486 | newfdb = xfs_dir2_db_to_fdb(mp, newdb); | ||
| 487 | /* | ||
| 488 | * If it's not the one we have in hand, | ||
| 489 | * read it in. | ||
| 490 | */ | ||
| 491 | if (newfdb != curfdb) { | ||
| 492 | /* | ||
| 493 | * If we had one before, drop it. | ||
| 494 | */ | ||
| 495 | if (curbp) | ||
| 496 | xfs_da_brelse(tp, curbp); | ||
| 497 | /* | ||
| 498 | * Read the free block. | ||
| 499 | */ | ||
| 500 | if ((error = xfs_da_read_buf(tp, dp, | ||
| 501 | xfs_dir2_db_to_da(mp, | ||
| 502 | newfdb), | ||
| 503 | -1, &curbp, | ||
| 504 | XFS_DATA_FORK))) { | ||
| 505 | return error; | ||
| 506 | } | ||
| 507 | free = curbp->data; | ||
| 508 | ASSERT(be32_to_cpu(free->hdr.magic) == | ||
| 509 | XFS_DIR2_FREE_MAGIC); | ||
| 510 | ASSERT((be32_to_cpu(free->hdr.firstdb) % | ||
| 511 | XFS_DIR2_MAX_FREE_BESTS(mp)) == | ||
| 512 | 0); | ||
| 513 | ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb); | ||
| 514 | ASSERT(curdb < | ||
| 515 | be32_to_cpu(free->hdr.firstdb) + | ||
| 516 | be32_to_cpu(free->hdr.nvalid)); | ||
| 517 | } | ||
| 518 | /* | ||
| 519 | * Get the index for our entry. | ||
| 520 | */ | ||
| 521 | fi = xfs_dir2_db_to_fdindex(mp, curdb); | ||
| 522 | /* | ||
| 523 | * If it has room, return it. | ||
| 524 | */ | ||
| 525 | if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) { | ||
| 526 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", | ||
| 527 | XFS_ERRLEVEL_LOW, mp); | ||
| 528 | if (curfdb != newfdb) | ||
| 529 | xfs_da_brelse(tp, curbp); | ||
| 530 | return XFS_ERROR(EFSCORRUPTED); | ||
| 531 | } | ||
| 532 | curfdb = newfdb; | ||
| 533 | if (be16_to_cpu(free->bests[fi]) >= length) { | ||
| 534 | *indexp = index; | ||
| 535 | state->extravalid = 1; | ||
| 536 | state->extrablk.bp = curbp; | ||
| 537 | state->extrablk.blkno = curfdb; | ||
| 538 | state->extrablk.index = fi; | ||
| 539 | state->extrablk.magic = | ||
| 540 | XFS_DIR2_FREE_MAGIC; | ||
| 541 | ASSERT(args->oknoent); | ||
| 542 | return XFS_ERROR(ENOENT); | ||
| 543 | } | ||
| 544 | } | ||
| 545 | } | ||
| 546 | /* | ||
| 547 | * Not adding a new entry, so we really want to find | ||
| 548 | * the name given to us. | ||
| 549 | */ | ||
| 550 | else { | ||
| 551 | /* | 470 | /* |
| 552 | * If it's a different data block, go get it. | 471 | * If it's not the one we have in hand, read it in. |
| 553 | */ | 472 | */ |
| 554 | if (newdb != curdb) { | 473 | if (newfdb != curfdb) { |
| 555 | /* | 474 | /* |
| 556 | * If we had a block before, drop it. | 475 | * If we had one before, drop it. |
| 557 | */ | 476 | */ |
| 558 | if (curbp) | 477 | if (curbp) |
| 559 | xfs_da_brelse(tp, curbp); | 478 | xfs_da_brelse(tp, curbp); |
| 560 | /* | 479 | /* |
| 561 | * Read the data block. | 480 | * Read the free block. |
| 562 | */ | 481 | */ |
| 563 | if ((error = | 482 | error = xfs_da_read_buf(tp, dp, |
| 564 | xfs_da_read_buf(tp, dp, | 483 | xfs_dir2_db_to_da(mp, newfdb), |
| 565 | xfs_dir2_db_to_da(mp, newdb), -1, | 484 | -1, &curbp, XFS_DATA_FORK); |
| 566 | &curbp, XFS_DATA_FORK))) { | 485 | if (error) |
| 567 | return error; | 486 | return error; |
| 568 | } | 487 | free = curbp->data; |
| 569 | xfs_dir2_data_check(dp, curbp); | 488 | ASSERT(be32_to_cpu(free->hdr.magic) == |
| 570 | curdb = newdb; | 489 | XFS_DIR2_FREE_MAGIC); |
| 490 | ASSERT((be32_to_cpu(free->hdr.firstdb) % | ||
| 491 | XFS_DIR2_MAX_FREE_BESTS(mp)) == 0); | ||
| 492 | ASSERT(be32_to_cpu(free->hdr.firstdb) <= curdb); | ||
| 493 | ASSERT(curdb < be32_to_cpu(free->hdr.firstdb) + | ||
| 494 | be32_to_cpu(free->hdr.nvalid)); | ||
| 571 | } | 495 | } |
| 572 | /* | 496 | /* |
| 573 | * Point to the data entry. | 497 | * Get the index for our entry. |
| 574 | */ | 498 | */ |
| 575 | dep = (xfs_dir2_data_entry_t *) | 499 | fi = xfs_dir2_db_to_fdindex(mp, curdb); |
| 576 | ((char *)curbp->data + | ||
| 577 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); | ||
| 578 | /* | 500 | /* |
| 579 | * Compare the entry, return it if it matches. | 501 | * If it has room, return it. |
| 580 | */ | 502 | */ |
| 581 | if (dep->namelen == args->namelen && | 503 | if (unlikely(be16_to_cpu(free->bests[fi]) == NULLDATAOFF)) { |
| 582 | dep->name[0] == args->name[0] && | 504 | XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", |
| 583 | memcmp(dep->name, args->name, args->namelen) == 0) { | 505 | XFS_ERRLEVEL_LOW, mp); |
| 584 | args->inumber = be64_to_cpu(dep->inumber); | 506 | if (curfdb != newfdb) |
| 585 | *indexp = index; | 507 | xfs_da_brelse(tp, curbp); |
| 586 | state->extravalid = 1; | 508 | return XFS_ERROR(EFSCORRUPTED); |
| 587 | state->extrablk.bp = curbp; | ||
| 588 | state->extrablk.blkno = curdb; | ||
| 589 | state->extrablk.index = | ||
| 590 | (int)((char *)dep - | ||
| 591 | (char *)curbp->data); | ||
| 592 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | ||
| 593 | return XFS_ERROR(EEXIST); | ||
| 594 | } | 509 | } |
| 510 | curfdb = newfdb; | ||
| 511 | if (be16_to_cpu(free->bests[fi]) >= length) | ||
| 512 | goto out; | ||
| 595 | } | 513 | } |
| 596 | } | 514 | } |
| 515 | /* Didn't find any space */ | ||
| 516 | fi = -1; | ||
| 517 | out: | ||
| 518 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); | ||
| 519 | if (curbp) { | ||
| 520 | /* Giving back a free block. */ | ||
| 521 | state->extravalid = 1; | ||
| 522 | state->extrablk.bp = curbp; | ||
| 523 | state->extrablk.index = fi; | ||
| 524 | state->extrablk.blkno = curfdb; | ||
| 525 | state->extrablk.magic = XFS_DIR2_FREE_MAGIC; | ||
| 526 | } else { | ||
| 527 | state->extravalid = 0; | ||
| 528 | } | ||
| 597 | /* | 529 | /* |
| 598 | * Didn't find a match. | 530 | * Return the index, that will be the insertion point. |
| 599 | * If we are holding a buffer, give it back in case our caller | ||
| 600 | * finds it useful. | ||
| 601 | */ | 531 | */ |
| 602 | if ((state->extravalid = (curbp != NULL))) { | 532 | *indexp = index; |
| 603 | state->extrablk.bp = curbp; | 533 | return XFS_ERROR(ENOENT); |
| 604 | state->extrablk.index = -1; | 534 | } |
| 535 | |||
| 536 | /* | ||
| 537 | * Look up a leaf entry in a node-format leaf block. | ||
| 538 | * The extrablk in state a data block. | ||
| 539 | */ | ||
| 540 | STATIC int | ||
| 541 | xfs_dir2_leafn_lookup_for_entry( | ||
| 542 | xfs_dabuf_t *bp, /* leaf buffer */ | ||
| 543 | xfs_da_args_t *args, /* operation arguments */ | ||
| 544 | int *indexp, /* out: leaf entry index */ | ||
| 545 | xfs_da_state_t *state) /* state to fill in */ | ||
| 546 | { | ||
| 547 | xfs_dabuf_t *curbp = NULL; /* current data/free buffer */ | ||
| 548 | xfs_dir2_db_t curdb = -1; /* current data block number */ | ||
| 549 | xfs_dir2_data_entry_t *dep; /* data block entry */ | ||
| 550 | xfs_inode_t *dp; /* incore directory inode */ | ||
| 551 | int error; /* error return value */ | ||
| 552 | int index; /* leaf entry index */ | ||
| 553 | xfs_dir2_leaf_t *leaf; /* leaf structure */ | ||
| 554 | xfs_dir2_leaf_entry_t *lep; /* leaf entry */ | ||
| 555 | xfs_mount_t *mp; /* filesystem mount point */ | ||
| 556 | xfs_dir2_db_t newdb; /* new data block number */ | ||
| 557 | xfs_trans_t *tp; /* transaction pointer */ | ||
| 558 | enum xfs_dacmp cmp; /* comparison result */ | ||
| 559 | |||
| 560 | dp = args->dp; | ||
| 561 | tp = args->trans; | ||
| 562 | mp = dp->i_mount; | ||
| 563 | leaf = bp->data; | ||
| 564 | ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC); | ||
| 565 | #ifdef __KERNEL__ | ||
| 566 | ASSERT(be16_to_cpu(leaf->hdr.count) > 0); | ||
| 567 | #endif | ||
| 568 | xfs_dir2_leafn_check(dp, bp); | ||
| 569 | /* | ||
| 570 | * Look up the hash value in the leaf entries. | ||
| 571 | */ | ||
| 572 | index = xfs_dir2_leaf_search_hash(args, bp); | ||
| 573 | /* | ||
| 574 | * Do we have a buffer coming in? | ||
| 575 | */ | ||
| 576 | if (state->extravalid) { | ||
| 577 | curbp = state->extrablk.bp; | ||
| 578 | curdb = state->extrablk.blkno; | ||
| 579 | } | ||
| 580 | /* | ||
| 581 | * Loop over leaf entries with the right hash value. | ||
| 582 | */ | ||
| 583 | for (lep = &leaf->ents[index]; index < be16_to_cpu(leaf->hdr.count) && | ||
| 584 | be32_to_cpu(lep->hashval) == args->hashval; | ||
| 585 | lep++, index++) { | ||
| 605 | /* | 586 | /* |
| 606 | * For addname, giving back a free block. | 587 | * Skip stale leaf entries. |
| 607 | */ | 588 | */ |
| 608 | if (args->addname) { | 589 | if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) |
| 609 | state->extrablk.blkno = curfdb; | 590 | continue; |
| 610 | state->extrablk.magic = XFS_DIR2_FREE_MAGIC; | 591 | /* |
| 592 | * Pull the data block number from the entry. | ||
| 593 | */ | ||
| 594 | newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address)); | ||
| 595 | /* | ||
| 596 | * Not adding a new entry, so we really want to find | ||
| 597 | * the name given to us. | ||
| 598 | * | ||
| 599 | * If it's a different data block, go get it. | ||
| 600 | */ | ||
| 601 | if (newdb != curdb) { | ||
| 602 | /* | ||
| 603 | * If we had a block before that we aren't saving | ||
| 604 | * for a CI name, drop it | ||
| 605 | */ | ||
| 606 | if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || | ||
| 607 | curdb != state->extrablk.blkno)) | ||
| 608 | xfs_da_brelse(tp, curbp); | ||
| 609 | /* | ||
| 610 | * If needing the block that is saved with a CI match, | ||
| 611 | * use it otherwise read in the new data block. | ||
| 612 | */ | ||
| 613 | if (args->cmpresult != XFS_CMP_DIFFERENT && | ||
| 614 | newdb == state->extrablk.blkno) { | ||
| 615 | ASSERT(state->extravalid); | ||
| 616 | curbp = state->extrablk.bp; | ||
| 617 | } else { | ||
| 618 | error = xfs_da_read_buf(tp, dp, | ||
| 619 | xfs_dir2_db_to_da(mp, newdb), | ||
| 620 | -1, &curbp, XFS_DATA_FORK); | ||
| 621 | if (error) | ||
| 622 | return error; | ||
| 623 | } | ||
| 624 | xfs_dir2_data_check(dp, curbp); | ||
| 625 | curdb = newdb; | ||
| 611 | } | 626 | } |
| 612 | /* | 627 | /* |
| 613 | * For other callers, giving back a data block. | 628 | * Point to the data entry. |
| 614 | */ | 629 | */ |
| 615 | else { | 630 | dep = (xfs_dir2_data_entry_t *)((char *)curbp->data + |
| 631 | xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address))); | ||
| 632 | /* | ||
| 633 | * Compare the entry and if it's an exact match, return | ||
| 634 | * EEXIST immediately. If it's the first case-insensitive | ||
| 635 | * match, store the block & inode number and continue looking. | ||
| 636 | */ | ||
| 637 | cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); | ||
| 638 | if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { | ||
| 639 | /* If there is a CI match block, drop it */ | ||
| 640 | if (args->cmpresult != XFS_CMP_DIFFERENT && | ||
| 641 | curdb != state->extrablk.blkno) | ||
| 642 | xfs_da_brelse(tp, state->extrablk.bp); | ||
| 643 | args->cmpresult = cmp; | ||
| 644 | args->inumber = be64_to_cpu(dep->inumber); | ||
| 645 | *indexp = index; | ||
| 646 | state->extravalid = 1; | ||
| 647 | state->extrablk.bp = curbp; | ||
| 616 | state->extrablk.blkno = curdb; | 648 | state->extrablk.blkno = curdb; |
| 649 | state->extrablk.index = (int)((char *)dep - | ||
| 650 | (char *)curbp->data); | ||
| 617 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | 651 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; |
| 652 | if (cmp == XFS_CMP_EXACT) | ||
| 653 | return XFS_ERROR(EEXIST); | ||
| 618 | } | 654 | } |
| 619 | } | 655 | } |
| 620 | /* | 656 | ASSERT(index == be16_to_cpu(leaf->hdr.count) || |
| 621 | * Return the final index, that will be the insertion point. | 657 | (args->op_flags & XFS_DA_OP_OKNOENT)); |
| 622 | */ | 658 | if (curbp) { |
| 659 | if (args->cmpresult == XFS_CMP_DIFFERENT) { | ||
| 660 | /* Giving back last used data block. */ | ||
| 661 | state->extravalid = 1; | ||
| 662 | state->extrablk.bp = curbp; | ||
| 663 | state->extrablk.index = -1; | ||
| 664 | state->extrablk.blkno = curdb; | ||
| 665 | state->extrablk.magic = XFS_DIR2_DATA_MAGIC; | ||
| 666 | } else { | ||
| 667 | /* If the curbp is not the CI match block, drop it */ | ||
| 668 | if (state->extrablk.bp != curbp) | ||
| 669 | xfs_da_brelse(tp, curbp); | ||
| 670 | } | ||
| 671 | } else { | ||
| 672 | state->extravalid = 0; | ||
| 673 | } | ||
| 623 | *indexp = index; | 674 | *indexp = index; |
| 624 | ASSERT(index == be16_to_cpu(leaf->hdr.count) || args->oknoent); | ||
| 625 | return XFS_ERROR(ENOENT); | 675 | return XFS_ERROR(ENOENT); |
| 626 | } | 676 | } |
| 627 | 677 | ||
| 628 | /* | 678 | /* |
| 679 | * Look up a leaf entry in a node-format leaf block. | ||
| 680 | * If this is an addname then the extrablk in state is a freespace block, | ||
| 681 | * otherwise it's a data block. | ||
| 682 | */ | ||
| 683 | int | ||
| 684 | xfs_dir2_leafn_lookup_int( | ||
| 685 | xfs_dabuf_t *bp, /* leaf buffer */ | ||
| 686 | xfs_da_args_t *args, /* operation arguments */ | ||
| 687 | int *indexp, /* out: leaf entry index */ | ||
| 688 | xfs_da_state_t *state) /* state to fill in */ | ||
| 689 | { | ||
| 690 | if (args->op_flags & XFS_DA_OP_ADDNAME) | ||
| 691 | return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, | ||
| 692 | state); | ||
| 693 | return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); | ||
| 694 | } | ||
| 695 | |||
| 696 | /* | ||
| 629 | * Move count leaf entries from source to destination leaf. | 697 | * Move count leaf entries from source to destination leaf. |
| 630 | * Log entries and headers. Stale entries are preserved. | 698 | * Log entries and headers. Stale entries are preserved. |
| 631 | */ | 699 | */ |
| @@ -823,9 +891,10 @@ xfs_dir2_leafn_rebalance( | |||
| 823 | */ | 891 | */ |
| 824 | if (!state->inleaf) | 892 | if (!state->inleaf) |
| 825 | blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); | 893 | blk2->index = blk1->index - be16_to_cpu(leaf1->hdr.count); |
| 826 | 894 | ||
| 827 | /* | 895 | /* |
| 828 | * Finally sanity check just to make sure we are not returning a negative index | 896 | * Finally sanity check just to make sure we are not returning a |
| 897 | * negative index | ||
| 829 | */ | 898 | */ |
| 830 | if(blk2->index < 0) { | 899 | if(blk2->index < 0) { |
| 831 | state->inleaf = 1; | 900 | state->inleaf = 1; |
| @@ -1332,7 +1401,7 @@ xfs_dir2_node_addname( | |||
| 1332 | /* | 1401 | /* |
| 1333 | * It worked, fix the hash values up the btree. | 1402 | * It worked, fix the hash values up the btree. |
| 1334 | */ | 1403 | */ |
| 1335 | if (!args->justcheck) | 1404 | if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) |
| 1336 | xfs_da_fixhashpath(state, &state->path); | 1405 | xfs_da_fixhashpath(state, &state->path); |
| 1337 | } else { | 1406 | } else { |
| 1338 | /* | 1407 | /* |
| @@ -1515,7 +1584,8 @@ xfs_dir2_node_addname_int( | |||
| 1515 | /* | 1584 | /* |
| 1516 | * Not allowed to allocate, return failure. | 1585 | * Not allowed to allocate, return failure. |
| 1517 | */ | 1586 | */ |
| 1518 | if (args->justcheck || args->total == 0) { | 1587 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || |
| 1588 | args->total == 0) { | ||
| 1519 | /* | 1589 | /* |
| 1520 | * Drop the freespace buffer unless it came from our | 1590 | * Drop the freespace buffer unless it came from our |
| 1521 | * caller. | 1591 | * caller. |
| @@ -1661,7 +1731,7 @@ xfs_dir2_node_addname_int( | |||
| 1661 | /* | 1731 | /* |
| 1662 | * If just checking, we succeeded. | 1732 | * If just checking, we succeeded. |
| 1663 | */ | 1733 | */ |
| 1664 | if (args->justcheck) { | 1734 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) { |
| 1665 | if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL) | 1735 | if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL) |
| 1666 | xfs_da_buf_done(fbp); | 1736 | xfs_da_buf_done(fbp); |
| 1667 | return 0; | 1737 | return 0; |
| @@ -1767,6 +1837,14 @@ xfs_dir2_node_lookup( | |||
| 1767 | error = xfs_da_node_lookup_int(state, &rval); | 1837 | error = xfs_da_node_lookup_int(state, &rval); |
| 1768 | if (error) | 1838 | if (error) |
| 1769 | rval = error; | 1839 | rval = error; |
| 1840 | else if (rval == ENOENT && args->cmpresult == XFS_CMP_CASE) { | ||
| 1841 | /* If a CI match, dup the actual name and return EEXIST */ | ||
| 1842 | xfs_dir2_data_entry_t *dep; | ||
| 1843 | |||
| 1844 | dep = (xfs_dir2_data_entry_t *)((char *)state->extrablk.bp-> | ||
| 1845 | data + state->extrablk.index); | ||
| 1846 | rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); | ||
| 1847 | } | ||
| 1770 | /* | 1848 | /* |
| 1771 | * Release the btree blocks and leaf block. | 1849 | * Release the btree blocks and leaf block. |
| 1772 | */ | 1850 | */ |
| @@ -1810,9 +1888,8 @@ xfs_dir2_node_removename( | |||
| 1810 | * Look up the entry we're deleting, set up the cursor. | 1888 | * Look up the entry we're deleting, set up the cursor. |
| 1811 | */ | 1889 | */ |
| 1812 | error = xfs_da_node_lookup_int(state, &rval); | 1890 | error = xfs_da_node_lookup_int(state, &rval); |
| 1813 | if (error) { | 1891 | if (error) |
| 1814 | rval = error; | 1892 | rval = error; |
| 1815 | } | ||
| 1816 | /* | 1893 | /* |
| 1817 | * Didn't find it, upper layer screwed up. | 1894 | * Didn't find it, upper layer screwed up. |
| 1818 | */ | 1895 | */ |
| @@ -1829,9 +1906,8 @@ xfs_dir2_node_removename( | |||
| 1829 | */ | 1906 | */ |
| 1830 | error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, | 1907 | error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, |
| 1831 | &state->extrablk, &rval); | 1908 | &state->extrablk, &rval); |
| 1832 | if (error) { | 1909 | if (error) |
| 1833 | return error; | 1910 | return error; |
| 1834 | } | ||
| 1835 | /* | 1911 | /* |
| 1836 | * Fix the hash values up the btree. | 1912 | * Fix the hash values up the btree. |
| 1837 | */ | 1913 | */ |
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c index 919d275a1cef..b46af0013ec9 100644 --- a/fs/xfs/xfs_dir2_sf.c +++ b/fs/xfs/xfs_dir2_sf.c | |||
| @@ -255,7 +255,7 @@ xfs_dir2_block_to_sf( | |||
| 255 | xfs_dir2_sf_check(args); | 255 | xfs_dir2_sf_check(args); |
| 256 | out: | 256 | out: |
| 257 | xfs_trans_log_inode(args->trans, dp, logflags); | 257 | xfs_trans_log_inode(args->trans, dp, logflags); |
| 258 | kmem_free(block, mp->m_dirblksize); | 258 | kmem_free(block); |
| 259 | return error; | 259 | return error; |
| 260 | } | 260 | } |
| 261 | 261 | ||
| @@ -332,7 +332,7 @@ xfs_dir2_sf_addname( | |||
| 332 | /* | 332 | /* |
| 333 | * Just checking or no space reservation, it doesn't fit. | 333 | * Just checking or no space reservation, it doesn't fit. |
| 334 | */ | 334 | */ |
| 335 | if (args->justcheck || args->total == 0) | 335 | if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) |
| 336 | return XFS_ERROR(ENOSPC); | 336 | return XFS_ERROR(ENOSPC); |
| 337 | /* | 337 | /* |
| 338 | * Convert to block form then add the name. | 338 | * Convert to block form then add the name. |
| @@ -345,7 +345,7 @@ xfs_dir2_sf_addname( | |||
| 345 | /* | 345 | /* |
| 346 | * Just checking, it fits. | 346 | * Just checking, it fits. |
| 347 | */ | 347 | */ |
| 348 | if (args->justcheck) | 348 | if (args->op_flags & XFS_DA_OP_JUSTCHECK) |
| 349 | return 0; | 349 | return 0; |
| 350 | /* | 350 | /* |
| 351 | * Do it the easy way - just add it at the end. | 351 | * Do it the easy way - just add it at the end. |
| @@ -512,7 +512,7 @@ xfs_dir2_sf_addname_hard( | |||
| 512 | sfep = xfs_dir2_sf_nextentry(sfp, sfep); | 512 | sfep = xfs_dir2_sf_nextentry(sfp, sfep); |
| 513 | memcpy(sfep, oldsfep, old_isize - nbytes); | 513 | memcpy(sfep, oldsfep, old_isize - nbytes); |
| 514 | } | 514 | } |
| 515 | kmem_free(buf, old_isize); | 515 | kmem_free(buf); |
| 516 | dp->i_d.di_size = new_isize; | 516 | dp->i_d.di_size = new_isize; |
| 517 | xfs_dir2_sf_check(args); | 517 | xfs_dir2_sf_check(args); |
| 518 | } | 518 | } |
| @@ -812,8 +812,11 @@ xfs_dir2_sf_lookup( | |||
| 812 | { | 812 | { |
| 813 | xfs_inode_t *dp; /* incore directory inode */ | 813 | xfs_inode_t *dp; /* incore directory inode */ |
| 814 | int i; /* entry index */ | 814 | int i; /* entry index */ |
| 815 | int error; | ||
| 815 | xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ | 816 | xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ |
| 816 | xfs_dir2_sf_t *sfp; /* shortform structure */ | 817 | xfs_dir2_sf_t *sfp; /* shortform structure */ |
| 818 | enum xfs_dacmp cmp; /* comparison result */ | ||
| 819 | xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ | ||
| 817 | 820 | ||
| 818 | xfs_dir2_trace_args("sf_lookup", args); | 821 | xfs_dir2_trace_args("sf_lookup", args); |
| 819 | xfs_dir2_sf_check(args); | 822 | xfs_dir2_sf_check(args); |
| @@ -836,6 +839,7 @@ xfs_dir2_sf_lookup( | |||
| 836 | */ | 839 | */ |
| 837 | if (args->namelen == 1 && args->name[0] == '.') { | 840 | if (args->namelen == 1 && args->name[0] == '.') { |
| 838 | args->inumber = dp->i_ino; | 841 | args->inumber = dp->i_ino; |
| 842 | args->cmpresult = XFS_CMP_EXACT; | ||
| 839 | return XFS_ERROR(EEXIST); | 843 | return XFS_ERROR(EEXIST); |
| 840 | } | 844 | } |
| 841 | /* | 845 | /* |
| @@ -844,28 +848,41 @@ xfs_dir2_sf_lookup( | |||
| 844 | if (args->namelen == 2 && | 848 | if (args->namelen == 2 && |
| 845 | args->name[0] == '.' && args->name[1] == '.') { | 849 | args->name[0] == '.' && args->name[1] == '.') { |
| 846 | args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent); | 850 | args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent); |
| 851 | args->cmpresult = XFS_CMP_EXACT; | ||
| 847 | return XFS_ERROR(EEXIST); | 852 | return XFS_ERROR(EEXIST); |
| 848 | } | 853 | } |
| 849 | /* | 854 | /* |
| 850 | * Loop over all the entries trying to match ours. | 855 | * Loop over all the entries trying to match ours. |
| 851 | */ | 856 | */ |
| 852 | for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); | 857 | ci_sfep = NULL; |
| 853 | i < sfp->hdr.count; | 858 | for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count; |
| 854 | i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { | 859 | i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { |
| 855 | if (sfep->namelen == args->namelen && | 860 | /* |
| 856 | sfep->name[0] == args->name[0] && | 861 | * Compare name and if it's an exact match, return the inode |
| 857 | memcmp(args->name, sfep->name, args->namelen) == 0) { | 862 | * number. If it's the first case-insensitive match, store the |
| 858 | args->inumber = | 863 | * inode number and continue looking for an exact match. |
| 859 | xfs_dir2_sf_get_inumber(sfp, | 864 | */ |
| 860 | xfs_dir2_sf_inumberp(sfep)); | 865 | cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, |
| 861 | return XFS_ERROR(EEXIST); | 866 | sfep->namelen); |
| 867 | if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { | ||
| 868 | args->cmpresult = cmp; | ||
| 869 | args->inumber = xfs_dir2_sf_get_inumber(sfp, | ||
| 870 | xfs_dir2_sf_inumberp(sfep)); | ||
| 871 | if (cmp == XFS_CMP_EXACT) | ||
| 872 | return XFS_ERROR(EEXIST); | ||
| 873 | ci_sfep = sfep; | ||
| 862 | } | 874 | } |
| 863 | } | 875 | } |
| 876 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); | ||
| 864 | /* | 877 | /* |
| 865 | * Didn't find it. | 878 | * Here, we can only be doing a lookup (not a rename or replace). |
| 879 | * If a case-insensitive match was not found, return ENOENT. | ||
| 866 | */ | 880 | */ |
| 867 | ASSERT(args->oknoent); | 881 | if (!ci_sfep) |
| 868 | return XFS_ERROR(ENOENT); | 882 | return XFS_ERROR(ENOENT); |
| 883 | /* otherwise process the CI match as required by the caller */ | ||
| 884 | error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); | ||
| 885 | return XFS_ERROR(error); | ||
| 869 | } | 886 | } |
| 870 | 887 | ||
| 871 | /* | 888 | /* |
| @@ -904,24 +921,21 @@ xfs_dir2_sf_removename( | |||
| 904 | * Loop over the old directory entries. | 921 | * Loop over the old directory entries. |
| 905 | * Find the one we're deleting. | 922 | * Find the one we're deleting. |
| 906 | */ | 923 | */ |
| 907 | for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); | 924 | for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->hdr.count; |
| 908 | i < sfp->hdr.count; | 925 | i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { |
| 909 | i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { | 926 | if (xfs_da_compname(args, sfep->name, sfep->namelen) == |
| 910 | if (sfep->namelen == args->namelen && | 927 | XFS_CMP_EXACT) { |
| 911 | sfep->name[0] == args->name[0] && | ||
| 912 | memcmp(sfep->name, args->name, args->namelen) == 0) { | ||
| 913 | ASSERT(xfs_dir2_sf_get_inumber(sfp, | 928 | ASSERT(xfs_dir2_sf_get_inumber(sfp, |
| 914 | xfs_dir2_sf_inumberp(sfep)) == | 929 | xfs_dir2_sf_inumberp(sfep)) == |
| 915 | args->inumber); | 930 | args->inumber); |
| 916 | break; | 931 | break; |
| 917 | } | 932 | } |
| 918 | } | 933 | } |
| 919 | /* | 934 | /* |
| 920 | * Didn't find it. | 935 | * Didn't find it. |
| 921 | */ | 936 | */ |
| 922 | if (i == sfp->hdr.count) { | 937 | if (i == sfp->hdr.count) |
| 923 | return XFS_ERROR(ENOENT); | 938 | return XFS_ERROR(ENOENT); |
| 924 | } | ||
| 925 | /* | 939 | /* |
| 926 | * Calculate sizes. | 940 | * Calculate sizes. |
| 927 | */ | 941 | */ |
| @@ -1042,11 +1056,10 @@ xfs_dir2_sf_replace( | |||
| 1042 | */ | 1056 | */ |
| 1043 | else { | 1057 | else { |
| 1044 | for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); | 1058 | for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); |
| 1045 | i < sfp->hdr.count; | 1059 | i < sfp->hdr.count; |
| 1046 | i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { | 1060 | i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) { |
| 1047 | if (sfep->namelen == args->namelen && | 1061 | if (xfs_da_compname(args, sfep->name, sfep->namelen) == |
| 1048 | sfep->name[0] == args->name[0] && | 1062 | XFS_CMP_EXACT) { |
| 1049 | memcmp(args->name, sfep->name, args->namelen) == 0) { | ||
| 1050 | #if XFS_BIG_INUMS || defined(DEBUG) | 1063 | #if XFS_BIG_INUMS || defined(DEBUG) |
| 1051 | ino = xfs_dir2_sf_get_inumber(sfp, | 1064 | ino = xfs_dir2_sf_get_inumber(sfp, |
| 1052 | xfs_dir2_sf_inumberp(sfep)); | 1065 | xfs_dir2_sf_inumberp(sfep)); |
| @@ -1061,7 +1074,7 @@ xfs_dir2_sf_replace( | |||
| 1061 | * Didn't find it. | 1074 | * Didn't find it. |
| 1062 | */ | 1075 | */ |
| 1063 | if (i == sfp->hdr.count) { | 1076 | if (i == sfp->hdr.count) { |
| 1064 | ASSERT(args->oknoent); | 1077 | ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); |
| 1065 | #if XFS_BIG_INUMS | 1078 | #if XFS_BIG_INUMS |
| 1066 | if (i8elevated) | 1079 | if (i8elevated) |
| 1067 | xfs_dir2_sf_toino4(args); | 1080 | xfs_dir2_sf_toino4(args); |
| @@ -1174,7 +1187,7 @@ xfs_dir2_sf_toino4( | |||
| 1174 | /* | 1187 | /* |
| 1175 | * Clean up the inode. | 1188 | * Clean up the inode. |
| 1176 | */ | 1189 | */ |
| 1177 | kmem_free(buf, oldsize); | 1190 | kmem_free(buf); |
| 1178 | dp->i_d.di_size = newsize; | 1191 | dp->i_d.di_size = newsize; |
| 1179 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); | 1192 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); |
| 1180 | } | 1193 | } |
| @@ -1251,7 +1264,7 @@ xfs_dir2_sf_toino8( | |||
| 1251 | /* | 1264 | /* |
| 1252 | * Clean up the inode. | 1265 | * Clean up the inode. |
| 1253 | */ | 1266 | */ |
| 1254 | kmem_free(buf, oldsize); | 1267 | kmem_free(buf); |
| 1255 | dp->i_d.di_size = newsize; | 1268 | dp->i_d.di_size = newsize; |
| 1256 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); | 1269 | xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); |
| 1257 | } | 1270 | } |
diff --git a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h index 005629d702d2..deecc9d238f8 100644 --- a/fs/xfs/xfs_dir2_sf.h +++ b/fs/xfs/xfs_dir2_sf.h | |||
| @@ -62,7 +62,7 @@ typedef union { | |||
| 62 | * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. | 62 | * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. |
| 63 | * Only need 16 bits, this is the byte offset into the single block form. | 63 | * Only need 16 bits, this is the byte offset into the single block form. |
| 64 | */ | 64 | */ |
| 65 | typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; | 65 | typedef struct { __uint8_t i[2]; } __arch_pack xfs_dir2_sf_off_t; |
| 66 | 66 | ||
| 67 | /* | 67 | /* |
| 68 | * The parent directory has a dedicated field, and the self-pointer must | 68 | * The parent directory has a dedicated field, and the self-pointer must |
| @@ -76,14 +76,14 @@ typedef struct xfs_dir2_sf_hdr { | |||
| 76 | __uint8_t count; /* count of entries */ | 76 | __uint8_t count; /* count of entries */ |
| 77 | __uint8_t i8count; /* count of 8-byte inode #s */ | 77 | __uint8_t i8count; /* count of 8-byte inode #s */ |
| 78 | xfs_dir2_inou_t parent; /* parent dir inode number */ | 78 | xfs_dir2_inou_t parent; /* parent dir inode number */ |
| 79 | } xfs_dir2_sf_hdr_t; | 79 | } __arch_pack xfs_dir2_sf_hdr_t; |
| 80 | 80 | ||
| 81 | typedef struct xfs_dir2_sf_entry { | 81 | typedef struct xfs_dir2_sf_entry { |
| 82 | __uint8_t namelen; /* actual name length */ | 82 | __uint8_t namelen; /* actual name length */ |
| 83 | xfs_dir2_sf_off_t offset; /* saved offset */ | 83 | xfs_dir2_sf_off_t offset; /* saved offset */ |
| 84 | __uint8_t name[1]; /* name, variable size */ | 84 | __uint8_t name[1]; /* name, variable size */ |
| 85 | xfs_dir2_inou_t inumber; /* inode number, var. offset */ | 85 | xfs_dir2_inou_t inumber; /* inode number, var. offset */ |
| 86 | } xfs_dir2_sf_entry_t; | 86 | } __arch_pack xfs_dir2_sf_entry_t; |
| 87 | 87 | ||
| 88 | typedef struct xfs_dir2_sf { | 88 | typedef struct xfs_dir2_sf { |
| 89 | xfs_dir2_sf_hdr_t hdr; /* shortform header */ | 89 | xfs_dir2_sf_hdr_t hdr; /* shortform header */ |
diff --git a/fs/xfs/xfs_dir2_trace.c b/fs/xfs/xfs_dir2_trace.c index f3fb2ffd6f5c..6cc7c0c681ac 100644 --- a/fs/xfs/xfs_dir2_trace.c +++ b/fs/xfs/xfs_dir2_trace.c | |||
| @@ -85,7 +85,8 @@ xfs_dir2_trace_args( | |||
| 85 | (void *)((unsigned long)(args->inumber >> 32)), | 85 | (void *)((unsigned long)(args->inumber >> 32)), |
| 86 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 86 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 87 | (void *)args->dp, (void *)args->trans, | 87 | (void *)args->dp, (void *)args->trans, |
| 88 | (void *)(unsigned long)args->justcheck, NULL, NULL); | 88 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 89 | NULL, NULL); | ||
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | void | 92 | void |
| @@ -100,7 +101,7 @@ xfs_dir2_trace_args_b( | |||
| 100 | (void *)((unsigned long)(args->inumber >> 32)), | 101 | (void *)((unsigned long)(args->inumber >> 32)), |
| 101 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 102 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 102 | (void *)args->dp, (void *)args->trans, | 103 | (void *)args->dp, (void *)args->trans, |
| 103 | (void *)(unsigned long)args->justcheck, | 104 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 104 | (void *)(bp ? bp->bps[0] : NULL), NULL); | 105 | (void *)(bp ? bp->bps[0] : NULL), NULL); |
| 105 | } | 106 | } |
| 106 | 107 | ||
| @@ -117,7 +118,7 @@ xfs_dir2_trace_args_bb( | |||
| 117 | (void *)((unsigned long)(args->inumber >> 32)), | 118 | (void *)((unsigned long)(args->inumber >> 32)), |
| 118 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 119 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 119 | (void *)args->dp, (void *)args->trans, | 120 | (void *)args->dp, (void *)args->trans, |
| 120 | (void *)(unsigned long)args->justcheck, | 121 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 121 | (void *)(lbp ? lbp->bps[0] : NULL), | 122 | (void *)(lbp ? lbp->bps[0] : NULL), |
| 122 | (void *)(dbp ? dbp->bps[0] : NULL)); | 123 | (void *)(dbp ? dbp->bps[0] : NULL)); |
| 123 | } | 124 | } |
| @@ -157,8 +158,8 @@ xfs_dir2_trace_args_db( | |||
| 157 | (void *)((unsigned long)(args->inumber >> 32)), | 158 | (void *)((unsigned long)(args->inumber >> 32)), |
| 158 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 159 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 159 | (void *)args->dp, (void *)args->trans, | 160 | (void *)args->dp, (void *)args->trans, |
| 160 | (void *)(unsigned long)args->justcheck, (void *)(long)db, | 161 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 161 | (void *)dbp); | 162 | (void *)(long)db, (void *)dbp); |
| 162 | } | 163 | } |
| 163 | 164 | ||
| 164 | void | 165 | void |
| @@ -173,7 +174,7 @@ xfs_dir2_trace_args_i( | |||
| 173 | (void *)((unsigned long)(args->inumber >> 32)), | 174 | (void *)((unsigned long)(args->inumber >> 32)), |
| 174 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 175 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 175 | (void *)args->dp, (void *)args->trans, | 176 | (void *)args->dp, (void *)args->trans, |
| 176 | (void *)(unsigned long)args->justcheck, | 177 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 177 | (void *)((unsigned long)(i >> 32)), | 178 | (void *)((unsigned long)(i >> 32)), |
| 178 | (void *)((unsigned long)(i & 0xFFFFFFFF))); | 179 | (void *)((unsigned long)(i & 0xFFFFFFFF))); |
| 179 | } | 180 | } |
| @@ -190,7 +191,8 @@ xfs_dir2_trace_args_s( | |||
| 190 | (void *)((unsigned long)(args->inumber >> 32)), | 191 | (void *)((unsigned long)(args->inumber >> 32)), |
| 191 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 192 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 192 | (void *)args->dp, (void *)args->trans, | 193 | (void *)args->dp, (void *)args->trans, |
| 193 | (void *)(unsigned long)args->justcheck, (void *)(long)s, NULL); | 194 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 195 | (void *)(long)s, NULL); | ||
| 194 | } | 196 | } |
| 195 | 197 | ||
| 196 | void | 198 | void |
| @@ -208,7 +210,7 @@ xfs_dir2_trace_args_sb( | |||
| 208 | (void *)((unsigned long)(args->inumber >> 32)), | 210 | (void *)((unsigned long)(args->inumber >> 32)), |
| 209 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), | 211 | (void *)((unsigned long)(args->inumber & 0xFFFFFFFF)), |
| 210 | (void *)args->dp, (void *)args->trans, | 212 | (void *)args->dp, (void *)args->trans, |
| 211 | (void *)(unsigned long)args->justcheck, (void *)(long)s, | 213 | (void *)(unsigned long)(args->op_flags & XFS_DA_OP_JUSTCHECK), |
| 212 | (void *)dbp); | 214 | (void *)(long)s, (void *)dbp); |
| 213 | } | 215 | } |
| 214 | #endif /* XFS_DIR2_TRACE */ | 216 | #endif /* XFS_DIR2_TRACE */ |
diff --git a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h index f71784ab6a60..2813cdd72375 100644 --- a/fs/xfs/xfs_dmapi.h +++ b/fs/xfs/xfs_dmapi.h | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | #ifndef __XFS_DMAPI_H__ | 18 | #ifndef __XFS_DMAPI_H__ |
| 19 | #define __XFS_DMAPI_H__ | 19 | #define __XFS_DMAPI_H__ |
| 20 | 20 | ||
| 21 | #include <linux/version.h> | ||
| 22 | /* Values used to define the on-disk version of dm_attrname_t. All | 21 | /* Values used to define the on-disk version of dm_attrname_t. All |
| 23 | * on-disk attribute names start with the 8-byte string "SGI_DMI_". | 22 | * on-disk attribute names start with the 8-byte string "SGI_DMI_". |
| 24 | * | 23 | * |
| @@ -166,6 +165,6 @@ typedef enum { | |||
| 166 | 165 | ||
| 167 | #define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \ | 166 | #define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \ |
| 168 | DM_FLAGS_NDELAY : 0) | 167 | DM_FLAGS_NDELAY : 0) |
| 169 | #define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) | 168 | #define AT_DELAY_FLAG(f) ((f & XFS_ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) |
| 170 | 169 | ||
| 171 | #endif /* __XFS_DMAPI_H__ */ | 170 | #endif /* __XFS_DMAPI_H__ */ |
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index 05e5365d3c31..f227ecd1a294 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c | |||
| @@ -58,22 +58,11 @@ xfs_error_trap(int e) | |||
| 58 | } | 58 | } |
| 59 | return e; | 59 | return e; |
| 60 | } | 60 | } |
| 61 | #endif | ||
| 62 | |||
| 63 | #if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) | ||
| 64 | 61 | ||
| 65 | int xfs_etest[XFS_NUM_INJECT_ERROR]; | 62 | int xfs_etest[XFS_NUM_INJECT_ERROR]; |
| 66 | int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; | 63 | int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; |
| 67 | char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; | 64 | char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; |
| 68 | 65 | ||
| 69 | void | ||
| 70 | xfs_error_test_init(void) | ||
| 71 | { | ||
| 72 | memset(xfs_etest, 0, sizeof(xfs_etest)); | ||
| 73 | memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid)); | ||
| 74 | memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname)); | ||
| 75 | } | ||
| 76 | |||
| 77 | int | 66 | int |
| 78 | xfs_error_test(int error_tag, int *fsidp, char *expression, | 67 | xfs_error_test(int error_tag, int *fsidp, char *expression, |
| 79 | int line, char *file, unsigned long randfactor) | 68 | int line, char *file, unsigned long randfactor) |
| @@ -150,8 +139,7 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud) | |||
| 150 | xfs_etest[i]); | 139 | xfs_etest[i]); |
| 151 | xfs_etest[i] = 0; | 140 | xfs_etest[i] = 0; |
| 152 | xfs_etest_fsid[i] = 0LL; | 141 | xfs_etest_fsid[i] = 0LL; |
| 153 | kmem_free(xfs_etest_fsname[i], | 142 | kmem_free(xfs_etest_fsname[i]); |
| 154 | strlen(xfs_etest_fsname[i]) + 1); | ||
| 155 | xfs_etest_fsname[i] = NULL; | 143 | xfs_etest_fsname[i] = NULL; |
| 156 | } | 144 | } |
| 157 | } | 145 | } |
| @@ -163,7 +151,7 @@ xfs_errortag_clearall(xfs_mount_t *mp, int loud) | |||
| 163 | 151 | ||
| 164 | return 0; | 152 | return 0; |
| 165 | } | 153 | } |
| 166 | #endif /* DEBUG || INDUCE_IO_ERROR */ | 154 | #endif /* DEBUG */ |
| 167 | 155 | ||
| 168 | static void | 156 | static void |
| 169 | xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap) | 157 | xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap) |
| @@ -175,7 +163,7 @@ xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap) | |||
| 175 | newfmt = kmem_alloc(len, KM_SLEEP); | 163 | newfmt = kmem_alloc(len, KM_SLEEP); |
| 176 | sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); | 164 | sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); |
| 177 | icmn_err(level, newfmt, ap); | 165 | icmn_err(level, newfmt, ap); |
| 178 | kmem_free(newfmt, len); | 166 | kmem_free(newfmt); |
| 179 | } else { | 167 | } else { |
| 180 | icmn_err(level, fmt, ap); | 168 | icmn_err(level, fmt, ap); |
| 181 | } | 169 | } |
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 6490d2a9f8e1..11543f10b0c6 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h | |||
| @@ -125,23 +125,14 @@ extern void xfs_corruption_error(char *tag, int level, struct xfs_mount *mp, | |||
| 125 | #define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) | 125 | #define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) |
| 126 | #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT | 126 | #define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT |
| 127 | 127 | ||
| 128 | #if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) | 128 | #ifdef DEBUG |
| 129 | extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); | 129 | extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); |
| 130 | extern void xfs_error_test_init(void); | ||
| 131 | 130 | ||
| 132 | #define XFS_NUM_INJECT_ERROR 10 | 131 | #define XFS_NUM_INJECT_ERROR 10 |
| 133 | |||
| 134 | #ifdef __ANSI_CPP__ | ||
| 135 | #define XFS_TEST_ERROR(expr, mp, tag, rf) \ | ||
| 136 | ((expr) || \ | ||
| 137 | xfs_error_test((tag), (mp)->m_fixedfsid, #expr, __LINE__, __FILE__, \ | ||
| 138 | (rf))) | ||
| 139 | #else | ||
| 140 | #define XFS_TEST_ERROR(expr, mp, tag, rf) \ | 132 | #define XFS_TEST_ERROR(expr, mp, tag, rf) \ |
| 141 | ((expr) || \ | 133 | ((expr) || \ |
| 142 | xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \ | 134 | xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \ |
| 143 | (rf))) | 135 | (rf))) |
| 144 | #endif /* __ANSI_CPP__ */ | ||
| 145 | 136 | ||
| 146 | extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp); | 137 | extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp); |
| 147 | extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud); | 138 | extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud); |
| @@ -149,7 +140,7 @@ extern int xfs_errortag_clearall(xfs_mount_t *mp, int loud); | |||
| 149 | #define XFS_TEST_ERROR(expr, mp, tag, rf) (expr) | 140 | #define XFS_TEST_ERROR(expr, mp, tag, rf) (expr) |
| 150 | #define xfs_errortag_add(tag, mp) (ENOSYS) | 141 | #define xfs_errortag_add(tag, mp) (ENOSYS) |
| 151 | #define xfs_errortag_clearall(mp, loud) (ENOSYS) | 142 | #define xfs_errortag_clearall(mp, loud) (ENOSYS) |
| 152 | #endif /* (DEBUG || INDUCE_IO_ERROR) */ | 143 | #endif /* DEBUG */ |
| 153 | 144 | ||
| 154 | /* | 145 | /* |
| 155 | * XFS panic tags -- allow a call to xfs_cmn_err() be turned into | 146 | * XFS panic tags -- allow a call to xfs_cmn_err() be turned into |
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 132bd07b9bb8..8aa28f751b2a 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c | |||
| @@ -41,8 +41,7 @@ xfs_efi_item_free(xfs_efi_log_item_t *efip) | |||
| 41 | int nexts = efip->efi_format.efi_nextents; | 41 | int nexts = efip->efi_format.efi_nextents; |
| 42 | 42 | ||
| 43 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { | 43 | if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { |
| 44 | kmem_free(efip, sizeof(xfs_efi_log_item_t) + | 44 | kmem_free(efip); |
| 45 | (nexts - 1) * sizeof(xfs_extent_t)); | ||
| 46 | } else { | 45 | } else { |
| 47 | kmem_zone_free(xfs_efi_zone, efip); | 46 | kmem_zone_free(xfs_efi_zone, efip); |
| 48 | } | 47 | } |
| @@ -374,8 +373,7 @@ xfs_efd_item_free(xfs_efd_log_item_t *efdp) | |||
| 374 | int nexts = efdp->efd_format.efd_nextents; | 373 | int nexts = efdp->efd_format.efd_nextents; |
| 375 | 374 | ||
| 376 | if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { | 375 | if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { |
| 377 | kmem_free(efdp, sizeof(xfs_efd_log_item_t) + | 376 | kmem_free(efdp); |
| 378 | (nexts - 1) * sizeof(xfs_extent_t)); | ||
| 379 | } else { | 377 | } else { |
| 380 | kmem_zone_free(xfs_efd_zone, efdp); | 378 | kmem_zone_free(xfs_efd_zone, efdp); |
| 381 | } | 379 | } |
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c index 3f3785b10804..f3bb75da384e 100644 --- a/fs/xfs/xfs_filestream.c +++ b/fs/xfs/xfs_filestream.c | |||
| @@ -397,10 +397,12 @@ int | |||
| 397 | xfs_filestream_init(void) | 397 | xfs_filestream_init(void) |
| 398 | { | 398 | { |
| 399 | item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item"); | 399 | item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item"); |
| 400 | if (!item_zone) | ||
| 401 | return -ENOMEM; | ||
| 400 | #ifdef XFS_FILESTREAMS_TRACE | 402 | #ifdef XFS_FILESTREAMS_TRACE |
| 401 | xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_SLEEP); | 403 | xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_NOFS); |
| 402 | #endif | 404 | #endif |
| 403 | return item_zone ? 0 : -ENOMEM; | 405 | return 0; |
| 404 | } | 406 | } |
| 405 | 407 | ||
| 406 | /* | 408 | /* |
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index 3bed6433d050..01c0cc88d3f3 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h | |||
| @@ -239,6 +239,7 @@ typedef struct xfs_fsop_resblks { | |||
| 239 | #define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ | 239 | #define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ |
| 240 | #define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ | 240 | #define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ |
| 241 | #define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ | 241 | #define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ |
| 242 | #define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ | ||
| 242 | #define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ | 243 | #define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ |
| 243 | 244 | ||
| 244 | 245 | ||
| @@ -371,6 +372,9 @@ typedef struct xfs_fsop_attrlist_handlereq { | |||
| 371 | 372 | ||
| 372 | typedef struct xfs_attr_multiop { | 373 | typedef struct xfs_attr_multiop { |
| 373 | __u32 am_opcode; | 374 | __u32 am_opcode; |
| 375 | #define ATTR_OP_GET 1 /* return the indicated attr's value */ | ||
| 376 | #define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ | ||
| 377 | #define ATTR_OP_REMOVE 3 /* remove the indicated attr */ | ||
| 374 | __s32 am_error; | 378 | __s32 am_error; |
| 375 | void __user *am_attrname; | 379 | void __user *am_attrname; |
| 376 | void __user *am_attrvalue; | 380 | void __user *am_attrvalue; |
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 381ebda4f7bc..84583cf73db3 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c | |||
| @@ -95,6 +95,8 @@ xfs_fs_geometry( | |||
| 95 | XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) | | 95 | XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) | |
| 96 | (xfs_sb_version_hassector(&mp->m_sb) ? | 96 | (xfs_sb_version_hassector(&mp->m_sb) ? |
| 97 | XFS_FSOP_GEOM_FLAGS_SECTOR : 0) | | 97 | XFS_FSOP_GEOM_FLAGS_SECTOR : 0) | |
| 98 | (xfs_sb_version_hasasciici(&mp->m_sb) ? | ||
| 99 | XFS_FSOP_GEOM_FLAGS_DIRV2CI : 0) | | ||
| 98 | (xfs_sb_version_haslazysbcount(&mp->m_sb) ? | 100 | (xfs_sb_version_haslazysbcount(&mp->m_sb) ? |
| 99 | XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) | | 101 | XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) | |
| 100 | (xfs_sb_version_hasattr2(&mp->m_sb) ? | 102 | (xfs_sb_version_hasattr2(&mp->m_sb) ? |
| @@ -625,7 +627,7 @@ xfs_fs_goingdown( | |||
| 625 | xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); | 627 | xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); |
| 626 | thaw_bdev(sb->s_bdev, sb); | 628 | thaw_bdev(sb->s_bdev, sb); |
| 627 | } | 629 | } |
| 628 | 630 | ||
| 629 | break; | 631 | break; |
| 630 | } | 632 | } |
| 631 | case XFS_FSOP_GOING_FLAGS_LOGFLUSH: | 633 | case XFS_FSOP_GOING_FLAGS_LOGFLUSH: |
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index e5310c90e50f..83502f3edef0 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c | |||
| @@ -181,7 +181,7 @@ xfs_inobt_delrec( | |||
| 181 | * then we can get rid of this level. | 181 | * then we can get rid of this level. |
| 182 | */ | 182 | */ |
| 183 | if (numrecs == 1 && level > 0) { | 183 | if (numrecs == 1 && level > 0) { |
| 184 | agbp = cur->bc_private.i.agbp; | 184 | agbp = cur->bc_private.a.agbp; |
| 185 | agi = XFS_BUF_TO_AGI(agbp); | 185 | agi = XFS_BUF_TO_AGI(agbp); |
| 186 | /* | 186 | /* |
| 187 | * pp is still set to the first pointer in the block. | 187 | * pp is still set to the first pointer in the block. |
| @@ -194,7 +194,7 @@ xfs_inobt_delrec( | |||
| 194 | * Free the block. | 194 | * Free the block. |
| 195 | */ | 195 | */ |
| 196 | if ((error = xfs_free_extent(cur->bc_tp, | 196 | if ((error = xfs_free_extent(cur->bc_tp, |
| 197 | XFS_AGB_TO_FSB(mp, cur->bc_private.i.agno, bno), 1))) | 197 | XFS_AGB_TO_FSB(mp, cur->bc_private.a.agno, bno), 1))) |
| 198 | return error; | 198 | return error; |
| 199 | xfs_trans_binval(cur->bc_tp, bp); | 199 | xfs_trans_binval(cur->bc_tp, bp); |
| 200 | xfs_ialloc_log_agi(cur->bc_tp, agbp, | 200 | xfs_ialloc_log_agi(cur->bc_tp, agbp, |
| @@ -379,7 +379,7 @@ xfs_inobt_delrec( | |||
| 379 | rrecs = be16_to_cpu(right->bb_numrecs); | 379 | rrecs = be16_to_cpu(right->bb_numrecs); |
| 380 | rbp = bp; | 380 | rbp = bp; |
| 381 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, | 381 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, |
| 382 | cur->bc_private.i.agno, lbno, 0, &lbp, | 382 | cur->bc_private.a.agno, lbno, 0, &lbp, |
| 383 | XFS_INO_BTREE_REF))) | 383 | XFS_INO_BTREE_REF))) |
| 384 | return error; | 384 | return error; |
| 385 | left = XFS_BUF_TO_INOBT_BLOCK(lbp); | 385 | left = XFS_BUF_TO_INOBT_BLOCK(lbp); |
| @@ -401,7 +401,7 @@ xfs_inobt_delrec( | |||
| 401 | lrecs = be16_to_cpu(left->bb_numrecs); | 401 | lrecs = be16_to_cpu(left->bb_numrecs); |
| 402 | lbp = bp; | 402 | lbp = bp; |
| 403 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, | 403 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, |
| 404 | cur->bc_private.i.agno, rbno, 0, &rbp, | 404 | cur->bc_private.a.agno, rbno, 0, &rbp, |
| 405 | XFS_INO_BTREE_REF))) | 405 | XFS_INO_BTREE_REF))) |
| 406 | return error; | 406 | return error; |
| 407 | right = XFS_BUF_TO_INOBT_BLOCK(rbp); | 407 | right = XFS_BUF_TO_INOBT_BLOCK(rbp); |
| @@ -484,7 +484,7 @@ xfs_inobt_delrec( | |||
| 484 | xfs_buf_t *rrbp; | 484 | xfs_buf_t *rrbp; |
| 485 | 485 | ||
| 486 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, | 486 | if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, |
| 487 | cur->bc_private.i.agno, be32_to_cpu(left->bb_rightsib), 0, | 487 | cur->bc_private.a.agno, be32_to_cpu(left->bb_rightsib), 0, |
| 488 | &rrbp, XFS_INO_BTREE_REF))) | 488 | &rrbp, XFS_INO_BTREE_REF))) |
| 489 | return error; | 489 | return error; |
| 490 | rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); | 490 | rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); |
| @@ -497,7 +497,7 @@ xfs_inobt_delrec( | |||
| 497 | * Free the deleting block. | 497 | * Free the deleting block. |
| 498 | */ | 498 | */ |
| 499 | if ((error = xfs_free_extent(cur->bc_tp, XFS_AGB_TO_FSB(mp, | 499 | if ((error = xfs_free_extent(cur->bc_tp, XFS_AGB_TO_FSB(mp, |
| 500 | cur->bc_private.i.agno, rbno), 1))) | 500 | cur->bc_private.a.agno, rbno), 1))) |
| 501 | return error; | 501 | return error; |
| 502 | xfs_trans_binval(cur->bc_tp, rbp); | 502 | xfs_trans_binval(cur->bc_tp, rbp); |
| 503 | /* | 503 | /* |
| @@ -854,7 +854,7 @@ xfs_inobt_lookup( | |||
| 854 | { | 854 | { |
| 855 | xfs_agi_t *agi; /* a.g. inode header */ | 855 | xfs_agi_t *agi; /* a.g. inode header */ |
| 856 | 856 | ||
| 857 | agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); | 857 | agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); |
| 858 | agno = be32_to_cpu(agi->agi_seqno); | 858 | agno = be32_to_cpu(agi->agi_seqno); |
| 859 | agbno = be32_to_cpu(agi->agi_root); | 859 | agbno = be32_to_cpu(agi->agi_root); |
| 860 | } | 860 | } |
| @@ -1089,7 +1089,7 @@ xfs_inobt_lshift( | |||
| 1089 | * Set up the left neighbor as "left". | 1089 | * Set up the left neighbor as "left". |
| 1090 | */ | 1090 | */ |
| 1091 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, | 1091 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, |
| 1092 | cur->bc_private.i.agno, be32_to_cpu(right->bb_leftsib), | 1092 | cur->bc_private.a.agno, be32_to_cpu(right->bb_leftsib), |
| 1093 | 0, &lbp, XFS_INO_BTREE_REF))) | 1093 | 0, &lbp, XFS_INO_BTREE_REF))) |
| 1094 | return error; | 1094 | return error; |
| 1095 | left = XFS_BUF_TO_INOBT_BLOCK(lbp); | 1095 | left = XFS_BUF_TO_INOBT_BLOCK(lbp); |
| @@ -1207,10 +1207,10 @@ xfs_inobt_newroot( | |||
| 1207 | /* | 1207 | /* |
| 1208 | * Get a block & a buffer. | 1208 | * Get a block & a buffer. |
| 1209 | */ | 1209 | */ |
| 1210 | agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); | 1210 | agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); |
| 1211 | args.tp = cur->bc_tp; | 1211 | args.tp = cur->bc_tp; |
| 1212 | args.mp = cur->bc_mp; | 1212 | args.mp = cur->bc_mp; |
| 1213 | args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, | 1213 | args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, |
| 1214 | be32_to_cpu(agi->agi_root)); | 1214 | be32_to_cpu(agi->agi_root)); |
| 1215 | args.mod = args.minleft = args.alignment = args.total = args.wasdel = | 1215 | args.mod = args.minleft = args.alignment = args.total = args.wasdel = |
| 1216 | args.isfl = args.userdata = args.minalignslop = 0; | 1216 | args.isfl = args.userdata = args.minalignslop = 0; |
| @@ -1233,7 +1233,7 @@ xfs_inobt_newroot( | |||
| 1233 | */ | 1233 | */ |
| 1234 | agi->agi_root = cpu_to_be32(args.agbno); | 1234 | agi->agi_root = cpu_to_be32(args.agbno); |
| 1235 | be32_add_cpu(&agi->agi_level, 1); | 1235 | be32_add_cpu(&agi->agi_level, 1); |
| 1236 | xfs_ialloc_log_agi(args.tp, cur->bc_private.i.agbp, | 1236 | xfs_ialloc_log_agi(args.tp, cur->bc_private.a.agbp, |
| 1237 | XFS_AGI_ROOT | XFS_AGI_LEVEL); | 1237 | XFS_AGI_ROOT | XFS_AGI_LEVEL); |
| 1238 | /* | 1238 | /* |
| 1239 | * At the previous root level there are now two blocks: the old | 1239 | * At the previous root level there are now two blocks: the old |
| @@ -1376,7 +1376,7 @@ xfs_inobt_rshift( | |||
| 1376 | * Set up the right neighbor as "right". | 1376 | * Set up the right neighbor as "right". |
| 1377 | */ | 1377 | */ |
| 1378 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, | 1378 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, |
| 1379 | cur->bc_private.i.agno, be32_to_cpu(left->bb_rightsib), | 1379 | cur->bc_private.a.agno, be32_to_cpu(left->bb_rightsib), |
| 1380 | 0, &rbp, XFS_INO_BTREE_REF))) | 1380 | 0, &rbp, XFS_INO_BTREE_REF))) |
| 1381 | return error; | 1381 | return error; |
| 1382 | right = XFS_BUF_TO_INOBT_BLOCK(rbp); | 1382 | right = XFS_BUF_TO_INOBT_BLOCK(rbp); |
| @@ -1492,7 +1492,7 @@ xfs_inobt_split( | |||
| 1492 | * Allocate the new block. | 1492 | * Allocate the new block. |
| 1493 | * If we can't do it, we're toast. Give up. | 1493 | * If we can't do it, we're toast. Give up. |
| 1494 | */ | 1494 | */ |
| 1495 | args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, lbno); | 1495 | args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, lbno); |
| 1496 | args.mod = args.minleft = args.alignment = args.total = args.wasdel = | 1496 | args.mod = args.minleft = args.alignment = args.total = args.wasdel = |
| 1497 | args.isfl = args.userdata = args.minalignslop = 0; | 1497 | args.isfl = args.userdata = args.minalignslop = 0; |
| 1498 | args.minlen = args.maxlen = args.prod = 1; | 1498 | args.minlen = args.maxlen = args.prod = 1; |
| @@ -1725,7 +1725,7 @@ xfs_inobt_decrement( | |||
| 1725 | 1725 | ||
| 1726 | agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur)); | 1726 | agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur)); |
| 1727 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, | 1727 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, |
| 1728 | cur->bc_private.i.agno, agbno, 0, &bp, | 1728 | cur->bc_private.a.agno, agbno, 0, &bp, |
| 1729 | XFS_INO_BTREE_REF))) | 1729 | XFS_INO_BTREE_REF))) |
| 1730 | return error; | 1730 | return error; |
| 1731 | lev--; | 1731 | lev--; |
| @@ -1897,7 +1897,7 @@ xfs_inobt_increment( | |||
| 1897 | 1897 | ||
| 1898 | agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur)); | 1898 | agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur)); |
| 1899 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, | 1899 | if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, |
| 1900 | cur->bc_private.i.agno, agbno, 0, &bp, | 1900 | cur->bc_private.a.agno, agbno, 0, &bp, |
| 1901 | XFS_INO_BTREE_REF))) | 1901 | XFS_INO_BTREE_REF))) |
| 1902 | return error; | 1902 | return error; |
| 1903 | lev--; | 1903 | lev--; |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index b07604b94d9f..e229e9e001c2 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
| @@ -216,7 +216,14 @@ finish_inode: | |||
| 216 | mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); | 216 | mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); |
| 217 | init_waitqueue_head(&ip->i_ipin_wait); | 217 | init_waitqueue_head(&ip->i_ipin_wait); |
| 218 | atomic_set(&ip->i_pincount, 0); | 218 | atomic_set(&ip->i_pincount, 0); |
| 219 | initnsema(&ip->i_flock, 1, "xfsfino"); | 219 | |
| 220 | /* | ||
| 221 | * Because we want to use a counting completion, complete | ||
| 222 | * the flush completion once to allow a single access to | ||
| 223 | * the flush completion without blocking. | ||
| 224 | */ | ||
| 225 | init_completion(&ip->i_flush); | ||
| 226 | complete(&ip->i_flush); | ||
| 220 | 227 | ||
| 221 | if (lock_flags) | 228 | if (lock_flags) |
| 222 | xfs_ilock(ip, lock_flags); | 229 | xfs_ilock(ip, lock_flags); |
| @@ -288,10 +295,17 @@ finish_inode: | |||
| 288 | *ipp = ip; | 295 | *ipp = ip; |
| 289 | 296 | ||
| 290 | /* | 297 | /* |
| 298 | * Set up the Linux with the Linux inode. | ||
| 299 | */ | ||
| 300 | ip->i_vnode = inode; | ||
| 301 | inode->i_private = ip; | ||
| 302 | |||
| 303 | /* | ||
| 291 | * If we have a real type for an on-disk inode, we can set ops(&unlock) | 304 | * If we have a real type for an on-disk inode, we can set ops(&unlock) |
| 292 | * now. If it's a new inode being created, xfs_ialloc will handle it. | 305 | * now. If it's a new inode being created, xfs_ialloc will handle it. |
| 293 | */ | 306 | */ |
| 294 | xfs_initialize_vnode(mp, inode, ip); | 307 | if (ip->i_d.di_mode != 0) |
| 308 | xfs_setup_inode(ip); | ||
| 295 | return 0; | 309 | return 0; |
| 296 | } | 310 | } |
| 297 | 311 | ||
| @@ -411,10 +425,11 @@ xfs_iput(xfs_inode_t *ip, | |||
| 411 | * Special iput for brand-new inodes that are still locked | 425 | * Special iput for brand-new inodes that are still locked |
| 412 | */ | 426 | */ |
| 413 | void | 427 | void |
| 414 | xfs_iput_new(xfs_inode_t *ip, | 428 | xfs_iput_new( |
| 415 | uint lock_flags) | 429 | xfs_inode_t *ip, |
| 430 | uint lock_flags) | ||
| 416 | { | 431 | { |
| 417 | struct inode *inode = ip->i_vnode; | 432 | struct inode *inode = VFS_I(ip); |
| 418 | 433 | ||
| 419 | xfs_itrace_entry(ip); | 434 | xfs_itrace_entry(ip); |
| 420 | 435 | ||
| @@ -775,26 +790,3 @@ xfs_isilocked( | |||
| 775 | } | 790 | } |
| 776 | #endif | 791 | #endif |
| 777 | 792 | ||
| 778 | /* | ||
| 779 | * The following three routines simply manage the i_flock | ||
| 780 | * semaphore embedded in the inode. This semaphore synchronizes | ||
| 781 | * processes attempting to flush the in-core inode back to disk. | ||
| 782 | */ | ||
| 783 | void | ||
| 784 | xfs_iflock(xfs_inode_t *ip) | ||
| 785 | { | ||
| 786 | psema(&(ip->i_flock), PINOD|PLTWAIT); | ||
| 787 | } | ||
| 788 | |||
| 789 | int | ||
| 790 | xfs_iflock_nowait(xfs_inode_t *ip) | ||
| 791 | { | ||
| 792 | return (cpsema(&(ip->i_flock))); | ||
| 793 | } | ||
| 794 | |||
| 795 | void | ||
| 796 | xfs_ifunlock(xfs_inode_t *ip) | ||
| 797 | { | ||
| 798 | ASSERT(issemalocked(&(ip->i_flock))); | ||
| 799 | vsema(&(ip->i_flock)); | ||
| 800 | } | ||
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index e569bf5d6cf0..00e80df9dd9d 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -580,8 +580,8 @@ xfs_iformat_extents( | |||
| 580 | xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); | 580 | xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); |
| 581 | for (i = 0; i < nex; i++, dp++) { | 581 | for (i = 0; i < nex; i++, dp++) { |
| 582 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); | 582 | xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); |
| 583 | ep->l0 = be64_to_cpu(get_unaligned(&dp->l0)); | 583 | ep->l0 = get_unaligned_be64(&dp->l0); |
| 584 | ep->l1 = be64_to_cpu(get_unaligned(&dp->l1)); | 584 | ep->l1 = get_unaligned_be64(&dp->l1); |
| 585 | } | 585 | } |
| 586 | XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); | 586 | XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); |
| 587 | if (whichfork != XFS_DATA_FORK || | 587 | if (whichfork != XFS_DATA_FORK || |
| @@ -835,22 +835,22 @@ xfs_iread( | |||
| 835 | * Do this before xfs_iformat in case it adds entries. | 835 | * Do this before xfs_iformat in case it adds entries. |
| 836 | */ | 836 | */ |
| 837 | #ifdef XFS_INODE_TRACE | 837 | #ifdef XFS_INODE_TRACE |
| 838 | ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_SLEEP); | 838 | ip->i_trace = ktrace_alloc(INODE_TRACE_SIZE, KM_NOFS); |
| 839 | #endif | 839 | #endif |
| 840 | #ifdef XFS_BMAP_TRACE | 840 | #ifdef XFS_BMAP_TRACE |
| 841 | ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_SLEEP); | 841 | ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, KM_NOFS); |
| 842 | #endif | 842 | #endif |
| 843 | #ifdef XFS_BMBT_TRACE | 843 | #ifdef XFS_BMBT_TRACE |
| 844 | ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_SLEEP); | 844 | ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, KM_NOFS); |
| 845 | #endif | 845 | #endif |
| 846 | #ifdef XFS_RW_TRACE | 846 | #ifdef XFS_RW_TRACE |
| 847 | ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_SLEEP); | 847 | ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, KM_NOFS); |
| 848 | #endif | 848 | #endif |
| 849 | #ifdef XFS_ILOCK_TRACE | 849 | #ifdef XFS_ILOCK_TRACE |
| 850 | ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_SLEEP); | 850 | ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, KM_NOFS); |
| 851 | #endif | 851 | #endif |
| 852 | #ifdef XFS_DIR2_TRACE | 852 | #ifdef XFS_DIR2_TRACE |
| 853 | ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_SLEEP); | 853 | ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); |
| 854 | #endif | 854 | #endif |
| 855 | 855 | ||
| 856 | /* | 856 | /* |
| @@ -1046,9 +1046,9 @@ xfs_ialloc( | |||
| 1046 | { | 1046 | { |
| 1047 | xfs_ino_t ino; | 1047 | xfs_ino_t ino; |
| 1048 | xfs_inode_t *ip; | 1048 | xfs_inode_t *ip; |
| 1049 | bhv_vnode_t *vp; | ||
| 1050 | uint flags; | 1049 | uint flags; |
| 1051 | int error; | 1050 | int error; |
| 1051 | timespec_t tv; | ||
| 1052 | 1052 | ||
| 1053 | /* | 1053 | /* |
| 1054 | * Call the space management code to pick | 1054 | * Call the space management code to pick |
| @@ -1077,13 +1077,12 @@ xfs_ialloc( | |||
| 1077 | } | 1077 | } |
| 1078 | ASSERT(ip != NULL); | 1078 | ASSERT(ip != NULL); |
| 1079 | 1079 | ||
| 1080 | vp = XFS_ITOV(ip); | ||
| 1081 | ip->i_d.di_mode = (__uint16_t)mode; | 1080 | ip->i_d.di_mode = (__uint16_t)mode; |
| 1082 | ip->i_d.di_onlink = 0; | 1081 | ip->i_d.di_onlink = 0; |
| 1083 | ip->i_d.di_nlink = nlink; | 1082 | ip->i_d.di_nlink = nlink; |
| 1084 | ASSERT(ip->i_d.di_nlink == nlink); | 1083 | ASSERT(ip->i_d.di_nlink == nlink); |
| 1085 | ip->i_d.di_uid = current_fsuid(cr); | 1084 | ip->i_d.di_uid = current_fsuid(); |
| 1086 | ip->i_d.di_gid = current_fsgid(cr); | 1085 | ip->i_d.di_gid = current_fsgid(); |
| 1087 | ip->i_d.di_projid = prid; | 1086 | ip->i_d.di_projid = prid; |
| 1088 | memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); | 1087 | memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); |
| 1089 | 1088 | ||
| @@ -1130,7 +1129,13 @@ xfs_ialloc( | |||
| 1130 | ip->i_size = 0; | 1129 | ip->i_size = 0; |
| 1131 | ip->i_d.di_nextents = 0; | 1130 | ip->i_d.di_nextents = 0; |
| 1132 | ASSERT(ip->i_d.di_nblocks == 0); | 1131 | ASSERT(ip->i_d.di_nblocks == 0); |
| 1133 | xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD); | 1132 | |
| 1133 | nanotime(&tv); | ||
| 1134 | ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; | ||
| 1135 | ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; | ||
| 1136 | ip->i_d.di_atime = ip->i_d.di_mtime; | ||
| 1137 | ip->i_d.di_ctime = ip->i_d.di_mtime; | ||
| 1138 | |||
| 1134 | /* | 1139 | /* |
| 1135 | * di_gen will have been taken care of in xfs_iread. | 1140 | * di_gen will have been taken care of in xfs_iread. |
| 1136 | */ | 1141 | */ |
| @@ -1220,7 +1225,7 @@ xfs_ialloc( | |||
| 1220 | xfs_trans_log_inode(tp, ip, flags); | 1225 | xfs_trans_log_inode(tp, ip, flags); |
| 1221 | 1226 | ||
| 1222 | /* now that we have an i_mode we can setup inode ops and unlock */ | 1227 | /* now that we have an i_mode we can setup inode ops and unlock */ |
| 1223 | xfs_initialize_vnode(tp->t_mountp, vp, ip); | 1228 | xfs_setup_inode(ip); |
| 1224 | 1229 | ||
| 1225 | *ipp = ip; | 1230 | *ipp = ip; |
| 1226 | return 0; | 1231 | return 0; |
| @@ -1399,7 +1404,6 @@ xfs_itruncate_start( | |||
| 1399 | xfs_fsize_t last_byte; | 1404 | xfs_fsize_t last_byte; |
| 1400 | xfs_off_t toss_start; | 1405 | xfs_off_t toss_start; |
| 1401 | xfs_mount_t *mp; | 1406 | xfs_mount_t *mp; |
| 1402 | bhv_vnode_t *vp; | ||
| 1403 | int error = 0; | 1407 | int error = 0; |
| 1404 | 1408 | ||
| 1405 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); | 1409 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); |
| @@ -1408,7 +1412,6 @@ xfs_itruncate_start( | |||
| 1408 | (flags == XFS_ITRUNC_MAYBE)); | 1412 | (flags == XFS_ITRUNC_MAYBE)); |
| 1409 | 1413 | ||
| 1410 | mp = ip->i_mount; | 1414 | mp = ip->i_mount; |
| 1411 | vp = XFS_ITOV(ip); | ||
| 1412 | 1415 | ||
| 1413 | /* wait for the completion of any pending DIOs */ | 1416 | /* wait for the completion of any pending DIOs */ |
| 1414 | if (new_size < ip->i_size) | 1417 | if (new_size < ip->i_size) |
| @@ -1457,7 +1460,7 @@ xfs_itruncate_start( | |||
| 1457 | 1460 | ||
| 1458 | #ifdef DEBUG | 1461 | #ifdef DEBUG |
| 1459 | if (new_size == 0) { | 1462 | if (new_size == 0) { |
| 1460 | ASSERT(VN_CACHED(vp) == 0); | 1463 | ASSERT(VN_CACHED(VFS_I(ip)) == 0); |
| 1461 | } | 1464 | } |
| 1462 | #endif | 1465 | #endif |
| 1463 | return error; | 1466 | return error; |
| @@ -1763,67 +1766,6 @@ xfs_itruncate_finish( | |||
| 1763 | return 0; | 1766 | return 0; |
| 1764 | } | 1767 | } |
| 1765 | 1768 | ||
| 1766 | |||
| 1767 | /* | ||
| 1768 | * xfs_igrow_start | ||
| 1769 | * | ||
| 1770 | * Do the first part of growing a file: zero any data in the last | ||
| 1771 | * block that is beyond the old EOF. We need to do this before | ||
| 1772 | * the inode is joined to the transaction to modify the i_size. | ||
| 1773 | * That way we can drop the inode lock and call into the buffer | ||
| 1774 | * cache to get the buffer mapping the EOF. | ||
| 1775 | */ | ||
| 1776 | int | ||
| 1777 | xfs_igrow_start( | ||
| 1778 | xfs_inode_t *ip, | ||
| 1779 | xfs_fsize_t new_size, | ||
| 1780 | cred_t *credp) | ||
| 1781 | { | ||
| 1782 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); | ||
| 1783 | ASSERT(new_size > ip->i_size); | ||
| 1784 | |||
| 1785 | /* | ||
| 1786 | * Zero any pages that may have been created by | ||
| 1787 | * xfs_write_file() beyond the end of the file | ||
| 1788 | * and any blocks between the old and new file sizes. | ||
| 1789 | */ | ||
| 1790 | return xfs_zero_eof(ip, new_size, ip->i_size); | ||
| 1791 | } | ||
| 1792 | |||
| 1793 | /* | ||
| 1794 | * xfs_igrow_finish | ||
| 1795 | * | ||
| 1796 | * This routine is called to extend the size of a file. | ||
| 1797 | * The inode must have both the iolock and the ilock locked | ||
| 1798 | * for update and it must be a part of the current transaction. | ||
| 1799 | * The xfs_igrow_start() function must have been called previously. | ||
| 1800 | * If the change_flag is not zero, the inode change timestamp will | ||
| 1801 | * be updated. | ||
| 1802 | */ | ||
| 1803 | void | ||
| 1804 | xfs_igrow_finish( | ||
| 1805 | xfs_trans_t *tp, | ||
| 1806 | xfs_inode_t *ip, | ||
| 1807 | xfs_fsize_t new_size, | ||
| 1808 | int change_flag) | ||
| 1809 | { | ||
| 1810 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL)); | ||
| 1811 | ASSERT(ip->i_transp == tp); | ||
| 1812 | ASSERT(new_size > ip->i_size); | ||
| 1813 | |||
| 1814 | /* | ||
| 1815 | * Update the file size. Update the inode change timestamp | ||
| 1816 | * if change_flag set. | ||
| 1817 | */ | ||
| 1818 | ip->i_d.di_size = new_size; | ||
| 1819 | ip->i_size = new_size; | ||
| 1820 | if (change_flag) | ||
| 1821 | xfs_ichgtime(ip, XFS_ICHGTIME_CHG); | ||
| 1822 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 1823 | |||
| 1824 | } | ||
| 1825 | |||
| 1826 | |||
| 1827 | /* | 1769 | /* |
| 1828 | * This is called when the inode's link count goes to 0. | 1770 | * This is called when the inode's link count goes to 0. |
| 1829 | * We place the on-disk inode on a list in the AGI. It | 1771 | * We place the on-disk inode on a list in the AGI. It |
| @@ -2258,7 +2200,7 @@ xfs_ifree_cluster( | |||
| 2258 | xfs_trans_binval(tp, bp); | 2200 | xfs_trans_binval(tp, bp); |
| 2259 | } | 2201 | } |
| 2260 | 2202 | ||
| 2261 | kmem_free(ip_found, ninodes * sizeof(xfs_inode_t *)); | 2203 | kmem_free(ip_found); |
| 2262 | xfs_put_perag(mp, pag); | 2204 | xfs_put_perag(mp, pag); |
| 2263 | } | 2205 | } |
| 2264 | 2206 | ||
| @@ -2470,7 +2412,7 @@ xfs_iroot_realloc( | |||
| 2470 | (int)new_size); | 2412 | (int)new_size); |
| 2471 | memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t)); | 2413 | memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t)); |
| 2472 | } | 2414 | } |
| 2473 | kmem_free(ifp->if_broot, ifp->if_broot_bytes); | 2415 | kmem_free(ifp->if_broot); |
| 2474 | ifp->if_broot = new_broot; | 2416 | ifp->if_broot = new_broot; |
| 2475 | ifp->if_broot_bytes = (int)new_size; | 2417 | ifp->if_broot_bytes = (int)new_size; |
| 2476 | ASSERT(ifp->if_broot_bytes <= | 2418 | ASSERT(ifp->if_broot_bytes <= |
| @@ -2514,7 +2456,7 @@ xfs_idata_realloc( | |||
| 2514 | 2456 | ||
| 2515 | if (new_size == 0) { | 2457 | if (new_size == 0) { |
| 2516 | if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { | 2458 | if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { |
| 2517 | kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); | 2459 | kmem_free(ifp->if_u1.if_data); |
| 2518 | } | 2460 | } |
| 2519 | ifp->if_u1.if_data = NULL; | 2461 | ifp->if_u1.if_data = NULL; |
| 2520 | real_size = 0; | 2462 | real_size = 0; |
| @@ -2529,7 +2471,7 @@ xfs_idata_realloc( | |||
| 2529 | ASSERT(ifp->if_real_bytes != 0); | 2471 | ASSERT(ifp->if_real_bytes != 0); |
| 2530 | memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, | 2472 | memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, |
| 2531 | new_size); | 2473 | new_size); |
| 2532 | kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); | 2474 | kmem_free(ifp->if_u1.if_data); |
| 2533 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; | 2475 | ifp->if_u1.if_data = ifp->if_u2.if_inline_data; |
| 2534 | } | 2476 | } |
| 2535 | real_size = 0; | 2477 | real_size = 0; |
| @@ -2636,7 +2578,7 @@ xfs_idestroy_fork( | |||
| 2636 | 2578 | ||
| 2637 | ifp = XFS_IFORK_PTR(ip, whichfork); | 2579 | ifp = XFS_IFORK_PTR(ip, whichfork); |
| 2638 | if (ifp->if_broot != NULL) { | 2580 | if (ifp->if_broot != NULL) { |
| 2639 | kmem_free(ifp->if_broot, ifp->if_broot_bytes); | 2581 | kmem_free(ifp->if_broot); |
| 2640 | ifp->if_broot = NULL; | 2582 | ifp->if_broot = NULL; |
| 2641 | } | 2583 | } |
| 2642 | 2584 | ||
| @@ -2650,7 +2592,7 @@ xfs_idestroy_fork( | |||
| 2650 | if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && | 2592 | if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && |
| 2651 | (ifp->if_u1.if_data != NULL)) { | 2593 | (ifp->if_u1.if_data != NULL)) { |
| 2652 | ASSERT(ifp->if_real_bytes != 0); | 2594 | ASSERT(ifp->if_real_bytes != 0); |
| 2653 | kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); | 2595 | kmem_free(ifp->if_u1.if_data); |
| 2654 | ifp->if_u1.if_data = NULL; | 2596 | ifp->if_u1.if_data = NULL; |
| 2655 | ifp->if_real_bytes = 0; | 2597 | ifp->if_real_bytes = 0; |
| 2656 | } | 2598 | } |
| @@ -2691,7 +2633,6 @@ xfs_idestroy( | |||
| 2691 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | 2633 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); |
| 2692 | mrfree(&ip->i_lock); | 2634 | mrfree(&ip->i_lock); |
| 2693 | mrfree(&ip->i_iolock); | 2635 | mrfree(&ip->i_iolock); |
| 2694 | freesema(&ip->i_flock); | ||
| 2695 | 2636 | ||
| 2696 | #ifdef XFS_INODE_TRACE | 2637 | #ifdef XFS_INODE_TRACE |
| 2697 | ktrace_free(ip->i_trace); | 2638 | ktrace_free(ip->i_trace); |
| @@ -3058,7 +2999,7 @@ xfs_iflush_cluster( | |||
| 3058 | 2999 | ||
| 3059 | out_free: | 3000 | out_free: |
| 3060 | read_unlock(&pag->pag_ici_lock); | 3001 | read_unlock(&pag->pag_ici_lock); |
| 3061 | kmem_free(ilist, ilist_size); | 3002 | kmem_free(ilist); |
| 3062 | return 0; | 3003 | return 0; |
| 3063 | 3004 | ||
| 3064 | 3005 | ||
| @@ -3102,17 +3043,17 @@ cluster_corrupt_out: | |||
| 3102 | * Unlocks the flush lock | 3043 | * Unlocks the flush lock |
| 3103 | */ | 3044 | */ |
| 3104 | xfs_iflush_abort(iq); | 3045 | xfs_iflush_abort(iq); |
| 3105 | kmem_free(ilist, ilist_size); | 3046 | kmem_free(ilist); |
| 3106 | return XFS_ERROR(EFSCORRUPTED); | 3047 | return XFS_ERROR(EFSCORRUPTED); |
| 3107 | } | 3048 | } |
| 3108 | 3049 | ||
| 3109 | /* | 3050 | /* |
| 3110 | * xfs_iflush() will write a modified inode's changes out to the | 3051 | * xfs_iflush() will write a modified inode's changes out to the |
| 3111 | * inode's on disk home. The caller must have the inode lock held | 3052 | * inode's on disk home. The caller must have the inode lock held |
| 3112 | * in at least shared mode and the inode flush semaphore must be | 3053 | * in at least shared mode and the inode flush completion must be |
| 3113 | * held as well. The inode lock will still be held upon return from | 3054 | * active as well. The inode lock will still be held upon return from |
| 3114 | * the call and the caller is free to unlock it. | 3055 | * the call and the caller is free to unlock it. |
| 3115 | * The inode flush lock will be unlocked when the inode reaches the disk. | 3056 | * The inode flush will be completed when the inode reaches the disk. |
| 3116 | * The flags indicate how the inode's buffer should be written out. | 3057 | * The flags indicate how the inode's buffer should be written out. |
| 3117 | */ | 3058 | */ |
| 3118 | int | 3059 | int |
| @@ -3131,7 +3072,7 @@ xfs_iflush( | |||
| 3131 | XFS_STATS_INC(xs_iflush_count); | 3072 | XFS_STATS_INC(xs_iflush_count); |
| 3132 | 3073 | ||
| 3133 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); | 3074 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); |
| 3134 | ASSERT(issemalocked(&(ip->i_flock))); | 3075 | ASSERT(!completion_done(&ip->i_flush)); |
| 3135 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || | 3076 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || |
| 3136 | ip->i_d.di_nextents > ip->i_df.if_ext_max); | 3077 | ip->i_d.di_nextents > ip->i_df.if_ext_max); |
| 3137 | 3078 | ||
| @@ -3143,8 +3084,6 @@ xfs_iflush( | |||
| 3143 | * flush lock and do nothing. | 3084 | * flush lock and do nothing. |
| 3144 | */ | 3085 | */ |
| 3145 | if (xfs_inode_clean(ip)) { | 3086 | if (xfs_inode_clean(ip)) { |
| 3146 | ASSERT((iip != NULL) ? | ||
| 3147 | !(iip->ili_item.li_flags & XFS_LI_IN_AIL) : 1); | ||
| 3148 | xfs_ifunlock(ip); | 3087 | xfs_ifunlock(ip); |
| 3149 | return 0; | 3088 | return 0; |
| 3150 | } | 3089 | } |
| @@ -3296,7 +3235,7 @@ xfs_iflush_int( | |||
| 3296 | #endif | 3235 | #endif |
| 3297 | 3236 | ||
| 3298 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); | 3237 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); |
| 3299 | ASSERT(issemalocked(&(ip->i_flock))); | 3238 | ASSERT(!completion_done(&ip->i_flush)); |
| 3300 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || | 3239 | ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || |
| 3301 | ip->i_d.di_nextents > ip->i_df.if_ext_max); | 3240 | ip->i_d.di_nextents > ip->i_df.if_ext_max); |
| 3302 | 3241 | ||
| @@ -3528,7 +3467,6 @@ xfs_iflush_all( | |||
| 3528 | xfs_mount_t *mp) | 3467 | xfs_mount_t *mp) |
| 3529 | { | 3468 | { |
| 3530 | xfs_inode_t *ip; | 3469 | xfs_inode_t *ip; |
| 3531 | bhv_vnode_t *vp; | ||
| 3532 | 3470 | ||
| 3533 | again: | 3471 | again: |
| 3534 | XFS_MOUNT_ILOCK(mp); | 3472 | XFS_MOUNT_ILOCK(mp); |
| @@ -3543,14 +3481,13 @@ xfs_iflush_all( | |||
| 3543 | continue; | 3481 | continue; |
| 3544 | } | 3482 | } |
| 3545 | 3483 | ||
| 3546 | vp = XFS_ITOV_NULL(ip); | 3484 | if (!VFS_I(ip)) { |
| 3547 | if (!vp) { | ||
| 3548 | XFS_MOUNT_IUNLOCK(mp); | 3485 | XFS_MOUNT_IUNLOCK(mp); |
| 3549 | xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); | 3486 | xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC); |
| 3550 | goto again; | 3487 | goto again; |
| 3551 | } | 3488 | } |
| 3552 | 3489 | ||
| 3553 | ASSERT(vn_count(vp) == 0); | 3490 | ASSERT(vn_count(VFS_I(ip)) == 0); |
| 3554 | 3491 | ||
| 3555 | ip = ip->i_mnext; | 3492 | ip = ip->i_mnext; |
| 3556 | } while (ip != mp->m_inodes); | 3493 | } while (ip != mp->m_inodes); |
| @@ -3770,7 +3707,7 @@ xfs_iext_add_indirect_multi( | |||
| 3770 | * (all extents past */ | 3707 | * (all extents past */ |
| 3771 | if (nex2) { | 3708 | if (nex2) { |
| 3772 | byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); | 3709 | byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); |
| 3773 | nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_SLEEP); | 3710 | nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS); |
| 3774 | memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff); | 3711 | memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff); |
| 3775 | erp->er_extcount -= nex2; | 3712 | erp->er_extcount -= nex2; |
| 3776 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2); | 3713 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2); |
| @@ -3836,7 +3773,7 @@ xfs_iext_add_indirect_multi( | |||
| 3836 | erp = xfs_iext_irec_new(ifp, erp_idx); | 3773 | erp = xfs_iext_irec_new(ifp, erp_idx); |
| 3837 | } | 3774 | } |
| 3838 | memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); | 3775 | memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); |
| 3839 | kmem_free(nex2_ep, byte_diff); | 3776 | kmem_free(nex2_ep); |
| 3840 | erp->er_extcount += nex2; | 3777 | erp->er_extcount += nex2; |
| 3841 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); | 3778 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); |
| 3842 | } | 3779 | } |
| @@ -4070,8 +4007,7 @@ xfs_iext_realloc_direct( | |||
| 4070 | ifp->if_u1.if_extents = | 4007 | ifp->if_u1.if_extents = |
| 4071 | kmem_realloc(ifp->if_u1.if_extents, | 4008 | kmem_realloc(ifp->if_u1.if_extents, |
| 4072 | rnew_size, | 4009 | rnew_size, |
| 4073 | ifp->if_real_bytes, | 4010 | ifp->if_real_bytes, KM_NOFS); |
| 4074 | KM_SLEEP); | ||
| 4075 | } | 4011 | } |
| 4076 | if (rnew_size > ifp->if_real_bytes) { | 4012 | if (rnew_size > ifp->if_real_bytes) { |
| 4077 | memset(&ifp->if_u1.if_extents[ifp->if_bytes / | 4013 | memset(&ifp->if_u1.if_extents[ifp->if_bytes / |
| @@ -4112,7 +4048,7 @@ xfs_iext_direct_to_inline( | |||
| 4112 | */ | 4048 | */ |
| 4113 | memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, | 4049 | memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, |
| 4114 | nextents * sizeof(xfs_bmbt_rec_t)); | 4050 | nextents * sizeof(xfs_bmbt_rec_t)); |
| 4115 | kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); | 4051 | kmem_free(ifp->if_u1.if_extents); |
| 4116 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; | 4052 | ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; |
| 4117 | ifp->if_real_bytes = 0; | 4053 | ifp->if_real_bytes = 0; |
| 4118 | } | 4054 | } |
| @@ -4130,7 +4066,7 @@ xfs_iext_inline_to_direct( | |||
| 4130 | xfs_ifork_t *ifp, /* inode fork pointer */ | 4066 | xfs_ifork_t *ifp, /* inode fork pointer */ |
| 4131 | int new_size) /* number of extents in file */ | 4067 | int new_size) /* number of extents in file */ |
| 4132 | { | 4068 | { |
| 4133 | ifp->if_u1.if_extents = kmem_alloc(new_size, KM_SLEEP); | 4069 | ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS); |
| 4134 | memset(ifp->if_u1.if_extents, 0, new_size); | 4070 | memset(ifp->if_u1.if_extents, 0, new_size); |
| 4135 | if (ifp->if_bytes) { | 4071 | if (ifp->if_bytes) { |
| 4136 | memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, | 4072 | memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, |
| @@ -4162,7 +4098,7 @@ xfs_iext_realloc_indirect( | |||
| 4162 | } else { | 4098 | } else { |
| 4163 | ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *) | 4099 | ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *) |
| 4164 | kmem_realloc(ifp->if_u1.if_ext_irec, | 4100 | kmem_realloc(ifp->if_u1.if_ext_irec, |
| 4165 | new_size, size, KM_SLEEP); | 4101 | new_size, size, KM_NOFS); |
| 4166 | } | 4102 | } |
| 4167 | } | 4103 | } |
| 4168 | 4104 | ||
| @@ -4186,7 +4122,7 @@ xfs_iext_indirect_to_direct( | |||
| 4186 | ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); | 4122 | ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); |
| 4187 | 4123 | ||
| 4188 | ep = ifp->if_u1.if_ext_irec->er_extbuf; | 4124 | ep = ifp->if_u1.if_ext_irec->er_extbuf; |
| 4189 | kmem_free(ifp->if_u1.if_ext_irec, sizeof(xfs_ext_irec_t)); | 4125 | kmem_free(ifp->if_u1.if_ext_irec); |
| 4190 | ifp->if_flags &= ~XFS_IFEXTIREC; | 4126 | ifp->if_flags &= ~XFS_IFEXTIREC; |
| 4191 | ifp->if_u1.if_extents = ep; | 4127 | ifp->if_u1.if_extents = ep; |
| 4192 | ifp->if_bytes = size; | 4128 | ifp->if_bytes = size; |
| @@ -4212,7 +4148,7 @@ xfs_iext_destroy( | |||
| 4212 | } | 4148 | } |
| 4213 | ifp->if_flags &= ~XFS_IFEXTIREC; | 4149 | ifp->if_flags &= ~XFS_IFEXTIREC; |
| 4214 | } else if (ifp->if_real_bytes) { | 4150 | } else if (ifp->if_real_bytes) { |
| 4215 | kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); | 4151 | kmem_free(ifp->if_u1.if_extents); |
| 4216 | } else if (ifp->if_bytes) { | 4152 | } else if (ifp->if_bytes) { |
| 4217 | memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * | 4153 | memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * |
| 4218 | sizeof(xfs_bmbt_rec_t)); | 4154 | sizeof(xfs_bmbt_rec_t)); |
| @@ -4404,11 +4340,10 @@ xfs_iext_irec_init( | |||
| 4404 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); | 4340 | nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); |
| 4405 | ASSERT(nextents <= XFS_LINEAR_EXTS); | 4341 | ASSERT(nextents <= XFS_LINEAR_EXTS); |
| 4406 | 4342 | ||
| 4407 | erp = (xfs_ext_irec_t *) | 4343 | erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS); |
| 4408 | kmem_alloc(sizeof(xfs_ext_irec_t), KM_SLEEP); | ||
| 4409 | 4344 | ||
| 4410 | if (nextents == 0) { | 4345 | if (nextents == 0) { |
| 4411 | ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP); | 4346 | ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); |
| 4412 | } else if (!ifp->if_real_bytes) { | 4347 | } else if (!ifp->if_real_bytes) { |
| 4413 | xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); | 4348 | xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); |
| 4414 | } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { | 4349 | } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { |
| @@ -4456,7 +4391,7 @@ xfs_iext_irec_new( | |||
| 4456 | 4391 | ||
| 4457 | /* Initialize new extent record */ | 4392 | /* Initialize new extent record */ |
| 4458 | erp = ifp->if_u1.if_ext_irec; | 4393 | erp = ifp->if_u1.if_ext_irec; |
| 4459 | erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_SLEEP); | 4394 | erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); |
| 4460 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; | 4395 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; |
| 4461 | memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); | 4396 | memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); |
| 4462 | erp[erp_idx].er_extcount = 0; | 4397 | erp[erp_idx].er_extcount = 0; |
| @@ -4483,7 +4418,7 @@ xfs_iext_irec_remove( | |||
| 4483 | if (erp->er_extbuf) { | 4418 | if (erp->er_extbuf) { |
| 4484 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, | 4419 | xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, |
| 4485 | -erp->er_extcount); | 4420 | -erp->er_extcount); |
| 4486 | kmem_free(erp->er_extbuf, XFS_IEXT_BUFSZ); | 4421 | kmem_free(erp->er_extbuf); |
| 4487 | } | 4422 | } |
| 4488 | /* Compact extent records */ | 4423 | /* Compact extent records */ |
| 4489 | erp = ifp->if_u1.if_ext_irec; | 4424 | erp = ifp->if_u1.if_ext_irec; |
| @@ -4501,8 +4436,7 @@ xfs_iext_irec_remove( | |||
| 4501 | xfs_iext_realloc_indirect(ifp, | 4436 | xfs_iext_realloc_indirect(ifp, |
| 4502 | nlists * sizeof(xfs_ext_irec_t)); | 4437 | nlists * sizeof(xfs_ext_irec_t)); |
| 4503 | } else { | 4438 | } else { |
| 4504 | kmem_free(ifp->if_u1.if_ext_irec, | 4439 | kmem_free(ifp->if_u1.if_ext_irec); |
| 4505 | sizeof(xfs_ext_irec_t)); | ||
| 4506 | } | 4440 | } |
| 4507 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; | 4441 | ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; |
| 4508 | } | 4442 | } |
| @@ -4571,7 +4505,7 @@ xfs_iext_irec_compact_pages( | |||
| 4571 | * so er_extoffs don't get modified in | 4505 | * so er_extoffs don't get modified in |
| 4572 | * xfs_iext_irec_remove. | 4506 | * xfs_iext_irec_remove. |
| 4573 | */ | 4507 | */ |
| 4574 | kmem_free(erp_next->er_extbuf, XFS_IEXT_BUFSZ); | 4508 | kmem_free(erp_next->er_extbuf); |
| 4575 | erp_next->er_extbuf = NULL; | 4509 | erp_next->er_extbuf = NULL; |
| 4576 | xfs_iext_irec_remove(ifp, erp_idx + 1); | 4510 | xfs_iext_irec_remove(ifp, erp_idx + 1); |
| 4577 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 4511 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
| @@ -4596,40 +4530,63 @@ xfs_iext_irec_compact_full( | |||
| 4596 | int nlists; /* number of irec's (ex lists) */ | 4530 | int nlists; /* number of irec's (ex lists) */ |
| 4597 | 4531 | ||
| 4598 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); | 4532 | ASSERT(ifp->if_flags & XFS_IFEXTIREC); |
| 4533 | |||
| 4599 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 4534 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; |
| 4600 | erp = ifp->if_u1.if_ext_irec; | 4535 | erp = ifp->if_u1.if_ext_irec; |
| 4601 | ep = &erp->er_extbuf[erp->er_extcount]; | 4536 | ep = &erp->er_extbuf[erp->er_extcount]; |
| 4602 | erp_next = erp + 1; | 4537 | erp_next = erp + 1; |
| 4603 | ep_next = erp_next->er_extbuf; | 4538 | ep_next = erp_next->er_extbuf; |
| 4539 | |||
| 4604 | while (erp_idx < nlists - 1) { | 4540 | while (erp_idx < nlists - 1) { |
| 4541 | /* | ||
| 4542 | * Check how many extent records are available in this irec. | ||
| 4543 | * If there is none skip the whole exercise. | ||
| 4544 | */ | ||
| 4605 | ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; | 4545 | ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; |
| 4606 | ext_diff = MIN(ext_avail, erp_next->er_extcount); | 4546 | if (ext_avail) { |
| 4607 | memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t)); | 4547 | |
| 4608 | erp->er_extcount += ext_diff; | ||
| 4609 | erp_next->er_extcount -= ext_diff; | ||
| 4610 | /* Remove next page */ | ||
| 4611 | if (erp_next->er_extcount == 0) { | ||
| 4612 | /* | 4548 | /* |
| 4613 | * Free page before removing extent record | 4549 | * Copy over as many as possible extent records into |
| 4614 | * so er_extoffs don't get modified in | 4550 | * the previous page. |
| 4615 | * xfs_iext_irec_remove. | ||
| 4616 | */ | 4551 | */ |
| 4617 | kmem_free(erp_next->er_extbuf, | 4552 | ext_diff = MIN(ext_avail, erp_next->er_extcount); |
| 4618 | erp_next->er_extcount * sizeof(xfs_bmbt_rec_t)); | 4553 | memcpy(ep, ep_next, ext_diff * sizeof(xfs_bmbt_rec_t)); |
| 4619 | erp_next->er_extbuf = NULL; | 4554 | erp->er_extcount += ext_diff; |
| 4620 | xfs_iext_irec_remove(ifp, erp_idx + 1); | 4555 | erp_next->er_extcount -= ext_diff; |
| 4621 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | 4556 | |
| 4622 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | 4557 | /* |
| 4623 | /* Update next page */ | 4558 | * If the next irec is empty now we can simply |
| 4624 | } else { | 4559 | * remove it. |
| 4625 | /* Move rest of page up to become next new page */ | 4560 | */ |
| 4626 | memmove(erp_next->er_extbuf, ep_next, | 4561 | if (erp_next->er_extcount == 0) { |
| 4627 | erp_next->er_extcount * sizeof(xfs_bmbt_rec_t)); | 4562 | /* |
| 4628 | ep_next = erp_next->er_extbuf; | 4563 | * Free page before removing extent record |
| 4629 | memset(&ep_next[erp_next->er_extcount], 0, | 4564 | * so er_extoffs don't get modified in |
| 4630 | (XFS_LINEAR_EXTS - erp_next->er_extcount) * | 4565 | * xfs_iext_irec_remove. |
| 4631 | sizeof(xfs_bmbt_rec_t)); | 4566 | */ |
| 4567 | kmem_free(erp_next->er_extbuf); | ||
| 4568 | erp_next->er_extbuf = NULL; | ||
| 4569 | xfs_iext_irec_remove(ifp, erp_idx + 1); | ||
| 4570 | erp = &ifp->if_u1.if_ext_irec[erp_idx]; | ||
| 4571 | nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; | ||
| 4572 | |||
| 4573 | /* | ||
| 4574 | * If the next irec is not empty move up the content | ||
| 4575 | * that has not been copied to the previous page to | ||
| 4576 | * the beggining of this one. | ||
| 4577 | */ | ||
| 4578 | } else { | ||
| 4579 | memmove(erp_next->er_extbuf, &ep_next[ext_diff], | ||
| 4580 | erp_next->er_extcount * | ||
| 4581 | sizeof(xfs_bmbt_rec_t)); | ||
| 4582 | ep_next = erp_next->er_extbuf; | ||
| 4583 | memset(&ep_next[erp_next->er_extcount], 0, | ||
| 4584 | (XFS_LINEAR_EXTS - | ||
| 4585 | erp_next->er_extcount) * | ||
| 4586 | sizeof(xfs_bmbt_rec_t)); | ||
| 4587 | } | ||
| 4632 | } | 4588 | } |
| 4589 | |||
| 4633 | if (erp->er_extcount == XFS_LINEAR_EXTS) { | 4590 | if (erp->er_extcount == XFS_LINEAR_EXTS) { |
| 4634 | erp_idx++; | 4591 | erp_idx++; |
| 4635 | if (erp_idx < nlists) | 4592 | if (erp_idx < nlists) |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 0a999fee4f03..1420c49674d7 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
| @@ -87,8 +87,7 @@ typedef struct xfs_ifork { | |||
| 87 | * Flags for xfs_ichgtime(). | 87 | * Flags for xfs_ichgtime(). |
| 88 | */ | 88 | */ |
| 89 | #define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ | 89 | #define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ |
| 90 | #define XFS_ICHGTIME_ACC 0x2 /* data fork access timestamp */ | 90 | #define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */ |
| 91 | #define XFS_ICHGTIME_CHG 0x4 /* inode field change timestamp */ | ||
| 92 | 91 | ||
| 93 | /* | 92 | /* |
| 94 | * Per-fork incore inode flags. | 93 | * Per-fork incore inode flags. |
| @@ -204,7 +203,7 @@ typedef struct xfs_inode { | |||
| 204 | struct xfs_inode *i_mprev; /* ptr to prev inode */ | 203 | struct xfs_inode *i_mprev; /* ptr to prev inode */ |
| 205 | struct xfs_mount *i_mount; /* fs mount struct ptr */ | 204 | struct xfs_mount *i_mount; /* fs mount struct ptr */ |
| 206 | struct list_head i_reclaim; /* reclaim list */ | 205 | struct list_head i_reclaim; /* reclaim list */ |
| 207 | bhv_vnode_t *i_vnode; /* vnode backpointer */ | 206 | struct inode *i_vnode; /* vnode backpointer */ |
| 208 | struct xfs_dquot *i_udquot; /* user dquot */ | 207 | struct xfs_dquot *i_udquot; /* user dquot */ |
| 209 | struct xfs_dquot *i_gdquot; /* group dquot */ | 208 | struct xfs_dquot *i_gdquot; /* group dquot */ |
| 210 | 209 | ||
| @@ -223,7 +222,7 @@ typedef struct xfs_inode { | |||
| 223 | struct xfs_inode_log_item *i_itemp; /* logging information */ | 222 | struct xfs_inode_log_item *i_itemp; /* logging information */ |
| 224 | mrlock_t i_lock; /* inode lock */ | 223 | mrlock_t i_lock; /* inode lock */ |
| 225 | mrlock_t i_iolock; /* inode IO lock */ | 224 | mrlock_t i_iolock; /* inode IO lock */ |
| 226 | sema_t i_flock; /* inode flush lock */ | 225 | struct completion i_flush; /* inode flush completion q */ |
| 227 | atomic_t i_pincount; /* inode pin count */ | 226 | atomic_t i_pincount; /* inode pin count */ |
| 228 | wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */ | 227 | wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */ |
| 229 | spinlock_t i_flags_lock; /* inode i_flags lock */ | 228 | spinlock_t i_flags_lock; /* inode i_flags lock */ |
| @@ -263,6 +262,18 @@ typedef struct xfs_inode { | |||
| 263 | #define XFS_ISIZE(ip) (((ip)->i_d.di_mode & S_IFMT) == S_IFREG) ? \ | 262 | #define XFS_ISIZE(ip) (((ip)->i_d.di_mode & S_IFMT) == S_IFREG) ? \ |
| 264 | (ip)->i_size : (ip)->i_d.di_size; | 263 | (ip)->i_size : (ip)->i_d.di_size; |
| 265 | 264 | ||
| 265 | /* Convert from vfs inode to xfs inode */ | ||
| 266 | static inline struct xfs_inode *XFS_I(struct inode *inode) | ||
| 267 | { | ||
| 268 | return (struct xfs_inode *)inode->i_private; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* convert from xfs inode to vfs inode */ | ||
| 272 | static inline struct inode *VFS_I(struct xfs_inode *ip) | ||
| 273 | { | ||
| 274 | return (struct inode *)ip->i_vnode; | ||
| 275 | } | ||
| 276 | |||
| 266 | /* | 277 | /* |
| 267 | * i_flags helper functions | 278 | * i_flags helper functions |
| 268 | */ | 279 | */ |
| @@ -439,9 +450,6 @@ xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) | |||
| 439 | #define XFS_ITRUNC_DEFINITE 0x1 | 450 | #define XFS_ITRUNC_DEFINITE 0x1 |
| 440 | #define XFS_ITRUNC_MAYBE 0x2 | 451 | #define XFS_ITRUNC_MAYBE 0x2 |
| 441 | 452 | ||
| 442 | #define XFS_ITOV(ip) ((ip)->i_vnode) | ||
| 443 | #define XFS_ITOV_NULL(ip) ((ip)->i_vnode) | ||
| 444 | |||
| 445 | /* | 453 | /* |
| 446 | * For multiple groups support: if S_ISGID bit is set in the parent | 454 | * For multiple groups support: if S_ISGID bit is set in the parent |
| 447 | * directory, group of new file is set to that of the parent, and | 455 | * directory, group of new file is set to that of the parent, and |
| @@ -473,11 +481,8 @@ int xfs_ilock_nowait(xfs_inode_t *, uint); | |||
| 473 | void xfs_iunlock(xfs_inode_t *, uint); | 481 | void xfs_iunlock(xfs_inode_t *, uint); |
| 474 | void xfs_ilock_demote(xfs_inode_t *, uint); | 482 | void xfs_ilock_demote(xfs_inode_t *, uint); |
| 475 | int xfs_isilocked(xfs_inode_t *, uint); | 483 | int xfs_isilocked(xfs_inode_t *, uint); |
| 476 | void xfs_iflock(xfs_inode_t *); | ||
| 477 | int xfs_iflock_nowait(xfs_inode_t *); | ||
| 478 | uint xfs_ilock_map_shared(xfs_inode_t *); | 484 | uint xfs_ilock_map_shared(xfs_inode_t *); |
| 479 | void xfs_iunlock_map_shared(xfs_inode_t *, uint); | 485 | void xfs_iunlock_map_shared(xfs_inode_t *, uint); |
| 480 | void xfs_ifunlock(xfs_inode_t *); | ||
| 481 | void xfs_ireclaim(xfs_inode_t *); | 486 | void xfs_ireclaim(xfs_inode_t *); |
| 482 | int xfs_finish_reclaim(xfs_inode_t *, int, int); | 487 | int xfs_finish_reclaim(xfs_inode_t *, int, int); |
| 483 | int xfs_finish_reclaim_all(struct xfs_mount *, int); | 488 | int xfs_finish_reclaim_all(struct xfs_mount *, int); |
| @@ -507,9 +512,6 @@ int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); | |||
| 507 | int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, | 512 | int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, |
| 508 | xfs_fsize_t, int, int); | 513 | xfs_fsize_t, int, int); |
| 509 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); | 514 | int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); |
| 510 | int xfs_igrow_start(xfs_inode_t *, xfs_fsize_t, struct cred *); | ||
| 511 | void xfs_igrow_finish(struct xfs_trans *, xfs_inode_t *, | ||
| 512 | xfs_fsize_t, int); | ||
| 513 | 515 | ||
| 514 | void xfs_idestroy_fork(xfs_inode_t *, int); | 516 | void xfs_idestroy_fork(xfs_inode_t *, int); |
| 515 | void xfs_idestroy(xfs_inode_t *); | 517 | void xfs_idestroy(xfs_inode_t *); |
| @@ -525,6 +527,7 @@ void xfs_iflush_all(struct xfs_mount *); | |||
| 525 | void xfs_ichgtime(xfs_inode_t *, int); | 527 | void xfs_ichgtime(xfs_inode_t *, int); |
| 526 | xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); | 528 | xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); |
| 527 | void xfs_lock_inodes(xfs_inode_t **, int, uint); | 529 | void xfs_lock_inodes(xfs_inode_t **, int, uint); |
| 530 | void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); | ||
| 528 | 531 | ||
| 529 | void xfs_synchronize_atime(xfs_inode_t *); | 532 | void xfs_synchronize_atime(xfs_inode_t *); |
| 530 | void xfs_mark_inode_dirty_sync(xfs_inode_t *); | 533 | void xfs_mark_inode_dirty_sync(xfs_inode_t *); |
| @@ -573,6 +576,26 @@ extern struct kmem_zone *xfs_ifork_zone; | |||
| 573 | extern struct kmem_zone *xfs_inode_zone; | 576 | extern struct kmem_zone *xfs_inode_zone; |
| 574 | extern struct kmem_zone *xfs_ili_zone; | 577 | extern struct kmem_zone *xfs_ili_zone; |
| 575 | 578 | ||
| 579 | /* | ||
| 580 | * Manage the i_flush queue embedded in the inode. This completion | ||
| 581 | * queue synchronizes processes attempting to flush the in-core | ||
| 582 | * inode back to disk. | ||
| 583 | */ | ||
| 584 | static inline void xfs_iflock(xfs_inode_t *ip) | ||
| 585 | { | ||
| 586 | wait_for_completion(&ip->i_flush); | ||
| 587 | } | ||
| 588 | |||
| 589 | static inline int xfs_iflock_nowait(xfs_inode_t *ip) | ||
| 590 | { | ||
| 591 | return try_wait_for_completion(&ip->i_flush); | ||
| 592 | } | ||
| 593 | |||
| 594 | static inline void xfs_ifunlock(xfs_inode_t *ip) | ||
| 595 | { | ||
| 596 | complete(&ip->i_flush); | ||
| 597 | } | ||
| 598 | |||
| 576 | #endif /* __KERNEL__ */ | 599 | #endif /* __KERNEL__ */ |
| 577 | 600 | ||
| 578 | #endif /* __XFS_INODE_H__ */ | 601 | #endif /* __XFS_INODE_H__ */ |
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 167b33f15772..97c7452e2620 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c | |||
| @@ -686,7 +686,7 @@ xfs_inode_item_unlock( | |||
| 686 | ASSERT(ip->i_d.di_nextents > 0); | 686 | ASSERT(ip->i_d.di_nextents > 0); |
| 687 | ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT); | 687 | ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT); |
| 688 | ASSERT(ip->i_df.if_bytes > 0); | 688 | ASSERT(ip->i_df.if_bytes > 0); |
| 689 | kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes); | 689 | kmem_free(iip->ili_extents_buf); |
| 690 | iip->ili_extents_buf = NULL; | 690 | iip->ili_extents_buf = NULL; |
| 691 | } | 691 | } |
| 692 | if (iip->ili_aextents_buf != NULL) { | 692 | if (iip->ili_aextents_buf != NULL) { |
| @@ -694,7 +694,7 @@ xfs_inode_item_unlock( | |||
| 694 | ASSERT(ip->i_d.di_anextents > 0); | 694 | ASSERT(ip->i_d.di_anextents > 0); |
| 695 | ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT); | 695 | ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT); |
| 696 | ASSERT(ip->i_afp->if_bytes > 0); | 696 | ASSERT(ip->i_afp->if_bytes > 0); |
| 697 | kmem_free(iip->ili_aextents_buf, ip->i_afp->if_bytes); | 697 | kmem_free(iip->ili_aextents_buf); |
| 698 | iip->ili_aextents_buf = NULL; | 698 | iip->ili_aextents_buf = NULL; |
| 699 | } | 699 | } |
| 700 | 700 | ||
| @@ -779,11 +779,10 @@ xfs_inode_item_pushbuf( | |||
| 779 | ASSERT(iip->ili_push_owner == current_pid()); | 779 | ASSERT(iip->ili_push_owner == current_pid()); |
| 780 | 780 | ||
| 781 | /* | 781 | /* |
| 782 | * If flushlock isn't locked anymore, chances are that the | 782 | * If a flush is not in progress anymore, chances are that the |
| 783 | * inode flush completed and the inode was taken off the AIL. | 783 | * inode was taken off the AIL. So, just get out. |
| 784 | * So, just get out. | ||
| 785 | */ | 784 | */ |
| 786 | if (!issemalocked(&(ip->i_flock)) || | 785 | if (completion_done(&ip->i_flush) || |
| 787 | ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { | 786 | ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { |
| 788 | iip->ili_pushbuf_flag = 0; | 787 | iip->ili_pushbuf_flag = 0; |
| 789 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 788 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| @@ -805,7 +804,7 @@ xfs_inode_item_pushbuf( | |||
| 805 | * If not, we can flush it async. | 804 | * If not, we can flush it async. |
| 806 | */ | 805 | */ |
| 807 | dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && | 806 | dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && |
| 808 | issemalocked(&(ip->i_flock))); | 807 | !completion_done(&ip->i_flush)); |
| 809 | iip->ili_pushbuf_flag = 0; | 808 | iip->ili_pushbuf_flag = 0; |
| 810 | xfs_iunlock(ip, XFS_ILOCK_SHARED); | 809 | xfs_iunlock(ip, XFS_ILOCK_SHARED); |
| 811 | xfs_buftrace("INODE ITEM PUSH", bp); | 810 | xfs_buftrace("INODE ITEM PUSH", bp); |
| @@ -858,7 +857,7 @@ xfs_inode_item_push( | |||
| 858 | ip = iip->ili_inode; | 857 | ip = iip->ili_inode; |
| 859 | 858 | ||
| 860 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); | 859 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED)); |
| 861 | ASSERT(issemalocked(&(ip->i_flock))); | 860 | ASSERT(!completion_done(&ip->i_flush)); |
| 862 | /* | 861 | /* |
| 863 | * Since we were able to lock the inode's flush lock and | 862 | * Since we were able to lock the inode's flush lock and |
| 864 | * we found it on the AIL, the inode must be dirty. This | 863 | * we found it on the AIL, the inode must be dirty. This |
| @@ -957,8 +956,7 @@ xfs_inode_item_destroy( | |||
| 957 | { | 956 | { |
| 958 | #ifdef XFS_TRANS_DEBUG | 957 | #ifdef XFS_TRANS_DEBUG |
| 959 | if (ip->i_itemp->ili_root_size != 0) { | 958 | if (ip->i_itemp->ili_root_size != 0) { |
| 960 | kmem_free(ip->i_itemp->ili_orig_root, | 959 | kmem_free(ip->i_itemp->ili_orig_root); |
| 961 | ip->i_itemp->ili_root_size); | ||
| 962 | } | 960 | } |
| 963 | #endif | 961 | #endif |
| 964 | kmem_zone_free(xfs_ili_zone, ip->i_itemp); | 962 | kmem_zone_free(xfs_ili_zone, ip->i_itemp); |
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 7edcde691d1a..67f22b2b44b3 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c | |||
| @@ -889,6 +889,16 @@ xfs_iomap_write_unwritten( | |||
| 889 | count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); | 889 | count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); |
| 890 | count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); | 890 | count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); |
| 891 | 891 | ||
| 892 | /* | ||
| 893 | * Reserve enough blocks in this transaction for two complete extent | ||
| 894 | * btree splits. We may be converting the middle part of an unwritten | ||
| 895 | * extent and in this case we will insert two new extents in the btree | ||
| 896 | * each of which could cause a full split. | ||
| 897 | * | ||
| 898 | * This reservation amount will be used in the first call to | ||
| 899 | * xfs_bmbt_split() to select an AG with enough space to satisfy the | ||
| 900 | * rest of the operation. | ||
| 901 | */ | ||
| 892 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; | 902 | resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; |
| 893 | 903 | ||
| 894 | do { | 904 | do { |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 419de15aeb43..cf6754a3c5b3 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
| @@ -59,7 +59,6 @@ xfs_bulkstat_one_iget( | |||
| 59 | { | 59 | { |
| 60 | xfs_icdinode_t *dic; /* dinode core info pointer */ | 60 | xfs_icdinode_t *dic; /* dinode core info pointer */ |
| 61 | xfs_inode_t *ip; /* incore inode pointer */ | 61 | xfs_inode_t *ip; /* incore inode pointer */ |
| 62 | bhv_vnode_t *vp; | ||
| 63 | int error; | 62 | int error; |
| 64 | 63 | ||
| 65 | error = xfs_iget(mp, NULL, ino, | 64 | error = xfs_iget(mp, NULL, ino, |
| @@ -72,7 +71,6 @@ xfs_bulkstat_one_iget( | |||
| 72 | ASSERT(ip != NULL); | 71 | ASSERT(ip != NULL); |
| 73 | ASSERT(ip->i_blkno != (xfs_daddr_t)0); | 72 | ASSERT(ip->i_blkno != (xfs_daddr_t)0); |
| 74 | 73 | ||
| 75 | vp = XFS_ITOV(ip); | ||
| 76 | dic = &ip->i_d; | 74 | dic = &ip->i_d; |
| 77 | 75 | ||
| 78 | /* xfs_iget returns the following without needing | 76 | /* xfs_iget returns the following without needing |
| @@ -85,7 +83,7 @@ xfs_bulkstat_one_iget( | |||
| 85 | buf->bs_uid = dic->di_uid; | 83 | buf->bs_uid = dic->di_uid; |
| 86 | buf->bs_gid = dic->di_gid; | 84 | buf->bs_gid = dic->di_gid; |
| 87 | buf->bs_size = dic->di_size; | 85 | buf->bs_size = dic->di_size; |
| 88 | vn_atime_to_bstime(vp, &buf->bs_atime); | 86 | vn_atime_to_bstime(VFS_I(ip), &buf->bs_atime); |
| 89 | buf->bs_mtime.tv_sec = dic->di_mtime.t_sec; | 87 | buf->bs_mtime.tv_sec = dic->di_mtime.t_sec; |
| 90 | buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec; | 88 | buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec; |
| 91 | buf->bs_ctime.tv_sec = dic->di_ctime.t_sec; | 89 | buf->bs_ctime.tv_sec = dic->di_ctime.t_sec; |
| @@ -257,7 +255,7 @@ xfs_bulkstat_one( | |||
| 257 | *ubused = error; | 255 | *ubused = error; |
| 258 | 256 | ||
| 259 | out_free: | 257 | out_free: |
| 260 | kmem_free(buf, sizeof(*buf)); | 258 | kmem_free(buf); |
| 261 | return error; | 259 | return error; |
| 262 | } | 260 | } |
| 263 | 261 | ||
| @@ -708,7 +706,7 @@ xfs_bulkstat( | |||
| 708 | /* | 706 | /* |
| 709 | * Done, we're either out of filesystem or space to put the data. | 707 | * Done, we're either out of filesystem or space to put the data. |
| 710 | */ | 708 | */ |
| 711 | kmem_free(irbuf, irbsize); | 709 | kmem_free(irbuf); |
| 712 | *ubcountp = ubelem; | 710 | *ubcountp = ubelem; |
| 713 | /* | 711 | /* |
| 714 | * Found some inodes, return them now and return the error next time. | 712 | * Found some inodes, return them now and return the error next time. |
| @@ -914,7 +912,7 @@ xfs_inumbers( | |||
| 914 | } | 912 | } |
| 915 | *lastino = XFS_AGINO_TO_INO(mp, agno, agino); | 913 | *lastino = XFS_AGINO_TO_INO(mp, agno, agino); |
| 916 | } | 914 | } |
| 917 | kmem_free(buffer, bcount * sizeof(*buffer)); | 915 | kmem_free(buffer); |
| 918 | if (cur) | 916 | if (cur) |
| 919 | xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : | 917 | xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : |
| 920 | XFS_BTREE_NOERROR)); | 918 | XFS_BTREE_NOERROR)); |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index ad3d26ddfe31..503ea89e8b9a 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
| @@ -124,16 +124,27 @@ STATIC void xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog, | |||
| 124 | STATIC int xlog_iclogs_empty(xlog_t *log); | 124 | STATIC int xlog_iclogs_empty(xlog_t *log); |
| 125 | 125 | ||
| 126 | #if defined(XFS_LOG_TRACE) | 126 | #if defined(XFS_LOG_TRACE) |
| 127 | |||
| 128 | #define XLOG_TRACE_LOGGRANT_SIZE 2048 | ||
| 129 | #define XLOG_TRACE_ICLOG_SIZE 256 | ||
| 130 | |||
| 131 | void | ||
| 132 | xlog_trace_loggrant_alloc(xlog_t *log) | ||
| 133 | { | ||
| 134 | log->l_grant_trace = ktrace_alloc(XLOG_TRACE_LOGGRANT_SIZE, KM_NOFS); | ||
| 135 | } | ||
| 136 | |||
| 137 | void | ||
| 138 | xlog_trace_loggrant_dealloc(xlog_t *log) | ||
| 139 | { | ||
| 140 | ktrace_free(log->l_grant_trace); | ||
| 141 | } | ||
| 142 | |||
| 127 | void | 143 | void |
| 128 | xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string) | 144 | xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string) |
| 129 | { | 145 | { |
| 130 | unsigned long cnts; | 146 | unsigned long cnts; |
| 131 | 147 | ||
| 132 | if (!log->l_grant_trace) { | ||
| 133 | log->l_grant_trace = ktrace_alloc(2048, KM_NOSLEEP); | ||
| 134 | if (!log->l_grant_trace) | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | /* ticket counts are 1 byte each */ | 148 | /* ticket counts are 1 byte each */ |
| 138 | cnts = ((unsigned long)tic->t_ocnt) | ((unsigned long)tic->t_cnt) << 8; | 149 | cnts = ((unsigned long)tic->t_ocnt) | ((unsigned long)tic->t_cnt) << 8; |
| 139 | 150 | ||
| @@ -157,10 +168,20 @@ xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string) | |||
| 157 | } | 168 | } |
| 158 | 169 | ||
| 159 | void | 170 | void |
| 171 | xlog_trace_iclog_alloc(xlog_in_core_t *iclog) | ||
| 172 | { | ||
| 173 | iclog->ic_trace = ktrace_alloc(XLOG_TRACE_ICLOG_SIZE, KM_NOFS); | ||
| 174 | } | ||
| 175 | |||
| 176 | void | ||
| 177 | xlog_trace_iclog_dealloc(xlog_in_core_t *iclog) | ||
| 178 | { | ||
| 179 | ktrace_free(iclog->ic_trace); | ||
| 180 | } | ||
| 181 | |||
| 182 | void | ||
| 160 | xlog_trace_iclog(xlog_in_core_t *iclog, uint state) | 183 | xlog_trace_iclog(xlog_in_core_t *iclog, uint state) |
| 161 | { | 184 | { |
| 162 | if (!iclog->ic_trace) | ||
| 163 | iclog->ic_trace = ktrace_alloc(256, KM_SLEEP); | ||
| 164 | ktrace_enter(iclog->ic_trace, | 185 | ktrace_enter(iclog->ic_trace, |
| 165 | (void *)((unsigned long)state), | 186 | (void *)((unsigned long)state), |
| 166 | (void *)((unsigned long)current_pid()), | 187 | (void *)((unsigned long)current_pid()), |
| @@ -170,8 +191,15 @@ xlog_trace_iclog(xlog_in_core_t *iclog, uint state) | |||
| 170 | (void *)NULL, (void *)NULL); | 191 | (void *)NULL, (void *)NULL); |
| 171 | } | 192 | } |
| 172 | #else | 193 | #else |
| 194 | |||
| 195 | #define xlog_trace_loggrant_alloc(log) | ||
| 196 | #define xlog_trace_loggrant_dealloc(log) | ||
| 173 | #define xlog_trace_loggrant(log,tic,string) | 197 | #define xlog_trace_loggrant(log,tic,string) |
| 198 | |||
| 199 | #define xlog_trace_iclog_alloc(iclog) | ||
| 200 | #define xlog_trace_iclog_dealloc(iclog) | ||
| 174 | #define xlog_trace_iclog(iclog,state) | 201 | #define xlog_trace_iclog(iclog,state) |
| 202 | |||
| 175 | #endif /* XFS_LOG_TRACE */ | 203 | #endif /* XFS_LOG_TRACE */ |
| 176 | 204 | ||
| 177 | 205 | ||
| @@ -226,20 +254,24 @@ xlog_grant_sub_space(struct log *log, int bytes) | |||
| 226 | static void | 254 | static void |
| 227 | xlog_grant_add_space_write(struct log *log, int bytes) | 255 | xlog_grant_add_space_write(struct log *log, int bytes) |
| 228 | { | 256 | { |
| 229 | log->l_grant_write_bytes += bytes; | 257 | int tmp = log->l_logsize - log->l_grant_write_bytes; |
| 230 | if (log->l_grant_write_bytes > log->l_logsize) { | 258 | if (tmp > bytes) |
| 231 | log->l_grant_write_bytes -= log->l_logsize; | 259 | log->l_grant_write_bytes += bytes; |
| 260 | else { | ||
| 232 | log->l_grant_write_cycle++; | 261 | log->l_grant_write_cycle++; |
| 262 | log->l_grant_write_bytes = bytes - tmp; | ||
| 233 | } | 263 | } |
| 234 | } | 264 | } |
| 235 | 265 | ||
| 236 | static void | 266 | static void |
| 237 | xlog_grant_add_space_reserve(struct log *log, int bytes) | 267 | xlog_grant_add_space_reserve(struct log *log, int bytes) |
| 238 | { | 268 | { |
| 239 | log->l_grant_reserve_bytes += bytes; | 269 | int tmp = log->l_logsize - log->l_grant_reserve_bytes; |
| 240 | if (log->l_grant_reserve_bytes > log->l_logsize) { | 270 | if (tmp > bytes) |
| 241 | log->l_grant_reserve_bytes -= log->l_logsize; | 271 | log->l_grant_reserve_bytes += bytes; |
| 272 | else { | ||
| 242 | log->l_grant_reserve_cycle++; | 273 | log->l_grant_reserve_cycle++; |
| 274 | log->l_grant_reserve_bytes = bytes - tmp; | ||
| 243 | } | 275 | } |
| 244 | } | 276 | } |
| 245 | 277 | ||
| @@ -332,15 +364,12 @@ xfs_log_done(xfs_mount_t *mp, | |||
| 332 | } else { | 364 | } else { |
| 333 | xlog_trace_loggrant(log, ticket, "xfs_log_done: (permanent)"); | 365 | xlog_trace_loggrant(log, ticket, "xfs_log_done: (permanent)"); |
| 334 | xlog_regrant_reserve_log_space(log, ticket); | 366 | xlog_regrant_reserve_log_space(log, ticket); |
| 335 | } | 367 | /* If this ticket was a permanent reservation and we aren't |
| 336 | 368 | * trying to release it, reset the inited flags; so next time | |
| 337 | /* If this ticket was a permanent reservation and we aren't | 369 | * we write, a start record will be written out. |
| 338 | * trying to release it, reset the inited flags; so next time | 370 | */ |
| 339 | * we write, a start record will be written out. | ||
| 340 | */ | ||
| 341 | if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) && | ||
| 342 | (flags & XFS_LOG_REL_PERM_RESERV) == 0) | ||
| 343 | ticket->t_flags |= XLOG_TIC_INITED; | 371 | ticket->t_flags |= XLOG_TIC_INITED; |
| 372 | } | ||
| 344 | 373 | ||
| 345 | return lsn; | 374 | return lsn; |
| 346 | } /* xfs_log_done */ | 375 | } /* xfs_log_done */ |
| @@ -353,11 +382,11 @@ xfs_log_done(xfs_mount_t *mp, | |||
| 353 | * Asynchronous forces are implemented by setting the WANT_SYNC | 382 | * Asynchronous forces are implemented by setting the WANT_SYNC |
| 354 | * bit in the appropriate in-core log and then returning. | 383 | * bit in the appropriate in-core log and then returning. |
| 355 | * | 384 | * |
| 356 | * Synchronous forces are implemented with a semaphore. All callers | 385 | * Synchronous forces are implemented with a signal variable. All callers |
| 357 | * to force a given lsn to disk will wait on a semaphore attached to the | 386 | * to force a given lsn to disk will wait on a the sv attached to the |
| 358 | * specific in-core log. When given in-core log finally completes its | 387 | * specific in-core log. When given in-core log finally completes its |
| 359 | * write to disk, that thread will wake up all threads waiting on the | 388 | * write to disk, that thread will wake up all threads waiting on the |
| 360 | * semaphore. | 389 | * sv. |
| 361 | */ | 390 | */ |
| 362 | int | 391 | int |
| 363 | _xfs_log_force( | 392 | _xfs_log_force( |
| @@ -584,12 +613,12 @@ error: | |||
| 584 | * mp - ubiquitous xfs mount point structure | 613 | * mp - ubiquitous xfs mount point structure |
| 585 | */ | 614 | */ |
| 586 | int | 615 | int |
| 587 | xfs_log_mount_finish(xfs_mount_t *mp, int mfsi_flags) | 616 | xfs_log_mount_finish(xfs_mount_t *mp) |
| 588 | { | 617 | { |
| 589 | int error; | 618 | int error; |
| 590 | 619 | ||
| 591 | if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) | 620 | if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) |
| 592 | error = xlog_recover_finish(mp->m_log, mfsi_flags); | 621 | error = xlog_recover_finish(mp->m_log); |
| 593 | else { | 622 | else { |
| 594 | error = 0; | 623 | error = 0; |
| 595 | ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); | 624 | ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); |
| @@ -703,7 +732,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) | |||
| 703 | if (!(iclog->ic_state == XLOG_STATE_ACTIVE || | 732 | if (!(iclog->ic_state == XLOG_STATE_ACTIVE || |
| 704 | iclog->ic_state == XLOG_STATE_DIRTY)) { | 733 | iclog->ic_state == XLOG_STATE_DIRTY)) { |
| 705 | if (!XLOG_FORCED_SHUTDOWN(log)) { | 734 | if (!XLOG_FORCED_SHUTDOWN(log)) { |
| 706 | sv_wait(&iclog->ic_forcesema, PMEM, | 735 | sv_wait(&iclog->ic_force_wait, PMEM, |
| 707 | &log->l_icloglock, s); | 736 | &log->l_icloglock, s); |
| 708 | } else { | 737 | } else { |
| 709 | spin_unlock(&log->l_icloglock); | 738 | spin_unlock(&log->l_icloglock); |
| @@ -744,7 +773,7 @@ xfs_log_unmount_write(xfs_mount_t *mp) | |||
| 744 | || iclog->ic_state == XLOG_STATE_DIRTY | 773 | || iclog->ic_state == XLOG_STATE_DIRTY |
| 745 | || iclog->ic_state == XLOG_STATE_IOERROR) ) { | 774 | || iclog->ic_state == XLOG_STATE_IOERROR) ) { |
| 746 | 775 | ||
| 747 | sv_wait(&iclog->ic_forcesema, PMEM, | 776 | sv_wait(&iclog->ic_force_wait, PMEM, |
| 748 | &log->l_icloglock, s); | 777 | &log->l_icloglock, s); |
| 749 | } else { | 778 | } else { |
| 750 | spin_unlock(&log->l_icloglock); | 779 | spin_unlock(&log->l_icloglock); |
| @@ -834,7 +863,7 @@ xfs_log_move_tail(xfs_mount_t *mp, | |||
| 834 | break; | 863 | break; |
| 835 | tail_lsn = 0; | 864 | tail_lsn = 0; |
| 836 | free_bytes -= tic->t_unit_res; | 865 | free_bytes -= tic->t_unit_res; |
| 837 | sv_signal(&tic->t_sema); | 866 | sv_signal(&tic->t_wait); |
| 838 | tic = tic->t_next; | 867 | tic = tic->t_next; |
| 839 | } while (tic != log->l_write_headq); | 868 | } while (tic != log->l_write_headq); |
| 840 | } | 869 | } |
| @@ -855,7 +884,7 @@ xfs_log_move_tail(xfs_mount_t *mp, | |||
| 855 | break; | 884 | break; |
| 856 | tail_lsn = 0; | 885 | tail_lsn = 0; |
| 857 | free_bytes -= need_bytes; | 886 | free_bytes -= need_bytes; |
| 858 | sv_signal(&tic->t_sema); | 887 | sv_signal(&tic->t_wait); |
| 859 | tic = tic->t_next; | 888 | tic = tic->t_next; |
| 860 | } while (tic != log->l_reserve_headq); | 889 | } while (tic != log->l_reserve_headq); |
| 861 | } | 890 | } |
| @@ -1008,7 +1037,7 @@ xlog_iodone(xfs_buf_t *bp) | |||
| 1008 | * layer, it means the underlyin device no longer supports | 1037 | * layer, it means the underlyin device no longer supports |
| 1009 | * barrier I/O. Warn loudly and turn off barriers. | 1038 | * barrier I/O. Warn loudly and turn off barriers. |
| 1010 | */ | 1039 | */ |
| 1011 | if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ORDERED(bp)) { | 1040 | if ((l->l_mp->m_flags & XFS_MOUNT_BARRIER) && !XFS_BUF_ISORDERED(bp)) { |
| 1012 | l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER; | 1041 | l->l_mp->m_flags &= ~XFS_MOUNT_BARRIER; |
| 1013 | xfs_fs_cmn_err(CE_WARN, l->l_mp, | 1042 | xfs_fs_cmn_err(CE_WARN, l->l_mp, |
| 1014 | "xlog_iodone: Barriers are no longer supported" | 1043 | "xlog_iodone: Barriers are no longer supported" |
| @@ -1228,8 +1257,9 @@ xlog_alloc_log(xfs_mount_t *mp, | |||
| 1228 | 1257 | ||
| 1229 | spin_lock_init(&log->l_icloglock); | 1258 | spin_lock_init(&log->l_icloglock); |
| 1230 | spin_lock_init(&log->l_grant_lock); | 1259 | spin_lock_init(&log->l_grant_lock); |
| 1231 | initnsema(&log->l_flushsema, 0, "ic-flush"); | 1260 | sv_init(&log->l_flush_wait, 0, "flush_wait"); |
| 1232 | 1261 | ||
| 1262 | xlog_trace_loggrant_alloc(log); | ||
| 1233 | /* log record size must be multiple of BBSIZE; see xlog_rec_header_t */ | 1263 | /* log record size must be multiple of BBSIZE; see xlog_rec_header_t */ |
| 1234 | ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0); | 1264 | ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0); |
| 1235 | 1265 | ||
| @@ -1281,8 +1311,10 @@ xlog_alloc_log(xfs_mount_t *mp, | |||
| 1281 | 1311 | ||
| 1282 | ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp)); | 1312 | ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp)); |
| 1283 | ASSERT(XFS_BUF_VALUSEMA(iclog->ic_bp) <= 0); | 1313 | ASSERT(XFS_BUF_VALUSEMA(iclog->ic_bp) <= 0); |
| 1284 | sv_init(&iclog->ic_forcesema, SV_DEFAULT, "iclog-force"); | 1314 | sv_init(&iclog->ic_force_wait, SV_DEFAULT, "iclog-force"); |
| 1285 | sv_init(&iclog->ic_writesema, SV_DEFAULT, "iclog-write"); | 1315 | sv_init(&iclog->ic_write_wait, SV_DEFAULT, "iclog-write"); |
| 1316 | |||
| 1317 | xlog_trace_iclog_alloc(iclog); | ||
| 1286 | 1318 | ||
| 1287 | iclogp = &iclog->ic_next; | 1319 | iclogp = &iclog->ic_next; |
| 1288 | } | 1320 | } |
| @@ -1561,33 +1593,21 @@ xlog_dealloc_log(xlog_t *log) | |||
| 1561 | 1593 | ||
| 1562 | iclog = log->l_iclog; | 1594 | iclog = log->l_iclog; |
| 1563 | for (i=0; i<log->l_iclog_bufs; i++) { | 1595 | for (i=0; i<log->l_iclog_bufs; i++) { |
| 1564 | sv_destroy(&iclog->ic_forcesema); | 1596 | sv_destroy(&iclog->ic_force_wait); |
| 1565 | sv_destroy(&iclog->ic_writesema); | 1597 | sv_destroy(&iclog->ic_write_wait); |
| 1566 | xfs_buf_free(iclog->ic_bp); | 1598 | xfs_buf_free(iclog->ic_bp); |
| 1567 | #ifdef XFS_LOG_TRACE | 1599 | xlog_trace_iclog_dealloc(iclog); |
| 1568 | if (iclog->ic_trace != NULL) { | ||
| 1569 | ktrace_free(iclog->ic_trace); | ||
| 1570 | } | ||
| 1571 | #endif | ||
| 1572 | next_iclog = iclog->ic_next; | 1600 | next_iclog = iclog->ic_next; |
| 1573 | kmem_free(iclog, sizeof(xlog_in_core_t)); | 1601 | kmem_free(iclog); |
| 1574 | iclog = next_iclog; | 1602 | iclog = next_iclog; |
| 1575 | } | 1603 | } |
| 1576 | freesema(&log->l_flushsema); | ||
| 1577 | spinlock_destroy(&log->l_icloglock); | 1604 | spinlock_destroy(&log->l_icloglock); |
| 1578 | spinlock_destroy(&log->l_grant_lock); | 1605 | spinlock_destroy(&log->l_grant_lock); |
| 1579 | 1606 | ||
| 1580 | xfs_buf_free(log->l_xbuf); | 1607 | xfs_buf_free(log->l_xbuf); |
| 1581 | #ifdef XFS_LOG_TRACE | 1608 | xlog_trace_loggrant_dealloc(log); |
| 1582 | if (log->l_trace != NULL) { | ||
| 1583 | ktrace_free(log->l_trace); | ||
| 1584 | } | ||
| 1585 | if (log->l_grant_trace != NULL) { | ||
| 1586 | ktrace_free(log->l_grant_trace); | ||
| 1587 | } | ||
| 1588 | #endif | ||
| 1589 | log->l_mp->m_log = NULL; | 1609 | log->l_mp->m_log = NULL; |
| 1590 | kmem_free(log, sizeof(xlog_t)); | 1610 | kmem_free(log); |
| 1591 | } /* xlog_dealloc_log */ | 1611 | } /* xlog_dealloc_log */ |
| 1592 | 1612 | ||
| 1593 | /* | 1613 | /* |
| @@ -1973,7 +1993,7 @@ xlog_write(xfs_mount_t * mp, | |||
| 1973 | /* Clean iclogs starting from the head. This ordering must be | 1993 | /* Clean iclogs starting from the head. This ordering must be |
| 1974 | * maintained, so an iclog doesn't become ACTIVE beyond one that | 1994 | * maintained, so an iclog doesn't become ACTIVE beyond one that |
| 1975 | * is SYNCING. This is also required to maintain the notion that we use | 1995 | * is SYNCING. This is also required to maintain the notion that we use |
| 1976 | * a counting semaphore to hold off would be writers to the log when every | 1996 | * a ordered wait queue to hold off would be writers to the log when every |
| 1977 | * iclog is trying to sync to disk. | 1997 | * iclog is trying to sync to disk. |
| 1978 | * | 1998 | * |
| 1979 | * State Change: DIRTY -> ACTIVE | 1999 | * State Change: DIRTY -> ACTIVE |
| @@ -2097,6 +2117,7 @@ xlog_state_do_callback( | |||
| 2097 | int funcdidcallbacks; /* flag: function did callbacks */ | 2117 | int funcdidcallbacks; /* flag: function did callbacks */ |
| 2098 | int repeats; /* for issuing console warnings if | 2118 | int repeats; /* for issuing console warnings if |
| 2099 | * looping too many times */ | 2119 | * looping too many times */ |
| 2120 | int wake = 0; | ||
| 2100 | 2121 | ||
| 2101 | spin_lock(&log->l_icloglock); | 2122 | spin_lock(&log->l_icloglock); |
| 2102 | first_iclog = iclog = log->l_iclog; | 2123 | first_iclog = iclog = log->l_iclog; |
| @@ -2236,7 +2257,7 @@ xlog_state_do_callback( | |||
| 2236 | xlog_state_clean_log(log); | 2257 | xlog_state_clean_log(log); |
| 2237 | 2258 | ||
| 2238 | /* wake up threads waiting in xfs_log_force() */ | 2259 | /* wake up threads waiting in xfs_log_force() */ |
| 2239 | sv_broadcast(&iclog->ic_forcesema); | 2260 | sv_broadcast(&iclog->ic_force_wait); |
| 2240 | 2261 | ||
| 2241 | iclog = iclog->ic_next; | 2262 | iclog = iclog->ic_next; |
| 2242 | } while (first_iclog != iclog); | 2263 | } while (first_iclog != iclog); |
| @@ -2278,15 +2299,13 @@ xlog_state_do_callback( | |||
| 2278 | } | 2299 | } |
| 2279 | #endif | 2300 | #endif |
| 2280 | 2301 | ||
| 2281 | flushcnt = 0; | 2302 | if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) |
| 2282 | if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) { | 2303 | wake = 1; |
| 2283 | flushcnt = log->l_flushcnt; | ||
| 2284 | log->l_flushcnt = 0; | ||
| 2285 | } | ||
| 2286 | spin_unlock(&log->l_icloglock); | 2304 | spin_unlock(&log->l_icloglock); |
| 2287 | while (flushcnt--) | 2305 | |
| 2288 | vsema(&log->l_flushsema); | 2306 | if (wake) |
| 2289 | } /* xlog_state_do_callback */ | 2307 | sv_broadcast(&log->l_flush_wait); |
| 2308 | } | ||
| 2290 | 2309 | ||
| 2291 | 2310 | ||
| 2292 | /* | 2311 | /* |
| @@ -2300,8 +2319,7 @@ xlog_state_do_callback( | |||
| 2300 | * the second completion goes through. | 2319 | * the second completion goes through. |
| 2301 | * | 2320 | * |
| 2302 | * Callbacks could take time, so they are done outside the scope of the | 2321 | * Callbacks could take time, so they are done outside the scope of the |
| 2303 | * global state machine log lock. Assume that the calls to cvsema won't | 2322 | * global state machine log lock. |
| 2304 | * take a long time. At least we know it won't sleep. | ||
| 2305 | */ | 2323 | */ |
| 2306 | STATIC void | 2324 | STATIC void |
| 2307 | xlog_state_done_syncing( | 2325 | xlog_state_done_syncing( |
| @@ -2337,7 +2355,7 @@ xlog_state_done_syncing( | |||
| 2337 | * iclog buffer, we wake them all, one will get to do the | 2355 | * iclog buffer, we wake them all, one will get to do the |
| 2338 | * I/O, the others get to wait for the result. | 2356 | * I/O, the others get to wait for the result. |
| 2339 | */ | 2357 | */ |
| 2340 | sv_broadcast(&iclog->ic_writesema); | 2358 | sv_broadcast(&iclog->ic_write_wait); |
| 2341 | spin_unlock(&log->l_icloglock); | 2359 | spin_unlock(&log->l_icloglock); |
| 2342 | xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ | 2360 | xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ |
| 2343 | } /* xlog_state_done_syncing */ | 2361 | } /* xlog_state_done_syncing */ |
| @@ -2345,11 +2363,9 @@ xlog_state_done_syncing( | |||
| 2345 | 2363 | ||
| 2346 | /* | 2364 | /* |
| 2347 | * If the head of the in-core log ring is not (ACTIVE or DIRTY), then we must | 2365 | * If the head of the in-core log ring is not (ACTIVE or DIRTY), then we must |
| 2348 | * sleep. The flush semaphore is set to the number of in-core buffers and | 2366 | * sleep. We wait on the flush queue on the head iclog as that should be |
| 2349 | * decremented around disk syncing. Therefore, if all buffers are syncing, | 2367 | * the first iclog to complete flushing. Hence if all iclogs are syncing, |
| 2350 | * this semaphore will cause new writes to sleep until a sync completes. | 2368 | * we will wait here and all new writes will sleep until a sync completes. |
| 2351 | * Otherwise, this code just does p() followed by v(). This approximates | ||
| 2352 | * a sleep/wakeup except we can't race. | ||
| 2353 | * | 2369 | * |
| 2354 | * The in-core logs are used in a circular fashion. They are not used | 2370 | * The in-core logs are used in a circular fashion. They are not used |
| 2355 | * out-of-order even when an iclog past the head is free. | 2371 | * out-of-order even when an iclog past the head is free. |
| @@ -2384,16 +2400,15 @@ restart: | |||
| 2384 | } | 2400 | } |
| 2385 | 2401 | ||
| 2386 | iclog = log->l_iclog; | 2402 | iclog = log->l_iclog; |
| 2387 | if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) { | 2403 | if (iclog->ic_state != XLOG_STATE_ACTIVE) { |
| 2388 | log->l_flushcnt++; | ||
| 2389 | spin_unlock(&log->l_icloglock); | ||
| 2390 | xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); | 2404 | xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); |
| 2391 | XFS_STATS_INC(xs_log_noiclogs); | 2405 | XFS_STATS_INC(xs_log_noiclogs); |
| 2392 | /* Ensure that log writes happen */ | 2406 | |
| 2393 | psema(&log->l_flushsema, PINOD); | 2407 | /* Wait for log writes to have flushed */ |
| 2408 | sv_wait(&log->l_flush_wait, 0, &log->l_icloglock, 0); | ||
| 2394 | goto restart; | 2409 | goto restart; |
| 2395 | } | 2410 | } |
| 2396 | ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); | 2411 | |
| 2397 | head = &iclog->ic_header; | 2412 | head = &iclog->ic_header; |
| 2398 | 2413 | ||
| 2399 | atomic_inc(&iclog->ic_refcnt); /* prevents sync */ | 2414 | atomic_inc(&iclog->ic_refcnt); /* prevents sync */ |
| @@ -2507,7 +2522,7 @@ xlog_grant_log_space(xlog_t *log, | |||
| 2507 | goto error_return; | 2522 | goto error_return; |
| 2508 | 2523 | ||
| 2509 | XFS_STATS_INC(xs_sleep_logspace); | 2524 | XFS_STATS_INC(xs_sleep_logspace); |
| 2510 | sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); | 2525 | sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s); |
| 2511 | /* | 2526 | /* |
| 2512 | * If we got an error, and the filesystem is shutting down, | 2527 | * If we got an error, and the filesystem is shutting down, |
| 2513 | * we'll catch it down below. So just continue... | 2528 | * we'll catch it down below. So just continue... |
| @@ -2533,7 +2548,7 @@ redo: | |||
| 2533 | xlog_trace_loggrant(log, tic, | 2548 | xlog_trace_loggrant(log, tic, |
| 2534 | "xlog_grant_log_space: sleep 2"); | 2549 | "xlog_grant_log_space: sleep 2"); |
| 2535 | XFS_STATS_INC(xs_sleep_logspace); | 2550 | XFS_STATS_INC(xs_sleep_logspace); |
| 2536 | sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); | 2551 | sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s); |
| 2537 | 2552 | ||
| 2538 | if (XLOG_FORCED_SHUTDOWN(log)) { | 2553 | if (XLOG_FORCED_SHUTDOWN(log)) { |
| 2539 | spin_lock(&log->l_grant_lock); | 2554 | spin_lock(&log->l_grant_lock); |
| @@ -2632,7 +2647,7 @@ xlog_regrant_write_log_space(xlog_t *log, | |||
| 2632 | if (free_bytes < ntic->t_unit_res) | 2647 | if (free_bytes < ntic->t_unit_res) |
| 2633 | break; | 2648 | break; |
| 2634 | free_bytes -= ntic->t_unit_res; | 2649 | free_bytes -= ntic->t_unit_res; |
| 2635 | sv_signal(&ntic->t_sema); | 2650 | sv_signal(&ntic->t_wait); |
| 2636 | ntic = ntic->t_next; | 2651 | ntic = ntic->t_next; |
| 2637 | } while (ntic != log->l_write_headq); | 2652 | } while (ntic != log->l_write_headq); |
| 2638 | 2653 | ||
| @@ -2643,7 +2658,7 @@ xlog_regrant_write_log_space(xlog_t *log, | |||
| 2643 | xlog_trace_loggrant(log, tic, | 2658 | xlog_trace_loggrant(log, tic, |
| 2644 | "xlog_regrant_write_log_space: sleep 1"); | 2659 | "xlog_regrant_write_log_space: sleep 1"); |
| 2645 | XFS_STATS_INC(xs_sleep_logspace); | 2660 | XFS_STATS_INC(xs_sleep_logspace); |
| 2646 | sv_wait(&tic->t_sema, PINOD|PLTWAIT, | 2661 | sv_wait(&tic->t_wait, PINOD|PLTWAIT, |
| 2647 | &log->l_grant_lock, s); | 2662 | &log->l_grant_lock, s); |
| 2648 | 2663 | ||
| 2649 | /* If we're shutting down, this tic is already | 2664 | /* If we're shutting down, this tic is already |
| @@ -2672,7 +2687,7 @@ redo: | |||
| 2672 | if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) | 2687 | if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) |
| 2673 | xlog_ins_ticketq(&log->l_write_headq, tic); | 2688 | xlog_ins_ticketq(&log->l_write_headq, tic); |
| 2674 | XFS_STATS_INC(xs_sleep_logspace); | 2689 | XFS_STATS_INC(xs_sleep_logspace); |
| 2675 | sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, s); | 2690 | sv_wait(&tic->t_wait, PINOD|PLTWAIT, &log->l_grant_lock, s); |
| 2676 | 2691 | ||
| 2677 | /* If we're shutting down, this tic is already off the queue */ | 2692 | /* If we're shutting down, this tic is already off the queue */ |
| 2678 | if (XLOG_FORCED_SHUTDOWN(log)) { | 2693 | if (XLOG_FORCED_SHUTDOWN(log)) { |
| @@ -2915,7 +2930,7 @@ xlog_state_switch_iclogs(xlog_t *log, | |||
| 2915 | * 2. the current iclog is drity, and the previous iclog is in the | 2930 | * 2. the current iclog is drity, and the previous iclog is in the |
| 2916 | * active or dirty state. | 2931 | * active or dirty state. |
| 2917 | * | 2932 | * |
| 2918 | * We may sleep (call psema) if: | 2933 | * We may sleep if: |
| 2919 | * | 2934 | * |
| 2920 | * 1. the current iclog is not in the active nor dirty state. | 2935 | * 1. the current iclog is not in the active nor dirty state. |
| 2921 | * 2. the current iclog dirty, and the previous iclog is not in the | 2936 | * 2. the current iclog dirty, and the previous iclog is not in the |
| @@ -3012,7 +3027,7 @@ maybe_sleep: | |||
| 3012 | return XFS_ERROR(EIO); | 3027 | return XFS_ERROR(EIO); |
| 3013 | } | 3028 | } |
| 3014 | XFS_STATS_INC(xs_log_force_sleep); | 3029 | XFS_STATS_INC(xs_log_force_sleep); |
| 3015 | sv_wait(&iclog->ic_forcesema, PINOD, &log->l_icloglock, s); | 3030 | sv_wait(&iclog->ic_force_wait, PINOD, &log->l_icloglock, s); |
| 3016 | /* | 3031 | /* |
| 3017 | * No need to grab the log lock here since we're | 3032 | * No need to grab the log lock here since we're |
| 3018 | * only deciding whether or not to return EIO | 3033 | * only deciding whether or not to return EIO |
| @@ -3095,7 +3110,7 @@ try_again: | |||
| 3095 | XLOG_STATE_SYNCING))) { | 3110 | XLOG_STATE_SYNCING))) { |
| 3096 | ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); | 3111 | ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); |
| 3097 | XFS_STATS_INC(xs_log_force_sleep); | 3112 | XFS_STATS_INC(xs_log_force_sleep); |
| 3098 | sv_wait(&iclog->ic_prev->ic_writesema, PSWP, | 3113 | sv_wait(&iclog->ic_prev->ic_write_wait, PSWP, |
| 3099 | &log->l_icloglock, s); | 3114 | &log->l_icloglock, s); |
| 3100 | *log_flushed = 1; | 3115 | *log_flushed = 1; |
| 3101 | already_slept = 1; | 3116 | already_slept = 1; |
| @@ -3115,7 +3130,7 @@ try_again: | |||
| 3115 | !(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { | 3130 | !(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { |
| 3116 | 3131 | ||
| 3117 | /* | 3132 | /* |
| 3118 | * Don't wait on the forcesema if we know that we've | 3133 | * Don't wait on completion if we know that we've |
| 3119 | * gotten a log write error. | 3134 | * gotten a log write error. |
| 3120 | */ | 3135 | */ |
| 3121 | if (iclog->ic_state & XLOG_STATE_IOERROR) { | 3136 | if (iclog->ic_state & XLOG_STATE_IOERROR) { |
| @@ -3123,7 +3138,7 @@ try_again: | |||
| 3123 | return XFS_ERROR(EIO); | 3138 | return XFS_ERROR(EIO); |
| 3124 | } | 3139 | } |
| 3125 | XFS_STATS_INC(xs_log_force_sleep); | 3140 | XFS_STATS_INC(xs_log_force_sleep); |
| 3126 | sv_wait(&iclog->ic_forcesema, PSWP, &log->l_icloglock, s); | 3141 | sv_wait(&iclog->ic_force_wait, PSWP, &log->l_icloglock, s); |
| 3127 | /* | 3142 | /* |
| 3128 | * No need to grab the log lock here since we're | 3143 | * No need to grab the log lock here since we're |
| 3129 | * only deciding whether or not to return EIO | 3144 | * only deciding whether or not to return EIO |
| @@ -3179,7 +3194,7 @@ STATIC void | |||
| 3179 | xlog_ticket_put(xlog_t *log, | 3194 | xlog_ticket_put(xlog_t *log, |
| 3180 | xlog_ticket_t *ticket) | 3195 | xlog_ticket_t *ticket) |
| 3181 | { | 3196 | { |
| 3182 | sv_destroy(&ticket->t_sema); | 3197 | sv_destroy(&ticket->t_wait); |
| 3183 | kmem_zone_free(xfs_log_ticket_zone, ticket); | 3198 | kmem_zone_free(xfs_log_ticket_zone, ticket); |
| 3184 | } /* xlog_ticket_put */ | 3199 | } /* xlog_ticket_put */ |
| 3185 | 3200 | ||
| @@ -3269,7 +3284,7 @@ xlog_ticket_get(xlog_t *log, | |||
| 3269 | tic->t_trans_type = 0; | 3284 | tic->t_trans_type = 0; |
| 3270 | if (xflags & XFS_LOG_PERM_RESERV) | 3285 | if (xflags & XFS_LOG_PERM_RESERV) |
| 3271 | tic->t_flags |= XLOG_TIC_PERM_RESERV; | 3286 | tic->t_flags |= XLOG_TIC_PERM_RESERV; |
| 3272 | sv_init(&(tic->t_sema), SV_DEFAULT, "logtick"); | 3287 | sv_init(&(tic->t_wait), SV_DEFAULT, "logtick"); |
| 3273 | 3288 | ||
| 3274 | xlog_tic_reset_res(tic); | 3289 | xlog_tic_reset_res(tic); |
| 3275 | 3290 | ||
| @@ -3556,14 +3571,14 @@ xfs_log_force_umount( | |||
| 3556 | */ | 3571 | */ |
| 3557 | if ((tic = log->l_reserve_headq)) { | 3572 | if ((tic = log->l_reserve_headq)) { |
| 3558 | do { | 3573 | do { |
| 3559 | sv_signal(&tic->t_sema); | 3574 | sv_signal(&tic->t_wait); |
| 3560 | tic = tic->t_next; | 3575 | tic = tic->t_next; |
| 3561 | } while (tic != log->l_reserve_headq); | 3576 | } while (tic != log->l_reserve_headq); |
| 3562 | } | 3577 | } |
| 3563 | 3578 | ||
| 3564 | if ((tic = log->l_write_headq)) { | 3579 | if ((tic = log->l_write_headq)) { |
| 3565 | do { | 3580 | do { |
| 3566 | sv_signal(&tic->t_sema); | 3581 | sv_signal(&tic->t_wait); |
| 3567 | tic = tic->t_next; | 3582 | tic = tic->t_next; |
| 3568 | } while (tic != log->l_write_headq); | 3583 | } while (tic != log->l_write_headq); |
| 3569 | } | 3584 | } |
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h index d1d678ecb63e..d47b91f10822 100644 --- a/fs/xfs/xfs_log.h +++ b/fs/xfs/xfs_log.h | |||
| @@ -149,7 +149,7 @@ int xfs_log_mount(struct xfs_mount *mp, | |||
| 149 | struct xfs_buftarg *log_target, | 149 | struct xfs_buftarg *log_target, |
| 150 | xfs_daddr_t start_block, | 150 | xfs_daddr_t start_block, |
| 151 | int num_bblocks); | 151 | int num_bblocks); |
| 152 | int xfs_log_mount_finish(struct xfs_mount *mp, int); | 152 | int xfs_log_mount_finish(struct xfs_mount *mp); |
| 153 | void xfs_log_move_tail(struct xfs_mount *mp, | 153 | void xfs_log_move_tail(struct xfs_mount *mp, |
| 154 | xfs_lsn_t tail_lsn); | 154 | xfs_lsn_t tail_lsn); |
| 155 | int xfs_log_notify(struct xfs_mount *mp, | 155 | int xfs_log_notify(struct xfs_mount *mp, |
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h index 8952a392b5f3..e7d8f84443fa 100644 --- a/fs/xfs/xfs_log_priv.h +++ b/fs/xfs/xfs_log_priv.h | |||
| @@ -241,7 +241,7 @@ typedef struct xlog_res { | |||
| 241 | } xlog_res_t; | 241 | } xlog_res_t; |
| 242 | 242 | ||
| 243 | typedef struct xlog_ticket { | 243 | typedef struct xlog_ticket { |
| 244 | sv_t t_sema; /* sleep on this semaphore : 20 */ | 244 | sv_t t_wait; /* ticket wait queue : 20 */ |
| 245 | struct xlog_ticket *t_next; /* :4|8 */ | 245 | struct xlog_ticket *t_next; /* :4|8 */ |
| 246 | struct xlog_ticket *t_prev; /* :4|8 */ | 246 | struct xlog_ticket *t_prev; /* :4|8 */ |
| 247 | xlog_tid_t t_tid; /* transaction identifier : 4 */ | 247 | xlog_tid_t t_tid; /* transaction identifier : 4 */ |
| @@ -314,7 +314,7 @@ typedef struct xlog_rec_ext_header { | |||
| 314 | * xlog_rec_header_t into the reserved space. | 314 | * xlog_rec_header_t into the reserved space. |
| 315 | * - ic_data follows, so a write to disk can start at the beginning of | 315 | * - ic_data follows, so a write to disk can start at the beginning of |
| 316 | * the iclog. | 316 | * the iclog. |
| 317 | * - ic_forcesema is used to implement synchronous forcing of the iclog to disk. | 317 | * - ic_forcewait is used to implement synchronous forcing of the iclog to disk. |
| 318 | * - ic_next is the pointer to the next iclog in the ring. | 318 | * - ic_next is the pointer to the next iclog in the ring. |
| 319 | * - ic_bp is a pointer to the buffer used to write this incore log to disk. | 319 | * - ic_bp is a pointer to the buffer used to write this incore log to disk. |
| 320 | * - ic_log is a pointer back to the global log structure. | 320 | * - ic_log is a pointer back to the global log structure. |
| @@ -339,8 +339,8 @@ typedef struct xlog_rec_ext_header { | |||
| 339 | * and move everything else out to subsequent cachelines. | 339 | * and move everything else out to subsequent cachelines. |
| 340 | */ | 340 | */ |
| 341 | typedef struct xlog_iclog_fields { | 341 | typedef struct xlog_iclog_fields { |
| 342 | sv_t ic_forcesema; | 342 | sv_t ic_force_wait; |
| 343 | sv_t ic_writesema; | 343 | sv_t ic_write_wait; |
| 344 | struct xlog_in_core *ic_next; | 344 | struct xlog_in_core *ic_next; |
| 345 | struct xlog_in_core *ic_prev; | 345 | struct xlog_in_core *ic_prev; |
| 346 | struct xfs_buf *ic_bp; | 346 | struct xfs_buf *ic_bp; |
| @@ -377,8 +377,8 @@ typedef struct xlog_in_core { | |||
| 377 | /* | 377 | /* |
| 378 | * Defines to save our code from this glop. | 378 | * Defines to save our code from this glop. |
| 379 | */ | 379 | */ |
| 380 | #define ic_forcesema hic_fields.ic_forcesema | 380 | #define ic_force_wait hic_fields.ic_force_wait |
| 381 | #define ic_writesema hic_fields.ic_writesema | 381 | #define ic_write_wait hic_fields.ic_write_wait |
| 382 | #define ic_next hic_fields.ic_next | 382 | #define ic_next hic_fields.ic_next |
| 383 | #define ic_prev hic_fields.ic_prev | 383 | #define ic_prev hic_fields.ic_prev |
| 384 | #define ic_bp hic_fields.ic_bp | 384 | #define ic_bp hic_fields.ic_bp |
| @@ -423,10 +423,8 @@ typedef struct log { | |||
| 423 | int l_logBBsize; /* size of log in BB chunks */ | 423 | int l_logBBsize; /* size of log in BB chunks */ |
| 424 | 424 | ||
| 425 | /* The following block of fields are changed while holding icloglock */ | 425 | /* The following block of fields are changed while holding icloglock */ |
| 426 | sema_t l_flushsema ____cacheline_aligned_in_smp; | 426 | sv_t l_flush_wait ____cacheline_aligned_in_smp; |
| 427 | /* iclog flushing semaphore */ | 427 | /* waiting for iclog flush */ |
| 428 | int l_flushcnt; /* # of procs waiting on this | ||
| 429 | * sema */ | ||
| 430 | int l_covered_state;/* state of "covering disk | 428 | int l_covered_state;/* state of "covering disk |
| 431 | * log entries" */ | 429 | * log entries" */ |
| 432 | xlog_in_core_t *l_iclog; /* head log queue */ | 430 | xlog_in_core_t *l_iclog; /* head log queue */ |
| @@ -450,7 +448,6 @@ typedef struct log { | |||
| 450 | int l_grant_write_bytes; | 448 | int l_grant_write_bytes; |
| 451 | 449 | ||
| 452 | #ifdef XFS_LOG_TRACE | 450 | #ifdef XFS_LOG_TRACE |
| 453 | struct ktrace *l_trace; | ||
| 454 | struct ktrace *l_grant_trace; | 451 | struct ktrace *l_grant_trace; |
| 455 | #endif | 452 | #endif |
| 456 | 453 | ||
| @@ -470,7 +467,7 @@ extern int xlog_find_tail(xlog_t *log, | |||
| 470 | xfs_daddr_t *head_blk, | 467 | xfs_daddr_t *head_blk, |
| 471 | xfs_daddr_t *tail_blk); | 468 | xfs_daddr_t *tail_blk); |
| 472 | extern int xlog_recover(xlog_t *log); | 469 | extern int xlog_recover(xlog_t *log); |
| 473 | extern int xlog_recover_finish(xlog_t *log, int mfsi_flags); | 470 | extern int xlog_recover_finish(xlog_t *log); |
| 474 | extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int); | 471 | extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog, int); |
| 475 | extern void xlog_recover_process_iunlinks(xlog_t *log); | 472 | extern void xlog_recover_process_iunlinks(xlog_t *log); |
| 476 | 473 | ||
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index e65ab4af0955..82d46ce69d5f 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
| @@ -1715,8 +1715,7 @@ xlog_check_buffer_cancelled( | |||
| 1715 | } else { | 1715 | } else { |
| 1716 | prevp->bc_next = bcp->bc_next; | 1716 | prevp->bc_next = bcp->bc_next; |
| 1717 | } | 1717 | } |
| 1718 | kmem_free(bcp, | 1718 | kmem_free(bcp); |
| 1719 | sizeof(xfs_buf_cancel_t)); | ||
| 1720 | } | 1719 | } |
| 1721 | } | 1720 | } |
| 1722 | return 1; | 1721 | return 1; |
| @@ -2519,7 +2518,7 @@ write_inode_buffer: | |||
| 2519 | 2518 | ||
| 2520 | error: | 2519 | error: |
| 2521 | if (need_free) | 2520 | if (need_free) |
| 2522 | kmem_free(in_f, sizeof(*in_f)); | 2521 | kmem_free(in_f); |
| 2523 | return XFS_ERROR(error); | 2522 | return XFS_ERROR(error); |
| 2524 | } | 2523 | } |
| 2525 | 2524 | ||
| @@ -2830,16 +2829,14 @@ xlog_recover_free_trans( | |||
| 2830 | item = item->ri_next; | 2829 | item = item->ri_next; |
| 2831 | /* Free the regions in the item. */ | 2830 | /* Free the regions in the item. */ |
| 2832 | for (i = 0; i < free_item->ri_cnt; i++) { | 2831 | for (i = 0; i < free_item->ri_cnt; i++) { |
| 2833 | kmem_free(free_item->ri_buf[i].i_addr, | 2832 | kmem_free(free_item->ri_buf[i].i_addr); |
| 2834 | free_item->ri_buf[i].i_len); | ||
| 2835 | } | 2833 | } |
| 2836 | /* Free the item itself */ | 2834 | /* Free the item itself */ |
| 2837 | kmem_free(free_item->ri_buf, | 2835 | kmem_free(free_item->ri_buf); |
| 2838 | (free_item->ri_total * sizeof(xfs_log_iovec_t))); | 2836 | kmem_free(free_item); |
| 2839 | kmem_free(free_item, sizeof(xlog_recover_item_t)); | ||
| 2840 | } while (first_item != item); | 2837 | } while (first_item != item); |
| 2841 | /* Free the transaction recover structure */ | 2838 | /* Free the transaction recover structure */ |
| 2842 | kmem_free(trans, sizeof(xlog_recover_t)); | 2839 | kmem_free(trans); |
| 2843 | } | 2840 | } |
| 2844 | 2841 | ||
| 2845 | STATIC int | 2842 | STATIC int |
| @@ -3786,8 +3783,7 @@ xlog_do_log_recovery( | |||
| 3786 | error = xlog_do_recovery_pass(log, head_blk, tail_blk, | 3783 | error = xlog_do_recovery_pass(log, head_blk, tail_blk, |
| 3787 | XLOG_RECOVER_PASS1); | 3784 | XLOG_RECOVER_PASS1); |
| 3788 | if (error != 0) { | 3785 | if (error != 0) { |
| 3789 | kmem_free(log->l_buf_cancel_table, | 3786 | kmem_free(log->l_buf_cancel_table); |
| 3790 | XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*)); | ||
| 3791 | log->l_buf_cancel_table = NULL; | 3787 | log->l_buf_cancel_table = NULL; |
| 3792 | return error; | 3788 | return error; |
| 3793 | } | 3789 | } |
| @@ -3806,8 +3802,7 @@ xlog_do_log_recovery( | |||
| 3806 | } | 3802 | } |
| 3807 | #endif /* DEBUG */ | 3803 | #endif /* DEBUG */ |
| 3808 | 3804 | ||
| 3809 | kmem_free(log->l_buf_cancel_table, | 3805 | kmem_free(log->l_buf_cancel_table); |
| 3810 | XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*)); | ||
| 3811 | log->l_buf_cancel_table = NULL; | 3806 | log->l_buf_cancel_table = NULL; |
| 3812 | 3807 | ||
| 3813 | return error; | 3808 | return error; |
| @@ -3945,8 +3940,7 @@ xlog_recover( | |||
| 3945 | */ | 3940 | */ |
| 3946 | int | 3941 | int |
| 3947 | xlog_recover_finish( | 3942 | xlog_recover_finish( |
| 3948 | xlog_t *log, | 3943 | xlog_t *log) |
| 3949 | int mfsi_flags) | ||
| 3950 | { | 3944 | { |
| 3951 | /* | 3945 | /* |
| 3952 | * Now we're ready to do the transactions needed for the | 3946 | * Now we're ready to do the transactions needed for the |
| @@ -3974,9 +3968,7 @@ xlog_recover_finish( | |||
| 3974 | xfs_log_force(log->l_mp, (xfs_lsn_t)0, | 3968 | xfs_log_force(log->l_mp, (xfs_lsn_t)0, |
| 3975 | (XFS_LOG_FORCE | XFS_LOG_SYNC)); | 3969 | (XFS_LOG_FORCE | XFS_LOG_SYNC)); |
| 3976 | 3970 | ||
| 3977 | if ( (mfsi_flags & XFS_MFSI_NOUNLINK) == 0 ) { | 3971 | xlog_recover_process_iunlinks(log); |
| 3978 | xlog_recover_process_iunlinks(log); | ||
| 3979 | } | ||
| 3980 | 3972 | ||
| 3981 | xlog_recover_check_summary(log); | 3973 | xlog_recover_check_summary(log); |
| 3982 | 3974 | ||
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index da3988453b71..a4503f5e9497 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -47,12 +47,10 @@ | |||
| 47 | 47 | ||
| 48 | STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t); | 48 | STATIC int xfs_mount_log_sb(xfs_mount_t *, __int64_t); |
| 49 | STATIC int xfs_uuid_mount(xfs_mount_t *); | 49 | STATIC int xfs_uuid_mount(xfs_mount_t *); |
| 50 | STATIC void xfs_uuid_unmount(xfs_mount_t *mp); | ||
| 51 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); | 50 | STATIC void xfs_unmountfs_wait(xfs_mount_t *); |
| 52 | 51 | ||
| 53 | 52 | ||
| 54 | #ifdef HAVE_PERCPU_SB | 53 | #ifdef HAVE_PERCPU_SB |
| 55 | STATIC void xfs_icsb_destroy_counters(xfs_mount_t *); | ||
| 56 | STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, | 54 | STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, |
| 57 | int); | 55 | int); |
| 58 | STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t, | 56 | STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t, |
| @@ -63,7 +61,6 @@ STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); | |||
| 63 | 61 | ||
| 64 | #else | 62 | #else |
| 65 | 63 | ||
| 66 | #define xfs_icsb_destroy_counters(mp) do { } while (0) | ||
| 67 | #define xfs_icsb_balance_counter(mp, a, b) do { } while (0) | 64 | #define xfs_icsb_balance_counter(mp, a, b) do { } while (0) |
| 68 | #define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0) | 65 | #define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0) |
| 69 | #define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0) | 66 | #define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0) |
| @@ -126,34 +123,12 @@ static const struct { | |||
| 126 | }; | 123 | }; |
| 127 | 124 | ||
| 128 | /* | 125 | /* |
| 129 | * Return a pointer to an initialized xfs_mount structure. | ||
| 130 | */ | ||
| 131 | xfs_mount_t * | ||
| 132 | xfs_mount_init(void) | ||
| 133 | { | ||
| 134 | xfs_mount_t *mp; | ||
| 135 | |||
| 136 | mp = kmem_zalloc(sizeof(xfs_mount_t), KM_SLEEP); | ||
| 137 | |||
| 138 | if (xfs_icsb_init_counters(mp)) { | ||
| 139 | mp->m_flags |= XFS_MOUNT_NO_PERCPU_SB; | ||
| 140 | } | ||
| 141 | |||
| 142 | spin_lock_init(&mp->m_sb_lock); | ||
| 143 | mutex_init(&mp->m_ilock); | ||
| 144 | mutex_init(&mp->m_growlock); | ||
| 145 | atomic_set(&mp->m_active_trans, 0); | ||
| 146 | |||
| 147 | return mp; | ||
| 148 | } | ||
| 149 | |||
| 150 | /* | ||
| 151 | * Free up the resources associated with a mount structure. Assume that | 126 | * Free up the resources associated with a mount structure. Assume that |
| 152 | * the structure was initially zeroed, so we can tell which fields got | 127 | * the structure was initially zeroed, so we can tell which fields got |
| 153 | * initialized. | 128 | * initialized. |
| 154 | */ | 129 | */ |
| 155 | void | 130 | STATIC void |
| 156 | xfs_mount_free( | 131 | xfs_free_perag( |
| 157 | xfs_mount_t *mp) | 132 | xfs_mount_t *mp) |
| 158 | { | 133 | { |
| 159 | if (mp->m_perag) { | 134 | if (mp->m_perag) { |
| @@ -161,28 +136,9 @@ xfs_mount_free( | |||
| 161 | 136 | ||
| 162 | for (agno = 0; agno < mp->m_maxagi; agno++) | 137 | for (agno = 0; agno < mp->m_maxagi; agno++) |
| 163 | if (mp->m_perag[agno].pagb_list) | 138 | if (mp->m_perag[agno].pagb_list) |
| 164 | kmem_free(mp->m_perag[agno].pagb_list, | 139 | kmem_free(mp->m_perag[agno].pagb_list); |
| 165 | sizeof(xfs_perag_busy_t) * | 140 | kmem_free(mp->m_perag); |
| 166 | XFS_PAGB_NUM_SLOTS); | ||
| 167 | kmem_free(mp->m_perag, | ||
| 168 | sizeof(xfs_perag_t) * mp->m_sb.sb_agcount); | ||
| 169 | } | 141 | } |
| 170 | |||
| 171 | spinlock_destroy(&mp->m_ail_lock); | ||
| 172 | spinlock_destroy(&mp->m_sb_lock); | ||
| 173 | mutex_destroy(&mp->m_ilock); | ||
| 174 | mutex_destroy(&mp->m_growlock); | ||
| 175 | if (mp->m_quotainfo) | ||
| 176 | XFS_QM_DONE(mp); | ||
| 177 | |||
| 178 | if (mp->m_fsname != NULL) | ||
| 179 | kmem_free(mp->m_fsname, mp->m_fsname_len); | ||
| 180 | if (mp->m_rtname != NULL) | ||
| 181 | kmem_free(mp->m_rtname, strlen(mp->m_rtname) + 1); | ||
| 182 | if (mp->m_logname != NULL) | ||
| 183 | kmem_free(mp->m_logname, strlen(mp->m_logname) + 1); | ||
| 184 | |||
| 185 | xfs_icsb_destroy_counters(mp); | ||
| 186 | } | 142 | } |
| 187 | 143 | ||
| 188 | /* | 144 | /* |
| @@ -288,6 +244,19 @@ xfs_mount_validate_sb( | |||
| 288 | return XFS_ERROR(EFSCORRUPTED); | 244 | return XFS_ERROR(EFSCORRUPTED); |
| 289 | } | 245 | } |
| 290 | 246 | ||
| 247 | /* | ||
| 248 | * Until this is fixed only page-sized or smaller data blocks work. | ||
| 249 | */ | ||
| 250 | if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { | ||
| 251 | xfs_fs_mount_cmn_err(flags, | ||
| 252 | "file system with blocksize %d bytes", | ||
| 253 | sbp->sb_blocksize); | ||
| 254 | xfs_fs_mount_cmn_err(flags, | ||
| 255 | "only pagesize (%ld) or less will currently work.", | ||
| 256 | PAGE_SIZE); | ||
| 257 | return XFS_ERROR(ENOSYS); | ||
| 258 | } | ||
| 259 | |||
| 291 | if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || | 260 | if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || |
| 292 | xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { | 261 | xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { |
| 293 | xfs_fs_mount_cmn_err(flags, | 262 | xfs_fs_mount_cmn_err(flags, |
| @@ -309,19 +278,6 @@ xfs_mount_validate_sb( | |||
| 309 | return XFS_ERROR(ENOSYS); | 278 | return XFS_ERROR(ENOSYS); |
| 310 | } | 279 | } |
| 311 | 280 | ||
| 312 | /* | ||
| 313 | * Until this is fixed only page-sized or smaller data blocks work. | ||
| 314 | */ | ||
| 315 | if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { | ||
| 316 | xfs_fs_mount_cmn_err(flags, | ||
| 317 | "file system with blocksize %d bytes", | ||
| 318 | sbp->sb_blocksize); | ||
| 319 | xfs_fs_mount_cmn_err(flags, | ||
| 320 | "only pagesize (%ld) or less will currently work.", | ||
| 321 | PAGE_SIZE); | ||
| 322 | return XFS_ERROR(ENOSYS); | ||
| 323 | } | ||
| 324 | |||
| 325 | return 0; | 281 | return 0; |
| 326 | } | 282 | } |
| 327 | 283 | ||
| @@ -734,11 +690,11 @@ xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount) | |||
| 734 | * Update alignment values based on mount options and sb values | 690 | * Update alignment values based on mount options and sb values |
| 735 | */ | 691 | */ |
| 736 | STATIC int | 692 | STATIC int |
| 737 | xfs_update_alignment(xfs_mount_t *mp, int mfsi_flags, __uint64_t *update_flags) | 693 | xfs_update_alignment(xfs_mount_t *mp, __uint64_t *update_flags) |
| 738 | { | 694 | { |
| 739 | xfs_sb_t *sbp = &(mp->m_sb); | 695 | xfs_sb_t *sbp = &(mp->m_sb); |
| 740 | 696 | ||
| 741 | if (mp->m_dalign && !(mfsi_flags & XFS_MFSI_SECOND)) { | 697 | if (mp->m_dalign) { |
| 742 | /* | 698 | /* |
| 743 | * If stripe unit and stripe width are not multiples | 699 | * If stripe unit and stripe width are not multiples |
| 744 | * of the fs blocksize turn off alignment. | 700 | * of the fs blocksize turn off alignment. |
| @@ -894,7 +850,7 @@ xfs_set_inoalignment(xfs_mount_t *mp) | |||
| 894 | * Check that the data (and log if separate) are an ok size. | 850 | * Check that the data (and log if separate) are an ok size. |
| 895 | */ | 851 | */ |
| 896 | STATIC int | 852 | STATIC int |
| 897 | xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) | 853 | xfs_check_sizes(xfs_mount_t *mp) |
| 898 | { | 854 | { |
| 899 | xfs_buf_t *bp; | 855 | xfs_buf_t *bp; |
| 900 | xfs_daddr_t d; | 856 | xfs_daddr_t d; |
| @@ -917,8 +873,7 @@ xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) | |||
| 917 | return error; | 873 | return error; |
| 918 | } | 874 | } |
| 919 | 875 | ||
| 920 | if (((mfsi_flags & XFS_MFSI_CLIENT) == 0) && | 876 | if (mp->m_logdev_targp != mp->m_ddev_targp) { |
| 921 | mp->m_logdev_targp != mp->m_ddev_targp) { | ||
| 922 | d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); | 877 | d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); |
| 923 | if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { | 878 | if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { |
| 924 | cmn_err(CE_WARN, "XFS: size check 3 failed"); | 879 | cmn_err(CE_WARN, "XFS: size check 3 failed"); |
| @@ -953,15 +908,13 @@ xfs_check_sizes(xfs_mount_t *mp, int mfsi_flags) | |||
| 953 | */ | 908 | */ |
| 954 | int | 909 | int |
| 955 | xfs_mountfs( | 910 | xfs_mountfs( |
| 956 | xfs_mount_t *mp, | 911 | xfs_mount_t *mp) |
| 957 | int mfsi_flags) | ||
| 958 | { | 912 | { |
| 959 | xfs_sb_t *sbp = &(mp->m_sb); | 913 | xfs_sb_t *sbp = &(mp->m_sb); |
| 960 | xfs_inode_t *rip; | 914 | xfs_inode_t *rip; |
| 961 | __uint64_t resblks; | 915 | __uint64_t resblks; |
| 962 | __int64_t update_flags = 0LL; | 916 | __int64_t update_flags = 0LL; |
| 963 | uint quotamount, quotaflags; | 917 | uint quotamount, quotaflags; |
| 964 | int agno; | ||
| 965 | int uuid_mounted = 0; | 918 | int uuid_mounted = 0; |
| 966 | int error = 0; | 919 | int error = 0; |
| 967 | 920 | ||
| @@ -994,9 +947,19 @@ xfs_mountfs( | |||
| 994 | * Re-check for ATTR2 in case it was found in bad_features2 | 947 | * Re-check for ATTR2 in case it was found in bad_features2 |
| 995 | * slot. | 948 | * slot. |
| 996 | */ | 949 | */ |
| 997 | if (xfs_sb_version_hasattr2(&mp->m_sb)) | 950 | if (xfs_sb_version_hasattr2(&mp->m_sb) && |
| 951 | !(mp->m_flags & XFS_MOUNT_NOATTR2)) | ||
| 998 | mp->m_flags |= XFS_MOUNT_ATTR2; | 952 | mp->m_flags |= XFS_MOUNT_ATTR2; |
| 953 | } | ||
| 954 | |||
| 955 | if (xfs_sb_version_hasattr2(&mp->m_sb) && | ||
| 956 | (mp->m_flags & XFS_MOUNT_NOATTR2)) { | ||
| 957 | xfs_sb_version_removeattr2(&mp->m_sb); | ||
| 958 | update_flags |= XFS_SB_FEATURES2; | ||
| 999 | 959 | ||
| 960 | /* update sb_versionnum for the clearing of the morebits */ | ||
| 961 | if (!sbp->sb_features2) | ||
| 962 | update_flags |= XFS_SB_VERSIONNUM; | ||
| 1000 | } | 963 | } |
| 1001 | 964 | ||
| 1002 | /* | 965 | /* |
| @@ -1005,7 +968,7 @@ xfs_mountfs( | |||
| 1005 | * allocator alignment is within an ag, therefore ag has | 968 | * allocator alignment is within an ag, therefore ag has |
| 1006 | * to be aligned at stripe boundary. | 969 | * to be aligned at stripe boundary. |
| 1007 | */ | 970 | */ |
| 1008 | error = xfs_update_alignment(mp, mfsi_flags, &update_flags); | 971 | error = xfs_update_alignment(mp, &update_flags); |
| 1009 | if (error) | 972 | if (error) |
| 1010 | goto error1; | 973 | goto error1; |
| 1011 | 974 | ||
| @@ -1024,8 +987,7 @@ xfs_mountfs( | |||
| 1024 | * since a single partition filesystem is identical to a single | 987 | * since a single partition filesystem is identical to a single |
| 1025 | * partition volume/filesystem. | 988 | * partition volume/filesystem. |
| 1026 | */ | 989 | */ |
| 1027 | if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && | 990 | if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) { |
| 1028 | (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { | ||
| 1029 | if (xfs_uuid_mount(mp)) { | 991 | if (xfs_uuid_mount(mp)) { |
| 1030 | error = XFS_ERROR(EINVAL); | 992 | error = XFS_ERROR(EINVAL); |
| 1031 | goto error1; | 993 | goto error1; |
| @@ -1053,7 +1015,7 @@ xfs_mountfs( | |||
| 1053 | /* | 1015 | /* |
| 1054 | * Check that the data (and log if separate) are an ok size. | 1016 | * Check that the data (and log if separate) are an ok size. |
| 1055 | */ | 1017 | */ |
| 1056 | error = xfs_check_sizes(mp, mfsi_flags); | 1018 | error = xfs_check_sizes(mp); |
| 1057 | if (error) | 1019 | if (error) |
| 1058 | goto error1; | 1020 | goto error1; |
| 1059 | 1021 | ||
| @@ -1067,13 +1029,6 @@ xfs_mountfs( | |||
| 1067 | } | 1029 | } |
| 1068 | 1030 | ||
| 1069 | /* | 1031 | /* |
| 1070 | * For client case we are done now | ||
| 1071 | */ | ||
| 1072 | if (mfsi_flags & XFS_MFSI_CLIENT) { | ||
| 1073 | return 0; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | /* | ||
| 1077 | * Copies the low order bits of the timestamp and the randomly | 1032 | * Copies the low order bits of the timestamp and the randomly |
| 1078 | * set "sequence" number out of a UUID. | 1033 | * set "sequence" number out of a UUID. |
| 1079 | */ | 1034 | */ |
| @@ -1097,8 +1052,10 @@ xfs_mountfs( | |||
| 1097 | * Allocate and initialize the per-ag data. | 1052 | * Allocate and initialize the per-ag data. |
| 1098 | */ | 1053 | */ |
| 1099 | init_rwsem(&mp->m_peraglock); | 1054 | init_rwsem(&mp->m_peraglock); |
| 1100 | mp->m_perag = | 1055 | mp->m_perag = kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), |
| 1101 | kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP); | 1056 | KM_MAYFAIL); |
| 1057 | if (!mp->m_perag) | ||
| 1058 | goto error1; | ||
| 1102 | 1059 | ||
| 1103 | mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); | 1060 | mp->m_maxagi = xfs_initialize_perag(mp, sbp->sb_agcount); |
| 1104 | 1061 | ||
| @@ -1210,7 +1167,7 @@ xfs_mountfs( | |||
| 1210 | * delayed until after the root and real-time bitmap inodes | 1167 | * delayed until after the root and real-time bitmap inodes |
| 1211 | * were consistently read in. | 1168 | * were consistently read in. |
| 1212 | */ | 1169 | */ |
| 1213 | error = xfs_log_mount_finish(mp, mfsi_flags); | 1170 | error = xfs_log_mount_finish(mp); |
| 1214 | if (error) { | 1171 | if (error) { |
| 1215 | cmn_err(CE_WARN, "XFS: log mount finish failed"); | 1172 | cmn_err(CE_WARN, "XFS: log mount finish failed"); |
| 1216 | goto error4; | 1173 | goto error4; |
| @@ -1219,7 +1176,7 @@ xfs_mountfs( | |||
| 1219 | /* | 1176 | /* |
| 1220 | * Complete the quota initialisation, post-log-replay component. | 1177 | * Complete the quota initialisation, post-log-replay component. |
| 1221 | */ | 1178 | */ |
| 1222 | error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags); | 1179 | error = XFS_QM_MOUNT(mp, quotamount, quotaflags); |
| 1223 | if (error) | 1180 | if (error) |
| 1224 | goto error4; | 1181 | goto error4; |
| 1225 | 1182 | ||
| @@ -1253,31 +1210,25 @@ xfs_mountfs( | |||
| 1253 | error3: | 1210 | error3: |
| 1254 | xfs_log_unmount_dealloc(mp); | 1211 | xfs_log_unmount_dealloc(mp); |
| 1255 | error2: | 1212 | error2: |
| 1256 | for (agno = 0; agno < sbp->sb_agcount; agno++) | 1213 | xfs_free_perag(mp); |
| 1257 | if (mp->m_perag[agno].pagb_list) | ||
| 1258 | kmem_free(mp->m_perag[agno].pagb_list, | ||
| 1259 | sizeof(xfs_perag_busy_t) * XFS_PAGB_NUM_SLOTS); | ||
| 1260 | kmem_free(mp->m_perag, sbp->sb_agcount * sizeof(xfs_perag_t)); | ||
| 1261 | mp->m_perag = NULL; | ||
| 1262 | /* FALLTHROUGH */ | ||
| 1263 | error1: | 1214 | error1: |
| 1264 | if (uuid_mounted) | 1215 | if (uuid_mounted) |
| 1265 | xfs_uuid_unmount(mp); | 1216 | uuid_table_remove(&mp->m_sb.sb_uuid); |
| 1266 | xfs_freesb(mp); | ||
| 1267 | return error; | 1217 | return error; |
| 1268 | } | 1218 | } |
| 1269 | 1219 | ||
| 1270 | /* | 1220 | /* |
| 1271 | * xfs_unmountfs | ||
| 1272 | * | ||
| 1273 | * This flushes out the inodes,dquots and the superblock, unmounts the | 1221 | * This flushes out the inodes,dquots and the superblock, unmounts the |
| 1274 | * log and makes sure that incore structures are freed. | 1222 | * log and makes sure that incore structures are freed. |
| 1275 | */ | 1223 | */ |
| 1276 | int | 1224 | void |
| 1277 | xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | 1225 | xfs_unmountfs( |
| 1226 | struct xfs_mount *mp) | ||
| 1278 | { | 1227 | { |
| 1279 | __uint64_t resblks; | 1228 | __uint64_t resblks; |
| 1280 | int error = 0; | 1229 | int error; |
| 1230 | |||
| 1231 | IRELE(mp->m_rootip); | ||
| 1281 | 1232 | ||
| 1282 | /* | 1233 | /* |
| 1283 | * We can potentially deadlock here if we have an inode cluster | 1234 | * We can potentially deadlock here if we have an inode cluster |
| @@ -1334,32 +1285,20 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr) | |||
| 1334 | xfs_unmountfs_wait(mp); /* wait for async bufs */ | 1285 | xfs_unmountfs_wait(mp); /* wait for async bufs */ |
| 1335 | xfs_log_unmount(mp); /* Done! No more fs ops. */ | 1286 | xfs_log_unmount(mp); /* Done! No more fs ops. */ |
| 1336 | 1287 | ||
| 1337 | xfs_freesb(mp); | ||
| 1338 | |||
| 1339 | /* | 1288 | /* |
| 1340 | * All inodes from this mount point should be freed. | 1289 | * All inodes from this mount point should be freed. |
| 1341 | */ | 1290 | */ |
| 1342 | ASSERT(mp->m_inodes == NULL); | 1291 | ASSERT(mp->m_inodes == NULL); |
| 1343 | 1292 | ||
| 1344 | xfs_unmountfs_close(mp, cr); | ||
| 1345 | if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) | 1293 | if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) |
| 1346 | xfs_uuid_unmount(mp); | 1294 | uuid_table_remove(&mp->m_sb.sb_uuid); |
| 1347 | 1295 | ||
| 1348 | #if defined(DEBUG) || defined(INDUCE_IO_ERROR) | 1296 | #if defined(DEBUG) |
| 1349 | xfs_errortag_clearall(mp, 0); | 1297 | xfs_errortag_clearall(mp, 0); |
| 1350 | #endif | 1298 | #endif |
| 1351 | xfs_mount_free(mp); | 1299 | xfs_free_perag(mp); |
| 1352 | return 0; | 1300 | if (mp->m_quotainfo) |
| 1353 | } | 1301 | XFS_QM_DONE(mp); |
| 1354 | |||
| 1355 | void | ||
| 1356 | xfs_unmountfs_close(xfs_mount_t *mp, struct cred *cr) | ||
| 1357 | { | ||
| 1358 | if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) | ||
| 1359 | xfs_free_buftarg(mp->m_logdev_targp, 1); | ||
| 1360 | if (mp->m_rtdev_targp) | ||
| 1361 | xfs_free_buftarg(mp->m_rtdev_targp, 1); | ||
| 1362 | xfs_free_buftarg(mp->m_ddev_targp, 0); | ||
| 1363 | } | 1302 | } |
| 1364 | 1303 | ||
| 1365 | STATIC void | 1304 | STATIC void |
| @@ -1905,16 +1844,6 @@ xfs_uuid_mount( | |||
| 1905 | } | 1844 | } |
| 1906 | 1845 | ||
| 1907 | /* | 1846 | /* |
| 1908 | * Remove filesystem from the UUID table. | ||
| 1909 | */ | ||
| 1910 | STATIC void | ||
| 1911 | xfs_uuid_unmount( | ||
| 1912 | xfs_mount_t *mp) | ||
| 1913 | { | ||
| 1914 | uuid_table_remove(&mp->m_sb.sb_uuid); | ||
| 1915 | } | ||
| 1916 | |||
| 1917 | /* | ||
| 1918 | * Used to log changes to the superblock unit and width fields which could | 1847 | * Used to log changes to the superblock unit and width fields which could |
| 1919 | * be altered by the mount options, as well as any potential sb_features2 | 1848 | * be altered by the mount options, as well as any potential sb_features2 |
| 1920 | * fixup. Only the first superblock is updated. | 1849 | * fixup. Only the first superblock is updated. |
| @@ -1928,7 +1857,8 @@ xfs_mount_log_sb( | |||
| 1928 | int error; | 1857 | int error; |
| 1929 | 1858 | ||
| 1930 | ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | | 1859 | ASSERT(fields & (XFS_SB_UNIT | XFS_SB_WIDTH | XFS_SB_UUID | |
| 1931 | XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2)); | 1860 | XFS_SB_FEATURES2 | XFS_SB_BAD_FEATURES2 | |
| 1861 | XFS_SB_VERSIONNUM)); | ||
| 1932 | 1862 | ||
| 1933 | tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); | 1863 | tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); |
| 1934 | error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, | 1864 | error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, |
| @@ -2109,7 +2039,7 @@ xfs_icsb_reinit_counters( | |||
| 2109 | xfs_icsb_unlock(mp); | 2039 | xfs_icsb_unlock(mp); |
| 2110 | } | 2040 | } |
| 2111 | 2041 | ||
| 2112 | STATIC void | 2042 | void |
| 2113 | xfs_icsb_destroy_counters( | 2043 | xfs_icsb_destroy_counters( |
| 2114 | xfs_mount_t *mp) | 2044 | xfs_mount_t *mp) |
| 2115 | { | 2045 | { |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 63e0693a358a..f3c1024b1241 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
| @@ -61,6 +61,7 @@ struct xfs_bmap_free; | |||
| 61 | struct xfs_extdelta; | 61 | struct xfs_extdelta; |
| 62 | struct xfs_swapext; | 62 | struct xfs_swapext; |
| 63 | struct xfs_mru_cache; | 63 | struct xfs_mru_cache; |
| 64 | struct xfs_nameops; | ||
| 64 | 65 | ||
| 65 | /* | 66 | /* |
| 66 | * Prototypes and functions for the Data Migration subsystem. | 67 | * Prototypes and functions for the Data Migration subsystem. |
| @@ -113,7 +114,7 @@ struct xfs_dqtrxops; | |||
| 113 | struct xfs_quotainfo; | 114 | struct xfs_quotainfo; |
| 114 | 115 | ||
| 115 | typedef int (*xfs_qminit_t)(struct xfs_mount *, uint *, uint *); | 116 | typedef int (*xfs_qminit_t)(struct xfs_mount *, uint *, uint *); |
| 116 | typedef int (*xfs_qmmount_t)(struct xfs_mount *, uint, uint, int); | 117 | typedef int (*xfs_qmmount_t)(struct xfs_mount *, uint, uint); |
| 117 | typedef int (*xfs_qmunmount_t)(struct xfs_mount *); | 118 | typedef int (*xfs_qmunmount_t)(struct xfs_mount *); |
| 118 | typedef void (*xfs_qmdone_t)(struct xfs_mount *); | 119 | typedef void (*xfs_qmdone_t)(struct xfs_mount *); |
| 119 | typedef void (*xfs_dqrele_t)(struct xfs_dquot *); | 120 | typedef void (*xfs_dqrele_t)(struct xfs_dquot *); |
| @@ -157,8 +158,8 @@ typedef struct xfs_qmops { | |||
| 157 | 158 | ||
| 158 | #define XFS_QM_INIT(mp, mnt, fl) \ | 159 | #define XFS_QM_INIT(mp, mnt, fl) \ |
| 159 | (*(mp)->m_qm_ops->xfs_qminit)(mp, mnt, fl) | 160 | (*(mp)->m_qm_ops->xfs_qminit)(mp, mnt, fl) |
| 160 | #define XFS_QM_MOUNT(mp, mnt, fl, mfsi_flags) \ | 161 | #define XFS_QM_MOUNT(mp, mnt, fl) \ |
| 161 | (*(mp)->m_qm_ops->xfs_qmmount)(mp, mnt, fl, mfsi_flags) | 162 | (*(mp)->m_qm_ops->xfs_qmmount)(mp, mnt, fl) |
| 162 | #define XFS_QM_UNMOUNT(mp) \ | 163 | #define XFS_QM_UNMOUNT(mp) \ |
| 163 | (*(mp)->m_qm_ops->xfs_qmunmount)(mp) | 164 | (*(mp)->m_qm_ops->xfs_qmunmount)(mp) |
| 164 | #define XFS_QM_DONE(mp) \ | 165 | #define XFS_QM_DONE(mp) \ |
| @@ -210,12 +211,14 @@ typedef struct xfs_icsb_cnts { | |||
| 210 | 211 | ||
| 211 | extern int xfs_icsb_init_counters(struct xfs_mount *); | 212 | extern int xfs_icsb_init_counters(struct xfs_mount *); |
| 212 | extern void xfs_icsb_reinit_counters(struct xfs_mount *); | 213 | extern void xfs_icsb_reinit_counters(struct xfs_mount *); |
| 214 | extern void xfs_icsb_destroy_counters(struct xfs_mount *); | ||
| 213 | extern void xfs_icsb_sync_counters(struct xfs_mount *, int); | 215 | extern void xfs_icsb_sync_counters(struct xfs_mount *, int); |
| 214 | extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int); | 216 | extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int); |
| 215 | 217 | ||
| 216 | #else | 218 | #else |
| 217 | #define xfs_icsb_init_counters(mp) (0) | 219 | #define xfs_icsb_init_counters(mp) (0) |
| 218 | #define xfs_icsb_reinit_counters(mp) do { } while (0) | 220 | #define xfs_icsb_destroy_counters(mp) do { } while (0) |
| 221 | #define xfs_icsb_reinit_counters(mp) do { } while (0) | ||
| 219 | #define xfs_icsb_sync_counters(mp, flags) do { } while (0) | 222 | #define xfs_icsb_sync_counters(mp, flags) do { } while (0) |
| 220 | #define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0) | 223 | #define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0) |
| 221 | #endif | 224 | #endif |
| @@ -313,6 +316,7 @@ typedef struct xfs_mount { | |||
| 313 | __uint8_t m_inode_quiesce;/* call quiesce on new inodes. | 316 | __uint8_t m_inode_quiesce;/* call quiesce on new inodes. |
| 314 | field governed by m_ilock */ | 317 | field governed by m_ilock */ |
| 315 | __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ | 318 | __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ |
| 319 | const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */ | ||
| 316 | int m_dirblksize; /* directory block sz--bytes */ | 320 | int m_dirblksize; /* directory block sz--bytes */ |
| 317 | int m_dirblkfsbs; /* directory block sz--fsbs */ | 321 | int m_dirblkfsbs; /* directory block sz--fsbs */ |
| 318 | xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ | 322 | xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ |
| @@ -378,6 +382,7 @@ typedef struct xfs_mount { | |||
| 378 | counters */ | 382 | counters */ |
| 379 | #define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams | 383 | #define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams |
| 380 | allocator */ | 384 | allocator */ |
| 385 | #define XFS_MOUNT_NOATTR2 (1ULL << 25) /* disable use of attr2 format */ | ||
| 381 | 386 | ||
| 382 | 387 | ||
| 383 | /* | 388 | /* |
| @@ -437,13 +442,6 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, | |||
| 437 | /* | 442 | /* |
| 438 | * Flags for xfs_mountfs | 443 | * Flags for xfs_mountfs |
| 439 | */ | 444 | */ |
| 440 | #define XFS_MFSI_SECOND 0x01 /* Secondary mount -- skip stuff */ | ||
| 441 | #define XFS_MFSI_CLIENT 0x02 /* Is a client -- skip lots of stuff */ | ||
| 442 | /* XFS_MFSI_RRINODES */ | ||
| 443 | #define XFS_MFSI_NOUNLINK 0x08 /* Skip unlinked inode processing in */ | ||
| 444 | /* log recovery */ | ||
| 445 | #define XFS_MFSI_NO_QUOTACHECK 0x10 /* Skip quotacheck processing */ | ||
| 446 | /* XFS_MFSI_CONVERT_SUNIT */ | ||
| 447 | #define XFS_MFSI_QUIET 0x40 /* Be silent if mount errors found */ | 445 | #define XFS_MFSI_QUIET 0x40 /* Be silent if mount errors found */ |
| 448 | 446 | ||
| 449 | #define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d) | 447 | #define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d) |
| @@ -510,15 +508,12 @@ typedef struct xfs_mod_sb { | |||
| 510 | #define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock)) | 508 | #define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock)) |
| 511 | #define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) | 509 | #define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) |
| 512 | 510 | ||
| 513 | extern xfs_mount_t *xfs_mount_init(void); | ||
| 514 | extern void xfs_mod_sb(xfs_trans_t *, __int64_t); | 511 | extern void xfs_mod_sb(xfs_trans_t *, __int64_t); |
| 515 | extern int xfs_log_sbcount(xfs_mount_t *, uint); | 512 | extern int xfs_log_sbcount(xfs_mount_t *, uint); |
| 516 | extern void xfs_mount_free(xfs_mount_t *mp); | 513 | extern int xfs_mountfs(xfs_mount_t *mp); |
| 517 | extern int xfs_mountfs(xfs_mount_t *mp, int); | ||
| 518 | extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); | 514 | extern void xfs_mountfs_check_barriers(xfs_mount_t *mp); |
| 519 | 515 | ||
| 520 | extern int xfs_unmountfs(xfs_mount_t *, struct cred *); | 516 | extern void xfs_unmountfs(xfs_mount_t *); |
| 521 | extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); | ||
| 522 | extern int xfs_unmountfs_writesb(xfs_mount_t *); | 517 | extern int xfs_unmountfs_writesb(xfs_mount_t *); |
| 523 | extern int xfs_unmount_flush(xfs_mount_t *, int); | 518 | extern int xfs_unmount_flush(xfs_mount_t *, int); |
| 524 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); | 519 | extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); |
| @@ -544,9 +539,6 @@ extern void xfs_qmops_put(struct xfs_mount *); | |||
| 544 | 539 | ||
| 545 | extern struct xfs_dmops xfs_dmcore_xfs; | 540 | extern struct xfs_dmops xfs_dmcore_xfs; |
| 546 | 541 | ||
| 547 | extern int xfs_init(void); | ||
| 548 | extern void xfs_cleanup(void); | ||
| 549 | |||
| 550 | #endif /* __KERNEL__ */ | 542 | #endif /* __KERNEL__ */ |
| 551 | 543 | ||
| 552 | #endif /* __XFS_MOUNT_H__ */ | 544 | #endif /* __XFS_MOUNT_H__ */ |
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index a0b2c0a2589a..afee7eb24323 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c | |||
| @@ -307,15 +307,18 @@ xfs_mru_cache_init(void) | |||
| 307 | xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t), | 307 | xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t), |
| 308 | "xfs_mru_cache_elem"); | 308 | "xfs_mru_cache_elem"); |
| 309 | if (!xfs_mru_elem_zone) | 309 | if (!xfs_mru_elem_zone) |
| 310 | return ENOMEM; | 310 | goto out; |
| 311 | 311 | ||
| 312 | xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache"); | 312 | xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache"); |
| 313 | if (!xfs_mru_reap_wq) { | 313 | if (!xfs_mru_reap_wq) |
| 314 | kmem_zone_destroy(xfs_mru_elem_zone); | 314 | goto out_destroy_mru_elem_zone; |
| 315 | return ENOMEM; | ||
| 316 | } | ||
| 317 | 315 | ||
| 318 | return 0; | 316 | return 0; |
| 317 | |||
| 318 | out_destroy_mru_elem_zone: | ||
| 319 | kmem_zone_destroy(xfs_mru_elem_zone); | ||
| 320 | out: | ||
| 321 | return -ENOMEM; | ||
| 319 | } | 322 | } |
| 320 | 323 | ||
| 321 | void | 324 | void |
| @@ -382,9 +385,9 @@ xfs_mru_cache_create( | |||
| 382 | 385 | ||
| 383 | exit: | 386 | exit: |
| 384 | if (err && mru && mru->lists) | 387 | if (err && mru && mru->lists) |
| 385 | kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists)); | 388 | kmem_free(mru->lists); |
| 386 | if (err && mru) | 389 | if (err && mru) |
| 387 | kmem_free(mru, sizeof(*mru)); | 390 | kmem_free(mru); |
| 388 | 391 | ||
| 389 | return err; | 392 | return err; |
| 390 | } | 393 | } |
| @@ -424,8 +427,8 @@ xfs_mru_cache_destroy( | |||
| 424 | 427 | ||
| 425 | xfs_mru_cache_flush(mru); | 428 | xfs_mru_cache_flush(mru); |
| 426 | 429 | ||
| 427 | kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists)); | 430 | kmem_free(mru->lists); |
| 428 | kmem_free(mru, sizeof(*mru)); | 431 | kmem_free(mru); |
| 429 | } | 432 | } |
| 430 | 433 | ||
| 431 | /* | 434 | /* |
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index d8063e1ad298..d700dacdb10e 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c | |||
| @@ -336,22 +336,18 @@ xfs_rename( | |||
| 336 | ASSERT(error != EEXIST); | 336 | ASSERT(error != EEXIST); |
| 337 | if (error) | 337 | if (error) |
| 338 | goto abort_return; | 338 | goto abort_return; |
| 339 | xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
| 340 | |||
| 341 | } else { | ||
| 342 | /* | ||
| 343 | * We always want to hit the ctime on the source inode. | ||
| 344 | * We do it in the if clause above for the 'new_parent && | ||
| 345 | * src_is_directory' case, and here we get all the other | ||
| 346 | * cases. This isn't strictly required by the standards | ||
| 347 | * since the source inode isn't really being changed, | ||
| 348 | * but old unix file systems did it and some incremental | ||
| 349 | * backup programs won't work without it. | ||
| 350 | */ | ||
| 351 | xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG); | ||
| 352 | } | 339 | } |
| 353 | 340 | ||
| 354 | /* | 341 | /* |
| 342 | * We always want to hit the ctime on the source inode. | ||
| 343 | * | ||
| 344 | * This isn't strictly required by the standards since the source | ||
| 345 | * inode isn't really being changed, but old unix file systems did | ||
| 346 | * it and some incremental backup programs won't work without it. | ||
| 347 | */ | ||
| 348 | xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG); | ||
| 349 | |||
| 350 | /* | ||
| 355 | * Adjust the link count on src_dp. This is necessary when | 351 | * Adjust the link count on src_dp. This is necessary when |
| 356 | * renaming a directory, either within one parent when | 352 | * renaming a directory, either within one parent when |
| 357 | * the target existed, or across two parent directories. | 353 | * the target existed, or across two parent directories. |
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index a0dc6e5bc5b9..e2f68de16159 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c | |||
| @@ -74,18 +74,6 @@ STATIC int xfs_rtmodify_summary(xfs_mount_t *, xfs_trans_t *, int, | |||
| 74 | */ | 74 | */ |
| 75 | 75 | ||
| 76 | /* | 76 | /* |
| 77 | * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. | ||
| 78 | */ | ||
| 79 | STATIC int | ||
| 80 | xfs_lowbit32( | ||
| 81 | __uint32_t v) | ||
| 82 | { | ||
| 83 | if (v) | ||
| 84 | return ffs(v) - 1; | ||
| 85 | return -1; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Allocate space to the bitmap or summary file, and zero it, for growfs. | 77 | * Allocate space to the bitmap or summary file, and zero it, for growfs. |
| 90 | */ | 78 | */ |
| 91 | STATIC int /* error */ | 79 | STATIC int /* error */ |
| @@ -450,6 +438,7 @@ xfs_rtallocate_extent_near( | |||
| 450 | } | 438 | } |
| 451 | bbno = XFS_BITTOBLOCK(mp, bno); | 439 | bbno = XFS_BITTOBLOCK(mp, bno); |
| 452 | i = 0; | 440 | i = 0; |
| 441 | ASSERT(minlen != 0); | ||
| 453 | log2len = xfs_highbit32(minlen); | 442 | log2len = xfs_highbit32(minlen); |
| 454 | /* | 443 | /* |
| 455 | * Loop over all bitmap blocks (bbno + i is current block). | 444 | * Loop over all bitmap blocks (bbno + i is current block). |
| @@ -618,6 +607,8 @@ xfs_rtallocate_extent_size( | |||
| 618 | xfs_suminfo_t sum; /* summary information for extents */ | 607 | xfs_suminfo_t sum; /* summary information for extents */ |
| 619 | 608 | ||
| 620 | ASSERT(minlen % prod == 0 && maxlen % prod == 0); | 609 | ASSERT(minlen % prod == 0 && maxlen % prod == 0); |
| 610 | ASSERT(maxlen != 0); | ||
| 611 | |||
| 621 | /* | 612 | /* |
| 622 | * Loop over all the levels starting with maxlen. | 613 | * Loop over all the levels starting with maxlen. |
| 623 | * At each level, look at all the bitmap blocks, to see if there | 614 | * At each level, look at all the bitmap blocks, to see if there |
| @@ -675,6 +666,9 @@ xfs_rtallocate_extent_size( | |||
| 675 | *rtblock = NULLRTBLOCK; | 666 | *rtblock = NULLRTBLOCK; |
| 676 | return 0; | 667 | return 0; |
| 677 | } | 668 | } |
| 669 | ASSERT(minlen != 0); | ||
| 670 | ASSERT(maxlen != 0); | ||
| 671 | |||
| 678 | /* | 672 | /* |
| 679 | * Loop over sizes, from maxlen down to minlen. | 673 | * Loop over sizes, from maxlen down to minlen. |
| 680 | * This time, when we do the allocations, allow smaller ones | 674 | * This time, when we do the allocations, allow smaller ones |
| @@ -1961,6 +1955,7 @@ xfs_growfs_rt( | |||
| 1961 | nsbp->sb_blocksize * nsbp->sb_rextsize); | 1955 | nsbp->sb_blocksize * nsbp->sb_rextsize); |
| 1962 | nsbp->sb_rextents = nsbp->sb_rblocks; | 1956 | nsbp->sb_rextents = nsbp->sb_rblocks; |
| 1963 | do_div(nsbp->sb_rextents, nsbp->sb_rextsize); | 1957 | do_div(nsbp->sb_rextents, nsbp->sb_rextsize); |
| 1958 | ASSERT(nsbp->sb_rextents != 0); | ||
| 1964 | nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); | 1959 | nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); |
| 1965 | nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; | 1960 | nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; |
| 1966 | nrsumsize = | 1961 | nrsumsize = |
| @@ -2062,7 +2057,7 @@ xfs_growfs_rt( | |||
| 2062 | /* | 2057 | /* |
| 2063 | * Free the fake mp structure. | 2058 | * Free the fake mp structure. |
| 2064 | */ | 2059 | */ |
| 2065 | kmem_free(nmp, sizeof(*nmp)); | 2060 | kmem_free(nmp); |
| 2066 | 2061 | ||
| 2067 | return error; | 2062 | return error; |
| 2068 | } | 2063 | } |
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index b0f31c09a76d..3a82576dde9a 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c | |||
| @@ -314,7 +314,7 @@ xfs_bioerror_relse( | |||
| 314 | * ASYNC buffers. | 314 | * ASYNC buffers. |
| 315 | */ | 315 | */ |
| 316 | XFS_BUF_ERROR(bp, EIO); | 316 | XFS_BUF_ERROR(bp, EIO); |
| 317 | XFS_BUF_V_IODONESEMA(bp); | 317 | XFS_BUF_FINISH_IOWAIT(bp); |
| 318 | } else { | 318 | } else { |
| 319 | xfs_buf_relse(bp); | 319 | xfs_buf_relse(bp); |
| 320 | } | 320 | } |
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h index d904efe7f871..3f8cf1587f4c 100644 --- a/fs/xfs/xfs_sb.h +++ b/fs/xfs/xfs_sb.h | |||
| @@ -46,10 +46,12 @@ struct xfs_mount; | |||
| 46 | #define XFS_SB_VERSION_SECTORBIT 0x0800 | 46 | #define XFS_SB_VERSION_SECTORBIT 0x0800 |
| 47 | #define XFS_SB_VERSION_EXTFLGBIT 0x1000 | 47 | #define XFS_SB_VERSION_EXTFLGBIT 0x1000 |
| 48 | #define XFS_SB_VERSION_DIRV2BIT 0x2000 | 48 | #define XFS_SB_VERSION_DIRV2BIT 0x2000 |
| 49 | #define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */ | ||
| 49 | #define XFS_SB_VERSION_MOREBITSBIT 0x8000 | 50 | #define XFS_SB_VERSION_MOREBITSBIT 0x8000 |
| 50 | #define XFS_SB_VERSION_OKSASHFBITS \ | 51 | #define XFS_SB_VERSION_OKSASHFBITS \ |
| 51 | (XFS_SB_VERSION_EXTFLGBIT | \ | 52 | (XFS_SB_VERSION_EXTFLGBIT | \ |
| 52 | XFS_SB_VERSION_DIRV2BIT) | 53 | XFS_SB_VERSION_DIRV2BIT | \ |
| 54 | XFS_SB_VERSION_BORGBIT) | ||
| 53 | #define XFS_SB_VERSION_OKREALFBITS \ | 55 | #define XFS_SB_VERSION_OKREALFBITS \ |
| 54 | (XFS_SB_VERSION_ATTRBIT | \ | 56 | (XFS_SB_VERSION_ATTRBIT | \ |
| 55 | XFS_SB_VERSION_NLINKBIT | \ | 57 | XFS_SB_VERSION_NLINKBIT | \ |
| @@ -437,6 +439,12 @@ static inline int xfs_sb_version_hassector(xfs_sb_t *sbp) | |||
| 437 | ((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT); | 439 | ((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT); |
| 438 | } | 440 | } |
| 439 | 441 | ||
| 442 | static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp) | ||
| 443 | { | ||
| 444 | return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ | ||
| 445 | (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT); | ||
| 446 | } | ||
| 447 | |||
| 440 | static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp) | 448 | static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp) |
| 441 | { | 449 | { |
| 442 | return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ | 450 | return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ |
| @@ -473,6 +481,13 @@ static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp) | |||
| 473 | ((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT))); | 481 | ((sbp)->sb_features2 | XFS_SB_VERSION2_ATTR2BIT))); |
| 474 | } | 482 | } |
| 475 | 483 | ||
| 484 | static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp) | ||
| 485 | { | ||
| 486 | sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT; | ||
| 487 | if (!sbp->sb_features2) | ||
| 488 | sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT; | ||
| 489 | } | ||
| 490 | |||
| 476 | /* | 491 | /* |
| 477 | * end of superblock version macros | 492 | * end of superblock version macros |
| 478 | */ | 493 | */ |
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 140386434aa3..4e1c22a23be5 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
| @@ -43,6 +43,7 @@ | |||
| 43 | #include "xfs_quota.h" | 43 | #include "xfs_quota.h" |
| 44 | #include "xfs_trans_priv.h" | 44 | #include "xfs_trans_priv.h" |
| 45 | #include "xfs_trans_space.h" | 45 | #include "xfs_trans_space.h" |
| 46 | #include "xfs_inode_item.h" | ||
| 46 | 47 | ||
| 47 | 48 | ||
| 48 | STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *); | 49 | STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *); |
| @@ -253,7 +254,7 @@ _xfs_trans_alloc( | |||
| 253 | tp->t_mountp = mp; | 254 | tp->t_mountp = mp; |
| 254 | tp->t_items_free = XFS_LIC_NUM_SLOTS; | 255 | tp->t_items_free = XFS_LIC_NUM_SLOTS; |
| 255 | tp->t_busy_free = XFS_LBC_NUM_SLOTS; | 256 | tp->t_busy_free = XFS_LBC_NUM_SLOTS; |
| 256 | XFS_LIC_INIT(&(tp->t_items)); | 257 | xfs_lic_init(&(tp->t_items)); |
| 257 | XFS_LBC_INIT(&(tp->t_busy)); | 258 | XFS_LBC_INIT(&(tp->t_busy)); |
| 258 | return tp; | 259 | return tp; |
| 259 | } | 260 | } |
| @@ -282,7 +283,7 @@ xfs_trans_dup( | |||
| 282 | ntp->t_mountp = tp->t_mountp; | 283 | ntp->t_mountp = tp->t_mountp; |
| 283 | ntp->t_items_free = XFS_LIC_NUM_SLOTS; | 284 | ntp->t_items_free = XFS_LIC_NUM_SLOTS; |
| 284 | ntp->t_busy_free = XFS_LBC_NUM_SLOTS; | 285 | ntp->t_busy_free = XFS_LBC_NUM_SLOTS; |
| 285 | XFS_LIC_INIT(&(ntp->t_items)); | 286 | xfs_lic_init(&(ntp->t_items)); |
| 286 | XFS_LBC_INIT(&(ntp->t_busy)); | 287 | XFS_LBC_INIT(&(ntp->t_busy)); |
| 287 | 288 | ||
| 288 | ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); | 289 | ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); |
| @@ -889,7 +890,7 @@ shut_us_down: | |||
| 889 | 890 | ||
| 890 | tp->t_commit_lsn = commit_lsn; | 891 | tp->t_commit_lsn = commit_lsn; |
| 891 | if (nvec > XFS_TRANS_LOGVEC_COUNT) { | 892 | if (nvec > XFS_TRANS_LOGVEC_COUNT) { |
| 892 | kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t)); | 893 | kmem_free(log_vector); |
| 893 | } | 894 | } |
| 894 | 895 | ||
| 895 | /* | 896 | /* |
| @@ -1169,7 +1170,7 @@ xfs_trans_cancel( | |||
| 1169 | while (licp != NULL) { | 1170 | while (licp != NULL) { |
| 1170 | lidp = licp->lic_descs; | 1171 | lidp = licp->lic_descs; |
| 1171 | for (i = 0; i < licp->lic_unused; i++, lidp++) { | 1172 | for (i = 0; i < licp->lic_unused; i++, lidp++) { |
| 1172 | if (XFS_LIC_ISFREE(licp, i)) { | 1173 | if (xfs_lic_isfree(licp, i)) { |
| 1173 | continue; | 1174 | continue; |
| 1174 | } | 1175 | } |
| 1175 | 1176 | ||
| @@ -1216,6 +1217,68 @@ xfs_trans_free( | |||
| 1216 | kmem_zone_free(xfs_trans_zone, tp); | 1217 | kmem_zone_free(xfs_trans_zone, tp); |
| 1217 | } | 1218 | } |
| 1218 | 1219 | ||
| 1220 | /* | ||
| 1221 | * Roll from one trans in the sequence of PERMANENT transactions to | ||
| 1222 | * the next: permanent transactions are only flushed out when | ||
| 1223 | * committed with XFS_TRANS_RELEASE_LOG_RES, but we still want as soon | ||
| 1224 | * as possible to let chunks of it go to the log. So we commit the | ||
| 1225 | * chunk we've been working on and get a new transaction to continue. | ||
| 1226 | */ | ||
| 1227 | int | ||
| 1228 | xfs_trans_roll( | ||
| 1229 | struct xfs_trans **tpp, | ||
| 1230 | struct xfs_inode *dp) | ||
| 1231 | { | ||
| 1232 | struct xfs_trans *trans; | ||
| 1233 | unsigned int logres, count; | ||
| 1234 | int error; | ||
| 1235 | |||
| 1236 | /* | ||
| 1237 | * Ensure that the inode is always logged. | ||
| 1238 | */ | ||
| 1239 | trans = *tpp; | ||
| 1240 | xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); | ||
| 1241 | |||
| 1242 | /* | ||
| 1243 | * Copy the critical parameters from one trans to the next. | ||
| 1244 | */ | ||
| 1245 | logres = trans->t_log_res; | ||
| 1246 | count = trans->t_log_count; | ||
| 1247 | *tpp = xfs_trans_dup(trans); | ||
| 1248 | |||
| 1249 | /* | ||
| 1250 | * Commit the current transaction. | ||
| 1251 | * If this commit failed, then it'd just unlock those items that | ||
| 1252 | * are not marked ihold. That also means that a filesystem shutdown | ||
| 1253 | * is in progress. The caller takes the responsibility to cancel | ||
| 1254 | * the duplicate transaction that gets returned. | ||
| 1255 | */ | ||
| 1256 | error = xfs_trans_commit(trans, 0); | ||
| 1257 | if (error) | ||
| 1258 | return (error); | ||
| 1259 | |||
| 1260 | trans = *tpp; | ||
| 1261 | |||
| 1262 | /* | ||
| 1263 | * Reserve space in the log for th next transaction. | ||
| 1264 | * This also pushes items in the "AIL", the list of logged items, | ||
| 1265 | * out to disk if they are taking up space at the tail of the log | ||
| 1266 | * that we want to use. This requires that either nothing be locked | ||
| 1267 | * across this call, or that anything that is locked be logged in | ||
| 1268 | * the prior and the next transactions. | ||
| 1269 | */ | ||
| 1270 | error = xfs_trans_reserve(trans, 0, logres, 0, | ||
| 1271 | XFS_TRANS_PERM_LOG_RES, count); | ||
| 1272 | /* | ||
| 1273 | * Ensure that the inode is in the new transaction and locked. | ||
| 1274 | */ | ||
| 1275 | if (error) | ||
| 1276 | return error; | ||
| 1277 | |||
| 1278 | xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); | ||
| 1279 | xfs_trans_ihold(trans, dp); | ||
| 1280 | return 0; | ||
| 1281 | } | ||
| 1219 | 1282 | ||
| 1220 | /* | 1283 | /* |
| 1221 | * THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item(). | 1284 | * THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item(). |
| @@ -1253,7 +1316,7 @@ xfs_trans_committed( | |||
| 1253 | * Special case the chunk embedded in the transaction. | 1316 | * Special case the chunk embedded in the transaction. |
| 1254 | */ | 1317 | */ |
| 1255 | licp = &(tp->t_items); | 1318 | licp = &(tp->t_items); |
| 1256 | if (!(XFS_LIC_ARE_ALL_FREE(licp))) { | 1319 | if (!(xfs_lic_are_all_free(licp))) { |
| 1257 | xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); | 1320 | xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); |
| 1258 | } | 1321 | } |
| 1259 | 1322 | ||
| @@ -1262,10 +1325,10 @@ xfs_trans_committed( | |||
| 1262 | */ | 1325 | */ |
| 1263 | licp = licp->lic_next; | 1326 | licp = licp->lic_next; |
| 1264 | while (licp != NULL) { | 1327 | while (licp != NULL) { |
| 1265 | ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); | 1328 | ASSERT(!xfs_lic_are_all_free(licp)); |
| 1266 | xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); | 1329 | xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); |
| 1267 | next_licp = licp->lic_next; | 1330 | next_licp = licp->lic_next; |
| 1268 | kmem_free(licp, sizeof(xfs_log_item_chunk_t)); | 1331 | kmem_free(licp); |
| 1269 | licp = next_licp; | 1332 | licp = next_licp; |
| 1270 | } | 1333 | } |
| 1271 | 1334 | ||
| @@ -1325,7 +1388,7 @@ xfs_trans_chunk_committed( | |||
| 1325 | 1388 | ||
| 1326 | lidp = licp->lic_descs; | 1389 | lidp = licp->lic_descs; |
| 1327 | for (i = 0; i < licp->lic_unused; i++, lidp++) { | 1390 | for (i = 0; i < licp->lic_unused; i++, lidp++) { |
| 1328 | if (XFS_LIC_ISFREE(licp, i)) { | 1391 | if (xfs_lic_isfree(licp, i)) { |
| 1329 | continue; | 1392 | continue; |
| 1330 | } | 1393 | } |
| 1331 | 1394 | ||
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 0804207c7391..74c80bd2b0ec 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h | |||
| @@ -210,62 +210,52 @@ typedef struct xfs_log_item_chunk { | |||
| 210 | * lic_unused to the right value (0 matches all free). The | 210 | * lic_unused to the right value (0 matches all free). The |
| 211 | * lic_descs.lid_index values are set up as each desc is allocated. | 211 | * lic_descs.lid_index values are set up as each desc is allocated. |
| 212 | */ | 212 | */ |
| 213 | #define XFS_LIC_INIT(cp) xfs_lic_init(cp) | ||
| 214 | static inline void xfs_lic_init(xfs_log_item_chunk_t *cp) | 213 | static inline void xfs_lic_init(xfs_log_item_chunk_t *cp) |
| 215 | { | 214 | { |
| 216 | cp->lic_free = XFS_LIC_FREEMASK; | 215 | cp->lic_free = XFS_LIC_FREEMASK; |
| 217 | } | 216 | } |
| 218 | 217 | ||
| 219 | #define XFS_LIC_INIT_SLOT(cp,slot) xfs_lic_init_slot(cp, slot) | ||
| 220 | static inline void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot) | 218 | static inline void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot) |
| 221 | { | 219 | { |
| 222 | cp->lic_descs[slot].lid_index = (unsigned char)(slot); | 220 | cp->lic_descs[slot].lid_index = (unsigned char)(slot); |
| 223 | } | 221 | } |
| 224 | 222 | ||
| 225 | #define XFS_LIC_VACANCY(cp) xfs_lic_vacancy(cp) | ||
| 226 | static inline int xfs_lic_vacancy(xfs_log_item_chunk_t *cp) | 223 | static inline int xfs_lic_vacancy(xfs_log_item_chunk_t *cp) |
| 227 | { | 224 | { |
| 228 | return cp->lic_free & XFS_LIC_FREEMASK; | 225 | return cp->lic_free & XFS_LIC_FREEMASK; |
| 229 | } | 226 | } |
| 230 | 227 | ||
| 231 | #define XFS_LIC_ALL_FREE(cp) xfs_lic_all_free(cp) | ||
| 232 | static inline void xfs_lic_all_free(xfs_log_item_chunk_t *cp) | 228 | static inline void xfs_lic_all_free(xfs_log_item_chunk_t *cp) |
| 233 | { | 229 | { |
| 234 | cp->lic_free = XFS_LIC_FREEMASK; | 230 | cp->lic_free = XFS_LIC_FREEMASK; |
| 235 | } | 231 | } |
| 236 | 232 | ||
| 237 | #define XFS_LIC_ARE_ALL_FREE(cp) xfs_lic_are_all_free(cp) | ||
| 238 | static inline int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp) | 233 | static inline int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp) |
| 239 | { | 234 | { |
| 240 | return ((cp->lic_free & XFS_LIC_FREEMASK) == XFS_LIC_FREEMASK); | 235 | return ((cp->lic_free & XFS_LIC_FREEMASK) == XFS_LIC_FREEMASK); |
| 241 | } | 236 | } |
| 242 | 237 | ||
| 243 | #define XFS_LIC_ISFREE(cp,slot) xfs_lic_isfree(cp,slot) | ||
| 244 | static inline int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot) | 238 | static inline int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot) |
| 245 | { | 239 | { |
| 246 | return (cp->lic_free & (1 << slot)); | 240 | return (cp->lic_free & (1 << slot)); |
| 247 | } | 241 | } |
| 248 | 242 | ||
| 249 | #define XFS_LIC_CLAIM(cp,slot) xfs_lic_claim(cp,slot) | ||
| 250 | static inline void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot) | 243 | static inline void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot) |
| 251 | { | 244 | { |
| 252 | cp->lic_free &= ~(1 << slot); | 245 | cp->lic_free &= ~(1 << slot); |
| 253 | } | 246 | } |
| 254 | 247 | ||
| 255 | #define XFS_LIC_RELSE(cp,slot) xfs_lic_relse(cp,slot) | ||
| 256 | static inline void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot) | 248 | static inline void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot) |
| 257 | { | 249 | { |
| 258 | cp->lic_free |= 1 << slot; | 250 | cp->lic_free |= 1 << slot; |
| 259 | } | 251 | } |
| 260 | 252 | ||
| 261 | #define XFS_LIC_SLOT(cp,slot) xfs_lic_slot(cp,slot) | ||
| 262 | static inline xfs_log_item_desc_t * | 253 | static inline xfs_log_item_desc_t * |
| 263 | xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot) | 254 | xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot) |
| 264 | { | 255 | { |
| 265 | return &(cp->lic_descs[slot]); | 256 | return &(cp->lic_descs[slot]); |
| 266 | } | 257 | } |
| 267 | 258 | ||
| 268 | #define XFS_LIC_DESC_TO_SLOT(dp) xfs_lic_desc_to_slot(dp) | ||
| 269 | static inline int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp) | 259 | static inline int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp) |
| 270 | { | 260 | { |
| 271 | return (uint)dp->lid_index; | 261 | return (uint)dp->lid_index; |
| @@ -278,7 +268,6 @@ static inline int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp) | |||
| 278 | * All of this yields the address of the chunk, which is | 268 | * All of this yields the address of the chunk, which is |
| 279 | * cast to a chunk pointer. | 269 | * cast to a chunk pointer. |
| 280 | */ | 270 | */ |
| 281 | #define XFS_LIC_DESC_TO_CHUNK(dp) xfs_lic_desc_to_chunk(dp) | ||
| 282 | static inline xfs_log_item_chunk_t * | 271 | static inline xfs_log_item_chunk_t * |
| 283 | xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp) | 272 | xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp) |
| 284 | { | 273 | { |
| @@ -986,6 +975,7 @@ int _xfs_trans_commit(xfs_trans_t *, | |||
| 986 | int *); | 975 | int *); |
| 987 | #define xfs_trans_commit(tp, flags) _xfs_trans_commit(tp, flags, NULL) | 976 | #define xfs_trans_commit(tp, flags) _xfs_trans_commit(tp, flags, NULL) |
| 988 | void xfs_trans_cancel(xfs_trans_t *, int); | 977 | void xfs_trans_cancel(xfs_trans_t *, int); |
| 978 | int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); | ||
| 989 | int xfs_trans_ail_init(struct xfs_mount *); | 979 | int xfs_trans_ail_init(struct xfs_mount *); |
| 990 | void xfs_trans_ail_destroy(struct xfs_mount *); | 980 | void xfs_trans_ail_destroy(struct xfs_mount *); |
| 991 | void xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); | 981 | void xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); |
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c index cb0c5839154b..4e855b5ced66 100644 --- a/fs/xfs/xfs_trans_buf.c +++ b/fs/xfs/xfs_trans_buf.c | |||
| @@ -1021,16 +1021,16 @@ xfs_trans_buf_item_match( | |||
| 1021 | bp = NULL; | 1021 | bp = NULL; |
| 1022 | len = BBTOB(len); | 1022 | len = BBTOB(len); |
| 1023 | licp = &tp->t_items; | 1023 | licp = &tp->t_items; |
| 1024 | if (!XFS_LIC_ARE_ALL_FREE(licp)) { | 1024 | if (!xfs_lic_are_all_free(licp)) { |
| 1025 | for (i = 0; i < licp->lic_unused; i++) { | 1025 | for (i = 0; i < licp->lic_unused; i++) { |
| 1026 | /* | 1026 | /* |
| 1027 | * Skip unoccupied slots. | 1027 | * Skip unoccupied slots. |
| 1028 | */ | 1028 | */ |
| 1029 | if (XFS_LIC_ISFREE(licp, i)) { | 1029 | if (xfs_lic_isfree(licp, i)) { |
| 1030 | continue; | 1030 | continue; |
| 1031 | } | 1031 | } |
| 1032 | 1032 | ||
| 1033 | lidp = XFS_LIC_SLOT(licp, i); | 1033 | lidp = xfs_lic_slot(licp, i); |
| 1034 | blip = (xfs_buf_log_item_t *)lidp->lid_item; | 1034 | blip = (xfs_buf_log_item_t *)lidp->lid_item; |
| 1035 | if (blip->bli_item.li_type != XFS_LI_BUF) { | 1035 | if (blip->bli_item.li_type != XFS_LI_BUF) { |
| 1036 | continue; | 1036 | continue; |
| @@ -1074,7 +1074,7 @@ xfs_trans_buf_item_match_all( | |||
| 1074 | bp = NULL; | 1074 | bp = NULL; |
| 1075 | len = BBTOB(len); | 1075 | len = BBTOB(len); |
| 1076 | for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) { | 1076 | for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) { |
| 1077 | if (XFS_LIC_ARE_ALL_FREE(licp)) { | 1077 | if (xfs_lic_are_all_free(licp)) { |
| 1078 | ASSERT(licp == &tp->t_items); | 1078 | ASSERT(licp == &tp->t_items); |
| 1079 | ASSERT(licp->lic_next == NULL); | 1079 | ASSERT(licp->lic_next == NULL); |
| 1080 | return NULL; | 1080 | return NULL; |
| @@ -1083,11 +1083,11 @@ xfs_trans_buf_item_match_all( | |||
| 1083 | /* | 1083 | /* |
| 1084 | * Skip unoccupied slots. | 1084 | * Skip unoccupied slots. |
| 1085 | */ | 1085 | */ |
| 1086 | if (XFS_LIC_ISFREE(licp, i)) { | 1086 | if (xfs_lic_isfree(licp, i)) { |
| 1087 | continue; | 1087 | continue; |
| 1088 | } | 1088 | } |
| 1089 | 1089 | ||
| 1090 | lidp = XFS_LIC_SLOT(licp, i); | 1090 | lidp = xfs_lic_slot(licp, i); |
| 1091 | blip = (xfs_buf_log_item_t *)lidp->lid_item; | 1091 | blip = (xfs_buf_log_item_t *)lidp->lid_item; |
| 1092 | if (blip->bli_item.li_type != XFS_LI_BUF) { | 1092 | if (blip->bli_item.li_type != XFS_LI_BUF) { |
| 1093 | continue; | 1093 | continue; |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index 4c70bf5e9985..2a1c0f071f91 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
| @@ -291,7 +291,7 @@ xfs_trans_inode_broot_debug( | |||
| 291 | iip = ip->i_itemp; | 291 | iip = ip->i_itemp; |
| 292 | if (iip->ili_root_size != 0) { | 292 | if (iip->ili_root_size != 0) { |
| 293 | ASSERT(iip->ili_orig_root != NULL); | 293 | ASSERT(iip->ili_orig_root != NULL); |
| 294 | kmem_free(iip->ili_orig_root, iip->ili_root_size); | 294 | kmem_free(iip->ili_orig_root); |
| 295 | iip->ili_root_size = 0; | 295 | iip->ili_root_size = 0; |
| 296 | iip->ili_orig_root = NULL; | 296 | iip->ili_orig_root = NULL; |
| 297 | } | 297 | } |
diff --git a/fs/xfs/xfs_trans_item.c b/fs/xfs/xfs_trans_item.c index 66a09f0d894b..3c666e8317f8 100644 --- a/fs/xfs/xfs_trans_item.c +++ b/fs/xfs/xfs_trans_item.c | |||
| @@ -53,11 +53,11 @@ xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip) | |||
| 53 | * Initialize the chunk, and then | 53 | * Initialize the chunk, and then |
| 54 | * claim the first slot in the newly allocated chunk. | 54 | * claim the first slot in the newly allocated chunk. |
| 55 | */ | 55 | */ |
| 56 | XFS_LIC_INIT(licp); | 56 | xfs_lic_init(licp); |
| 57 | XFS_LIC_CLAIM(licp, 0); | 57 | xfs_lic_claim(licp, 0); |
| 58 | licp->lic_unused = 1; | 58 | licp->lic_unused = 1; |
| 59 | XFS_LIC_INIT_SLOT(licp, 0); | 59 | xfs_lic_init_slot(licp, 0); |
| 60 | lidp = XFS_LIC_SLOT(licp, 0); | 60 | lidp = xfs_lic_slot(licp, 0); |
| 61 | 61 | ||
| 62 | /* | 62 | /* |
| 63 | * Link in the new chunk and update the free count. | 63 | * Link in the new chunk and update the free count. |
| @@ -88,14 +88,14 @@ xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip) | |||
| 88 | */ | 88 | */ |
| 89 | licp = &tp->t_items; | 89 | licp = &tp->t_items; |
| 90 | while (licp != NULL) { | 90 | while (licp != NULL) { |
| 91 | if (XFS_LIC_VACANCY(licp)) { | 91 | if (xfs_lic_vacancy(licp)) { |
| 92 | if (licp->lic_unused <= XFS_LIC_MAX_SLOT) { | 92 | if (licp->lic_unused <= XFS_LIC_MAX_SLOT) { |
| 93 | i = licp->lic_unused; | 93 | i = licp->lic_unused; |
| 94 | ASSERT(XFS_LIC_ISFREE(licp, i)); | 94 | ASSERT(xfs_lic_isfree(licp, i)); |
| 95 | break; | 95 | break; |
| 96 | } | 96 | } |
| 97 | for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) { | 97 | for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) { |
| 98 | if (XFS_LIC_ISFREE(licp, i)) | 98 | if (xfs_lic_isfree(licp, i)) |
| 99 | break; | 99 | break; |
| 100 | } | 100 | } |
| 101 | ASSERT(i <= XFS_LIC_MAX_SLOT); | 101 | ASSERT(i <= XFS_LIC_MAX_SLOT); |
| @@ -108,12 +108,12 @@ xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip) | |||
| 108 | * If we find a free descriptor, claim it, | 108 | * If we find a free descriptor, claim it, |
| 109 | * initialize it, and return it. | 109 | * initialize it, and return it. |
| 110 | */ | 110 | */ |
| 111 | XFS_LIC_CLAIM(licp, i); | 111 | xfs_lic_claim(licp, i); |
| 112 | if (licp->lic_unused <= i) { | 112 | if (licp->lic_unused <= i) { |
| 113 | licp->lic_unused = i + 1; | 113 | licp->lic_unused = i + 1; |
| 114 | XFS_LIC_INIT_SLOT(licp, i); | 114 | xfs_lic_init_slot(licp, i); |
| 115 | } | 115 | } |
| 116 | lidp = XFS_LIC_SLOT(licp, i); | 116 | lidp = xfs_lic_slot(licp, i); |
| 117 | tp->t_items_free--; | 117 | tp->t_items_free--; |
| 118 | lidp->lid_item = lip; | 118 | lidp->lid_item = lip; |
| 119 | lidp->lid_flags = 0; | 119 | lidp->lid_flags = 0; |
| @@ -136,9 +136,9 @@ xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) | |||
| 136 | xfs_log_item_chunk_t *licp; | 136 | xfs_log_item_chunk_t *licp; |
| 137 | xfs_log_item_chunk_t **licpp; | 137 | xfs_log_item_chunk_t **licpp; |
| 138 | 138 | ||
| 139 | slot = XFS_LIC_DESC_TO_SLOT(lidp); | 139 | slot = xfs_lic_desc_to_slot(lidp); |
| 140 | licp = XFS_LIC_DESC_TO_CHUNK(lidp); | 140 | licp = xfs_lic_desc_to_chunk(lidp); |
| 141 | XFS_LIC_RELSE(licp, slot); | 141 | xfs_lic_relse(licp, slot); |
| 142 | lidp->lid_item->li_desc = NULL; | 142 | lidp->lid_item->li_desc = NULL; |
| 143 | tp->t_items_free++; | 143 | tp->t_items_free++; |
| 144 | 144 | ||
| @@ -154,14 +154,14 @@ xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) | |||
| 154 | * Also decrement the transaction structure's count of free items | 154 | * Also decrement the transaction structure's count of free items |
| 155 | * by the number in a chunk since we are freeing an empty chunk. | 155 | * by the number in a chunk since we are freeing an empty chunk. |
| 156 | */ | 156 | */ |
| 157 | if (XFS_LIC_ARE_ALL_FREE(licp) && (licp != &(tp->t_items))) { | 157 | if (xfs_lic_are_all_free(licp) && (licp != &(tp->t_items))) { |
| 158 | licpp = &(tp->t_items.lic_next); | 158 | licpp = &(tp->t_items.lic_next); |
| 159 | while (*licpp != licp) { | 159 | while (*licpp != licp) { |
| 160 | ASSERT(*licpp != NULL); | 160 | ASSERT(*licpp != NULL); |
| 161 | licpp = &((*licpp)->lic_next); | 161 | licpp = &((*licpp)->lic_next); |
| 162 | } | 162 | } |
| 163 | *licpp = licp->lic_next; | 163 | *licpp = licp->lic_next; |
| 164 | kmem_free(licp, sizeof(xfs_log_item_chunk_t)); | 164 | kmem_free(licp); |
| 165 | tp->t_items_free -= XFS_LIC_NUM_SLOTS; | 165 | tp->t_items_free -= XFS_LIC_NUM_SLOTS; |
| 166 | } | 166 | } |
| 167 | } | 167 | } |
| @@ -207,20 +207,20 @@ xfs_trans_first_item(xfs_trans_t *tp) | |||
| 207 | /* | 207 | /* |
| 208 | * If it's not in the first chunk, skip to the second. | 208 | * If it's not in the first chunk, skip to the second. |
| 209 | */ | 209 | */ |
| 210 | if (XFS_LIC_ARE_ALL_FREE(licp)) { | 210 | if (xfs_lic_are_all_free(licp)) { |
| 211 | licp = licp->lic_next; | 211 | licp = licp->lic_next; |
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | /* | 214 | /* |
| 215 | * Return the first non-free descriptor in the chunk. | 215 | * Return the first non-free descriptor in the chunk. |
| 216 | */ | 216 | */ |
| 217 | ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); | 217 | ASSERT(!xfs_lic_are_all_free(licp)); |
| 218 | for (i = 0; i < licp->lic_unused; i++) { | 218 | for (i = 0; i < licp->lic_unused; i++) { |
| 219 | if (XFS_LIC_ISFREE(licp, i)) { | 219 | if (xfs_lic_isfree(licp, i)) { |
| 220 | continue; | 220 | continue; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | return XFS_LIC_SLOT(licp, i); | 223 | return xfs_lic_slot(licp, i); |
| 224 | } | 224 | } |
| 225 | cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item"); | 225 | cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item"); |
| 226 | return NULL; | 226 | return NULL; |
| @@ -242,18 +242,18 @@ xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) | |||
| 242 | xfs_log_item_chunk_t *licp; | 242 | xfs_log_item_chunk_t *licp; |
| 243 | int i; | 243 | int i; |
| 244 | 244 | ||
| 245 | licp = XFS_LIC_DESC_TO_CHUNK(lidp); | 245 | licp = xfs_lic_desc_to_chunk(lidp); |
| 246 | 246 | ||
| 247 | /* | 247 | /* |
| 248 | * First search the rest of the chunk. The for loop keeps us | 248 | * First search the rest of the chunk. The for loop keeps us |
| 249 | * from referencing things beyond the end of the chunk. | 249 | * from referencing things beyond the end of the chunk. |
| 250 | */ | 250 | */ |
| 251 | for (i = (int)XFS_LIC_DESC_TO_SLOT(lidp) + 1; i < licp->lic_unused; i++) { | 251 | for (i = (int)xfs_lic_desc_to_slot(lidp) + 1; i < licp->lic_unused; i++) { |
| 252 | if (XFS_LIC_ISFREE(licp, i)) { | 252 | if (xfs_lic_isfree(licp, i)) { |
| 253 | continue; | 253 | continue; |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | return XFS_LIC_SLOT(licp, i); | 256 | return xfs_lic_slot(licp, i); |
| 257 | } | 257 | } |
| 258 | 258 | ||
| 259 | /* | 259 | /* |
| @@ -266,13 +266,13 @@ xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) | |||
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | licp = licp->lic_next; | 268 | licp = licp->lic_next; |
| 269 | ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); | 269 | ASSERT(!xfs_lic_are_all_free(licp)); |
| 270 | for (i = 0; i < licp->lic_unused; i++) { | 270 | for (i = 0; i < licp->lic_unused; i++) { |
| 271 | if (XFS_LIC_ISFREE(licp, i)) { | 271 | if (xfs_lic_isfree(licp, i)) { |
| 272 | continue; | 272 | continue; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | return XFS_LIC_SLOT(licp, i); | 275 | return xfs_lic_slot(licp, i); |
| 276 | } | 276 | } |
| 277 | ASSERT(0); | 277 | ASSERT(0); |
| 278 | /* NOTREACHED */ | 278 | /* NOTREACHED */ |
| @@ -300,9 +300,9 @@ xfs_trans_free_items( | |||
| 300 | /* | 300 | /* |
| 301 | * Special case the embedded chunk so we don't free it below. | 301 | * Special case the embedded chunk so we don't free it below. |
| 302 | */ | 302 | */ |
| 303 | if (!XFS_LIC_ARE_ALL_FREE(licp)) { | 303 | if (!xfs_lic_are_all_free(licp)) { |
| 304 | (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); | 304 | (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); |
| 305 | XFS_LIC_ALL_FREE(licp); | 305 | xfs_lic_all_free(licp); |
| 306 | licp->lic_unused = 0; | 306 | licp->lic_unused = 0; |
| 307 | } | 307 | } |
| 308 | licp = licp->lic_next; | 308 | licp = licp->lic_next; |
| @@ -311,10 +311,10 @@ xfs_trans_free_items( | |||
| 311 | * Unlock each item in each chunk and free the chunks. | 311 | * Unlock each item in each chunk and free the chunks. |
| 312 | */ | 312 | */ |
| 313 | while (licp != NULL) { | 313 | while (licp != NULL) { |
| 314 | ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); | 314 | ASSERT(!xfs_lic_are_all_free(licp)); |
| 315 | (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); | 315 | (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); |
| 316 | next_licp = licp->lic_next; | 316 | next_licp = licp->lic_next; |
| 317 | kmem_free(licp, sizeof(xfs_log_item_chunk_t)); | 317 | kmem_free(licp); |
| 318 | licp = next_licp; | 318 | licp = next_licp; |
| 319 | } | 319 | } |
| 320 | 320 | ||
| @@ -347,7 +347,7 @@ xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn) | |||
| 347 | /* | 347 | /* |
| 348 | * Special case the embedded chunk so we don't free. | 348 | * Special case the embedded chunk so we don't free. |
| 349 | */ | 349 | */ |
| 350 | if (!XFS_LIC_ARE_ALL_FREE(licp)) { | 350 | if (!xfs_lic_are_all_free(licp)) { |
| 351 | freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); | 351 | freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); |
| 352 | } | 352 | } |
| 353 | licpp = &(tp->t_items.lic_next); | 353 | licpp = &(tp->t_items.lic_next); |
| @@ -358,12 +358,12 @@ xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn) | |||
| 358 | * and free empty chunks. | 358 | * and free empty chunks. |
| 359 | */ | 359 | */ |
| 360 | while (licp != NULL) { | 360 | while (licp != NULL) { |
| 361 | ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); | 361 | ASSERT(!xfs_lic_are_all_free(licp)); |
| 362 | freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); | 362 | freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); |
| 363 | next_licp = licp->lic_next; | 363 | next_licp = licp->lic_next; |
| 364 | if (XFS_LIC_ARE_ALL_FREE(licp)) { | 364 | if (xfs_lic_are_all_free(licp)) { |
| 365 | *licpp = next_licp; | 365 | *licpp = next_licp; |
| 366 | kmem_free(licp, sizeof(xfs_log_item_chunk_t)); | 366 | kmem_free(licp); |
| 367 | freed -= XFS_LIC_NUM_SLOTS; | 367 | freed -= XFS_LIC_NUM_SLOTS; |
| 368 | } else { | 368 | } else { |
| 369 | licpp = &(licp->lic_next); | 369 | licpp = &(licp->lic_next); |
| @@ -402,7 +402,7 @@ xfs_trans_unlock_chunk( | |||
| 402 | freed = 0; | 402 | freed = 0; |
| 403 | lidp = licp->lic_descs; | 403 | lidp = licp->lic_descs; |
| 404 | for (i = 0; i < licp->lic_unused; i++, lidp++) { | 404 | for (i = 0; i < licp->lic_unused; i++, lidp++) { |
| 405 | if (XFS_LIC_ISFREE(licp, i)) { | 405 | if (xfs_lic_isfree(licp, i)) { |
| 406 | continue; | 406 | continue; |
| 407 | } | 407 | } |
| 408 | lip = lidp->lid_item; | 408 | lip = lidp->lid_item; |
| @@ -421,7 +421,7 @@ xfs_trans_unlock_chunk( | |||
| 421 | */ | 421 | */ |
| 422 | if (!(freeing_chunk) && | 422 | if (!(freeing_chunk) && |
| 423 | (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) { | 423 | (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) { |
| 424 | XFS_LIC_RELSE(licp, i); | 424 | xfs_lic_relse(licp, i); |
| 425 | freed++; | 425 | freed++; |
| 426 | } | 426 | } |
| 427 | } | 427 | } |
| @@ -530,7 +530,7 @@ xfs_trans_free_busy(xfs_trans_t *tp) | |||
| 530 | lbcp = tp->t_busy.lbc_next; | 530 | lbcp = tp->t_busy.lbc_next; |
| 531 | while (lbcp != NULL) { | 531 | while (lbcp != NULL) { |
| 532 | lbcq = lbcp->lbc_next; | 532 | lbcq = lbcp->lbc_next; |
| 533 | kmem_free(lbcp, sizeof(xfs_log_busy_chunk_t)); | 533 | kmem_free(lbcp); |
| 534 | lbcp = lbcq; | 534 | lbcp = lbcq; |
| 535 | } | 535 | } |
| 536 | 536 | ||
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 98e5f110ba5f..35d4d414bcc2 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c | |||
| @@ -237,7 +237,7 @@ xfs_droplink( | |||
| 237 | 237 | ||
| 238 | ASSERT (ip->i_d.di_nlink > 0); | 238 | ASSERT (ip->i_d.di_nlink > 0); |
| 239 | ip->i_d.di_nlink--; | 239 | ip->i_d.di_nlink--; |
| 240 | drop_nlink(ip->i_vnode); | 240 | drop_nlink(VFS_I(ip)); |
| 241 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 241 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 242 | 242 | ||
| 243 | error = 0; | 243 | error = 0; |
| @@ -301,7 +301,7 @@ xfs_bumplink( | |||
| 301 | 301 | ||
| 302 | ASSERT(ip->i_d.di_nlink > 0); | 302 | ASSERT(ip->i_d.di_nlink > 0); |
| 303 | ip->i_d.di_nlink++; | 303 | ip->i_d.di_nlink++; |
| 304 | inc_nlink(ip->i_vnode); | 304 | inc_nlink(VFS_I(ip)); |
| 305 | if ((ip->i_d.di_version == XFS_DINODE_VERSION_1) && | 305 | if ((ip->i_d.di_version == XFS_DINODE_VERSION_1) && |
| 306 | (ip->i_d.di_nlink > XFS_MAXLINK_1)) { | 306 | (ip->i_d.di_nlink > XFS_MAXLINK_1)) { |
| 307 | /* | 307 | /* |
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h index f316cb85d8e2..ef321225d269 100644 --- a/fs/xfs/xfs_utils.h +++ b/fs/xfs/xfs_utils.h | |||
| @@ -18,9 +18,6 @@ | |||
| 18 | #ifndef __XFS_UTILS_H__ | 18 | #ifndef __XFS_UTILS_H__ |
| 19 | #define __XFS_UTILS_H__ | 19 | #define __XFS_UTILS_H__ |
| 20 | 20 | ||
| 21 | #define IRELE(ip) VN_RELE(XFS_ITOV(ip)) | ||
| 22 | #define IHOLD(ip) VN_HOLD(XFS_ITOV(ip)) | ||
| 23 | |||
| 24 | extern int xfs_truncate_file(xfs_mount_t *, xfs_inode_t *); | 21 | extern int xfs_truncate_file(xfs_mount_t *, xfs_inode_t *); |
| 25 | extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, | 22 | extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t, |
| 26 | xfs_dev_t, cred_t *, prid_t, int, | 23 | xfs_dev_t, cred_t *, prid_t, int, |
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 30bacd8bb0e5..439dd3939dda 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c | |||
| @@ -58,586 +58,6 @@ | |||
| 58 | #include "xfs_utils.h" | 58 | #include "xfs_utils.h" |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | int __init | ||
| 62 | xfs_init(void) | ||
| 63 | { | ||
| 64 | #ifdef XFS_DABUF_DEBUG | ||
| 65 | extern spinlock_t xfs_dabuf_global_lock; | ||
| 66 | spin_lock_init(&xfs_dabuf_global_lock); | ||
| 67 | #endif | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Initialize all of the zone allocators we use. | ||
| 71 | */ | ||
| 72 | xfs_log_ticket_zone = kmem_zone_init(sizeof(xlog_ticket_t), | ||
| 73 | "xfs_log_ticket"); | ||
| 74 | xfs_bmap_free_item_zone = kmem_zone_init(sizeof(xfs_bmap_free_item_t), | ||
| 75 | "xfs_bmap_free_item"); | ||
| 76 | xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t), | ||
| 77 | "xfs_btree_cur"); | ||
| 78 | xfs_da_state_zone = kmem_zone_init(sizeof(xfs_da_state_t), | ||
| 79 | "xfs_da_state"); | ||
| 80 | xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf"); | ||
| 81 | xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); | ||
| 82 | xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans"); | ||
| 83 | xfs_acl_zone_init(xfs_acl_zone, "xfs_acl"); | ||
| 84 | xfs_mru_cache_init(); | ||
| 85 | xfs_filestream_init(); | ||
| 86 | |||
| 87 | /* | ||
| 88 | * The size of the zone allocated buf log item is the maximum | ||
| 89 | * size possible under XFS. This wastes a little bit of memory, | ||
| 90 | * but it is much faster. | ||
| 91 | */ | ||
| 92 | xfs_buf_item_zone = | ||
| 93 | kmem_zone_init((sizeof(xfs_buf_log_item_t) + | ||
| 94 | (((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) / | ||
| 95 | NBWORD) * sizeof(int))), | ||
| 96 | "xfs_buf_item"); | ||
| 97 | xfs_efd_zone = | ||
| 98 | kmem_zone_init((sizeof(xfs_efd_log_item_t) + | ||
| 99 | ((XFS_EFD_MAX_FAST_EXTENTS - 1) * | ||
| 100 | sizeof(xfs_extent_t))), | ||
| 101 | "xfs_efd_item"); | ||
| 102 | xfs_efi_zone = | ||
| 103 | kmem_zone_init((sizeof(xfs_efi_log_item_t) + | ||
| 104 | ((XFS_EFI_MAX_FAST_EXTENTS - 1) * | ||
| 105 | sizeof(xfs_extent_t))), | ||
| 106 | "xfs_efi_item"); | ||
| 107 | |||
| 108 | /* | ||
| 109 | * These zones warrant special memory allocator hints | ||
| 110 | */ | ||
| 111 | xfs_inode_zone = | ||
| 112 | kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode", | ||
| 113 | KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | | ||
| 114 | KM_ZONE_SPREAD, NULL); | ||
| 115 | xfs_ili_zone = | ||
| 116 | kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili", | ||
| 117 | KM_ZONE_SPREAD, NULL); | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Allocate global trace buffers. | ||
| 121 | */ | ||
| 122 | #ifdef XFS_ALLOC_TRACE | ||
| 123 | xfs_alloc_trace_buf = ktrace_alloc(XFS_ALLOC_TRACE_SIZE, KM_SLEEP); | ||
| 124 | #endif | ||
| 125 | #ifdef XFS_BMAP_TRACE | ||
| 126 | xfs_bmap_trace_buf = ktrace_alloc(XFS_BMAP_TRACE_SIZE, KM_SLEEP); | ||
| 127 | #endif | ||
| 128 | #ifdef XFS_BMBT_TRACE | ||
| 129 | xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP); | ||
| 130 | #endif | ||
| 131 | #ifdef XFS_ATTR_TRACE | ||
| 132 | xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP); | ||
| 133 | #endif | ||
| 134 | #ifdef XFS_DIR2_TRACE | ||
| 135 | xfs_dir2_trace_buf = ktrace_alloc(XFS_DIR2_GTRACE_SIZE, KM_SLEEP); | ||
| 136 | #endif | ||
| 137 | |||
| 138 | xfs_dir_startup(); | ||
| 139 | |||
| 140 | #if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) | ||
| 141 | xfs_error_test_init(); | ||
| 142 | #endif /* DEBUG || INDUCE_IO_ERROR */ | ||
| 143 | |||
| 144 | xfs_init_procfs(); | ||
| 145 | xfs_sysctl_register(); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | |||
| 149 | void __exit | ||
| 150 | xfs_cleanup(void) | ||
| 151 | { | ||
| 152 | extern kmem_zone_t *xfs_inode_zone; | ||
| 153 | extern kmem_zone_t *xfs_efd_zone; | ||
| 154 | extern kmem_zone_t *xfs_efi_zone; | ||
| 155 | |||
| 156 | xfs_cleanup_procfs(); | ||
| 157 | xfs_sysctl_unregister(); | ||
| 158 | xfs_filestream_uninit(); | ||
| 159 | xfs_mru_cache_uninit(); | ||
| 160 | xfs_acl_zone_destroy(xfs_acl_zone); | ||
| 161 | |||
| 162 | #ifdef XFS_DIR2_TRACE | ||
| 163 | ktrace_free(xfs_dir2_trace_buf); | ||
| 164 | #endif | ||
| 165 | #ifdef XFS_ATTR_TRACE | ||
| 166 | ktrace_free(xfs_attr_trace_buf); | ||
| 167 | #endif | ||
| 168 | #ifdef XFS_BMBT_TRACE | ||
| 169 | ktrace_free(xfs_bmbt_trace_buf); | ||
| 170 | #endif | ||
| 171 | #ifdef XFS_BMAP_TRACE | ||
| 172 | ktrace_free(xfs_bmap_trace_buf); | ||
| 173 | #endif | ||
| 174 | #ifdef XFS_ALLOC_TRACE | ||
| 175 | ktrace_free(xfs_alloc_trace_buf); | ||
| 176 | #endif | ||
| 177 | |||
| 178 | kmem_zone_destroy(xfs_bmap_free_item_zone); | ||
| 179 | kmem_zone_destroy(xfs_btree_cur_zone); | ||
| 180 | kmem_zone_destroy(xfs_inode_zone); | ||
| 181 | kmem_zone_destroy(xfs_trans_zone); | ||
| 182 | kmem_zone_destroy(xfs_da_state_zone); | ||
| 183 | kmem_zone_destroy(xfs_dabuf_zone); | ||
| 184 | kmem_zone_destroy(xfs_buf_item_zone); | ||
| 185 | kmem_zone_destroy(xfs_efd_zone); | ||
| 186 | kmem_zone_destroy(xfs_efi_zone); | ||
| 187 | kmem_zone_destroy(xfs_ifork_zone); | ||
| 188 | kmem_zone_destroy(xfs_ili_zone); | ||
| 189 | kmem_zone_destroy(xfs_log_ticket_zone); | ||
| 190 | } | ||
| 191 | |||
| 192 | /* | ||
| 193 | * xfs_start_flags | ||
| 194 | * | ||
| 195 | * This function fills in xfs_mount_t fields based on mount args. | ||
| 196 | * Note: the superblock has _not_ yet been read in. | ||
| 197 | */ | ||
| 198 | STATIC int | ||
| 199 | xfs_start_flags( | ||
| 200 | struct xfs_mount_args *ap, | ||
| 201 | struct xfs_mount *mp) | ||
| 202 | { | ||
| 203 | /* Values are in BBs */ | ||
| 204 | if ((ap->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { | ||
| 205 | /* | ||
| 206 | * At this point the superblock has not been read | ||
| 207 | * in, therefore we do not know the block size. | ||
| 208 | * Before the mount call ends we will convert | ||
| 209 | * these to FSBs. | ||
| 210 | */ | ||
| 211 | mp->m_dalign = ap->sunit; | ||
| 212 | mp->m_swidth = ap->swidth; | ||
| 213 | } | ||
| 214 | |||
| 215 | if (ap->logbufs != -1 && | ||
| 216 | ap->logbufs != 0 && | ||
| 217 | (ap->logbufs < XLOG_MIN_ICLOGS || | ||
| 218 | ap->logbufs > XLOG_MAX_ICLOGS)) { | ||
| 219 | cmn_err(CE_WARN, | ||
| 220 | "XFS: invalid logbufs value: %d [not %d-%d]", | ||
| 221 | ap->logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); | ||
| 222 | return XFS_ERROR(EINVAL); | ||
| 223 | } | ||
| 224 | mp->m_logbufs = ap->logbufs; | ||
| 225 | if (ap->logbufsize != -1 && | ||
| 226 | ap->logbufsize != 0 && | ||
| 227 | (ap->logbufsize < XLOG_MIN_RECORD_BSIZE || | ||
| 228 | ap->logbufsize > XLOG_MAX_RECORD_BSIZE || | ||
| 229 | !is_power_of_2(ap->logbufsize))) { | ||
| 230 | cmn_err(CE_WARN, | ||
| 231 | "XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", | ||
| 232 | ap->logbufsize); | ||
| 233 | return XFS_ERROR(EINVAL); | ||
| 234 | } | ||
| 235 | mp->m_logbsize = ap->logbufsize; | ||
| 236 | mp->m_fsname_len = strlen(ap->fsname) + 1; | ||
| 237 | mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP); | ||
| 238 | strcpy(mp->m_fsname, ap->fsname); | ||
| 239 | if (ap->rtname[0]) { | ||
| 240 | mp->m_rtname = kmem_alloc(strlen(ap->rtname) + 1, KM_SLEEP); | ||
| 241 | strcpy(mp->m_rtname, ap->rtname); | ||
| 242 | } | ||
| 243 | if (ap->logname[0]) { | ||
| 244 | mp->m_logname = kmem_alloc(strlen(ap->logname) + 1, KM_SLEEP); | ||
| 245 | strcpy(mp->m_logname, ap->logname); | ||
| 246 | } | ||
| 247 | |||
| 248 | if (ap->flags & XFSMNT_WSYNC) | ||
| 249 | mp->m_flags |= XFS_MOUNT_WSYNC; | ||
| 250 | #if XFS_BIG_INUMS | ||
| 251 | if (ap->flags & XFSMNT_INO64) { | ||
| 252 | mp->m_flags |= XFS_MOUNT_INO64; | ||
| 253 | mp->m_inoadd = XFS_INO64_OFFSET; | ||
| 254 | } | ||
| 255 | #endif | ||
| 256 | if (ap->flags & XFSMNT_RETERR) | ||
| 257 | mp->m_flags |= XFS_MOUNT_RETERR; | ||
| 258 | if (ap->flags & XFSMNT_NOALIGN) | ||
| 259 | mp->m_flags |= XFS_MOUNT_NOALIGN; | ||
| 260 | if (ap->flags & XFSMNT_SWALLOC) | ||
| 261 | mp->m_flags |= XFS_MOUNT_SWALLOC; | ||
| 262 | if (ap->flags & XFSMNT_OSYNCISOSYNC) | ||
| 263 | mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC; | ||
| 264 | if (ap->flags & XFSMNT_32BITINODES) | ||
| 265 | mp->m_flags |= XFS_MOUNT_32BITINODES; | ||
| 266 | |||
| 267 | if (ap->flags & XFSMNT_IOSIZE) { | ||
| 268 | if (ap->iosizelog > XFS_MAX_IO_LOG || | ||
| 269 | ap->iosizelog < XFS_MIN_IO_LOG) { | ||
| 270 | cmn_err(CE_WARN, | ||
| 271 | "XFS: invalid log iosize: %d [not %d-%d]", | ||
| 272 | ap->iosizelog, XFS_MIN_IO_LOG, | ||
| 273 | XFS_MAX_IO_LOG); | ||
| 274 | return XFS_ERROR(EINVAL); | ||
| 275 | } | ||
| 276 | |||
| 277 | mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; | ||
| 278 | mp->m_readio_log = mp->m_writeio_log = ap->iosizelog; | ||
| 279 | } | ||
| 280 | |||
| 281 | if (ap->flags & XFSMNT_IKEEP) | ||
| 282 | mp->m_flags |= XFS_MOUNT_IKEEP; | ||
| 283 | if (ap->flags & XFSMNT_DIRSYNC) | ||
| 284 | mp->m_flags |= XFS_MOUNT_DIRSYNC; | ||
| 285 | if (ap->flags & XFSMNT_ATTR2) | ||
| 286 | mp->m_flags |= XFS_MOUNT_ATTR2; | ||
| 287 | |||
| 288 | if (ap->flags2 & XFSMNT2_COMPAT_IOSIZE) | ||
| 289 | mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; | ||
| 290 | |||
| 291 | /* | ||
| 292 | * no recovery flag requires a read-only mount | ||
| 293 | */ | ||
| 294 | if (ap->flags & XFSMNT_NORECOVERY) { | ||
| 295 | if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { | ||
| 296 | cmn_err(CE_WARN, | ||
| 297 | "XFS: tried to mount a FS read-write without recovery!"); | ||
| 298 | return XFS_ERROR(EINVAL); | ||
| 299 | } | ||
| 300 | mp->m_flags |= XFS_MOUNT_NORECOVERY; | ||
| 301 | } | ||
| 302 | |||
| 303 | if (ap->flags & XFSMNT_NOUUID) | ||
| 304 | mp->m_flags |= XFS_MOUNT_NOUUID; | ||
| 305 | if (ap->flags & XFSMNT_BARRIER) | ||
| 306 | mp->m_flags |= XFS_MOUNT_BARRIER; | ||
| 307 | else | ||
| 308 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | ||
| 309 | |||
| 310 | if (ap->flags2 & XFSMNT2_FILESTREAMS) | ||
| 311 | mp->m_flags |= XFS_MOUNT_FILESTREAMS; | ||
| 312 | |||
| 313 | if (ap->flags & XFSMNT_DMAPI) | ||
| 314 | mp->m_flags |= XFS_MOUNT_DMAPI; | ||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | /* | ||
| 319 | * This function fills in xfs_mount_t fields based on mount args. | ||
| 320 | * Note: the superblock _has_ now been read in. | ||
| 321 | */ | ||
| 322 | STATIC int | ||
| 323 | xfs_finish_flags( | ||
| 324 | struct xfs_mount_args *ap, | ||
| 325 | struct xfs_mount *mp) | ||
| 326 | { | ||
| 327 | int ronly = (mp->m_flags & XFS_MOUNT_RDONLY); | ||
| 328 | |||
| 329 | /* Fail a mount where the logbuf is smaller then the log stripe */ | ||
| 330 | if (xfs_sb_version_haslogv2(&mp->m_sb)) { | ||
| 331 | if ((ap->logbufsize <= 0) && | ||
| 332 | (mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE)) { | ||
| 333 | mp->m_logbsize = mp->m_sb.sb_logsunit; | ||
| 334 | } else if (ap->logbufsize > 0 && | ||
| 335 | ap->logbufsize < mp->m_sb.sb_logsunit) { | ||
| 336 | cmn_err(CE_WARN, | ||
| 337 | "XFS: logbuf size must be greater than or equal to log stripe size"); | ||
| 338 | return XFS_ERROR(EINVAL); | ||
| 339 | } | ||
| 340 | } else { | ||
| 341 | /* Fail a mount if the logbuf is larger than 32K */ | ||
| 342 | if (ap->logbufsize > XLOG_BIG_RECORD_BSIZE) { | ||
| 343 | cmn_err(CE_WARN, | ||
| 344 | "XFS: logbuf size for version 1 logs must be 16K or 32K"); | ||
| 345 | return XFS_ERROR(EINVAL); | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | if (xfs_sb_version_hasattr2(&mp->m_sb)) | ||
| 350 | mp->m_flags |= XFS_MOUNT_ATTR2; | ||
| 351 | |||
| 352 | /* | ||
| 353 | * prohibit r/w mounts of read-only filesystems | ||
| 354 | */ | ||
| 355 | if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !ronly) { | ||
| 356 | cmn_err(CE_WARN, | ||
| 357 | "XFS: cannot mount a read-only filesystem as read-write"); | ||
| 358 | return XFS_ERROR(EROFS); | ||
| 359 | } | ||
| 360 | |||
| 361 | /* | ||
| 362 | * check for shared mount. | ||
| 363 | */ | ||
| 364 | if (ap->flags & XFSMNT_SHARED) { | ||
| 365 | if (!xfs_sb_version_hasshared(&mp->m_sb)) | ||
| 366 | return XFS_ERROR(EINVAL); | ||
| 367 | |||
| 368 | /* | ||
| 369 | * For IRIX 6.5, shared mounts must have the shared | ||
| 370 | * version bit set, have the persistent readonly | ||
| 371 | * field set, must be version 0 and can only be mounted | ||
| 372 | * read-only. | ||
| 373 | */ | ||
| 374 | if (!ronly || !(mp->m_sb.sb_flags & XFS_SBF_READONLY) || | ||
| 375 | (mp->m_sb.sb_shared_vn != 0)) | ||
| 376 | return XFS_ERROR(EINVAL); | ||
| 377 | |||
| 378 | mp->m_flags |= XFS_MOUNT_SHARED; | ||
| 379 | |||
| 380 | /* | ||
| 381 | * Shared XFS V0 can't deal with DMI. Return EINVAL. | ||
| 382 | */ | ||
| 383 | if (mp->m_sb.sb_shared_vn == 0 && (ap->flags & XFSMNT_DMAPI)) | ||
| 384 | return XFS_ERROR(EINVAL); | ||
| 385 | } | ||
| 386 | |||
| 387 | if (ap->flags & XFSMNT_UQUOTA) { | ||
| 388 | mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); | ||
| 389 | if (ap->flags & XFSMNT_UQUOTAENF) | ||
| 390 | mp->m_qflags |= XFS_UQUOTA_ENFD; | ||
| 391 | } | ||
| 392 | |||
| 393 | if (ap->flags & XFSMNT_GQUOTA) { | ||
| 394 | mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); | ||
| 395 | if (ap->flags & XFSMNT_GQUOTAENF) | ||
| 396 | mp->m_qflags |= XFS_OQUOTA_ENFD; | ||
| 397 | } else if (ap->flags & XFSMNT_PQUOTA) { | ||
| 398 | mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); | ||
| 399 | if (ap->flags & XFSMNT_PQUOTAENF) | ||
| 400 | mp->m_qflags |= XFS_OQUOTA_ENFD; | ||
| 401 | } | ||
| 402 | |||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | /* | ||
| 407 | * xfs_mount | ||
| 408 | * | ||
| 409 | * The file system configurations are: | ||
| 410 | * (1) device (partition) with data and internal log | ||
| 411 | * (2) logical volume with data and log subvolumes. | ||
| 412 | * (3) logical volume with data, log, and realtime subvolumes. | ||
| 413 | * | ||
| 414 | * We only have to handle opening the log and realtime volumes here if | ||
| 415 | * they are present. The data subvolume has already been opened by | ||
| 416 | * get_sb_bdev() and is stored in vfsp->vfs_super->s_bdev. | ||
| 417 | */ | ||
| 418 | int | ||
| 419 | xfs_mount( | ||
| 420 | struct xfs_mount *mp, | ||
| 421 | struct xfs_mount_args *args, | ||
| 422 | cred_t *credp) | ||
| 423 | { | ||
| 424 | struct block_device *ddev, *logdev, *rtdev; | ||
| 425 | int flags = 0, error; | ||
| 426 | |||
| 427 | ddev = mp->m_super->s_bdev; | ||
| 428 | logdev = rtdev = NULL; | ||
| 429 | |||
| 430 | error = xfs_dmops_get(mp, args); | ||
| 431 | if (error) | ||
| 432 | return error; | ||
| 433 | error = xfs_qmops_get(mp, args); | ||
| 434 | if (error) | ||
| 435 | return error; | ||
| 436 | |||
| 437 | if (args->flags & XFSMNT_QUIET) | ||
| 438 | flags |= XFS_MFSI_QUIET; | ||
| 439 | |||
| 440 | /* | ||
| 441 | * Open real time and log devices - order is important. | ||
| 442 | */ | ||
| 443 | if (args->logname[0]) { | ||
| 444 | error = xfs_blkdev_get(mp, args->logname, &logdev); | ||
| 445 | if (error) | ||
| 446 | return error; | ||
| 447 | } | ||
| 448 | if (args->rtname[0]) { | ||
| 449 | error = xfs_blkdev_get(mp, args->rtname, &rtdev); | ||
| 450 | if (error) { | ||
| 451 | xfs_blkdev_put(logdev); | ||
| 452 | return error; | ||
| 453 | } | ||
| 454 | |||
| 455 | if (rtdev == ddev || rtdev == logdev) { | ||
| 456 | cmn_err(CE_WARN, | ||
| 457 | "XFS: Cannot mount filesystem with identical rtdev and ddev/logdev."); | ||
| 458 | xfs_blkdev_put(logdev); | ||
| 459 | xfs_blkdev_put(rtdev); | ||
| 460 | return EINVAL; | ||
| 461 | } | ||
| 462 | } | ||
| 463 | |||
| 464 | /* | ||
| 465 | * Setup xfs_mount buffer target pointers | ||
| 466 | */ | ||
| 467 | error = ENOMEM; | ||
| 468 | mp->m_ddev_targp = xfs_alloc_buftarg(ddev, 0); | ||
| 469 | if (!mp->m_ddev_targp) { | ||
| 470 | xfs_blkdev_put(logdev); | ||
| 471 | xfs_blkdev_put(rtdev); | ||
| 472 | return error; | ||
| 473 | } | ||
| 474 | if (rtdev) { | ||
| 475 | mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev, 1); | ||
| 476 | if (!mp->m_rtdev_targp) { | ||
| 477 | xfs_blkdev_put(logdev); | ||
| 478 | xfs_blkdev_put(rtdev); | ||
| 479 | goto error0; | ||
| 480 | } | ||
| 481 | } | ||
| 482 | mp->m_logdev_targp = (logdev && logdev != ddev) ? | ||
| 483 | xfs_alloc_buftarg(logdev, 1) : mp->m_ddev_targp; | ||
| 484 | if (!mp->m_logdev_targp) { | ||
| 485 | xfs_blkdev_put(logdev); | ||
| 486 | xfs_blkdev_put(rtdev); | ||
| 487 | goto error0; | ||
| 488 | } | ||
| 489 | |||
| 490 | /* | ||
| 491 | * Setup flags based on mount(2) options and then the superblock | ||
| 492 | */ | ||
| 493 | error = xfs_start_flags(args, mp); | ||
| 494 | if (error) | ||
| 495 | goto error1; | ||
| 496 | error = xfs_readsb(mp, flags); | ||
| 497 | if (error) | ||
| 498 | goto error1; | ||
| 499 | error = xfs_finish_flags(args, mp); | ||
| 500 | if (error) | ||
| 501 | goto error2; | ||
| 502 | |||
| 503 | /* | ||
| 504 | * Setup xfs_mount buffer target pointers based on superblock | ||
| 505 | */ | ||
| 506 | error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize, | ||
| 507 | mp->m_sb.sb_sectsize); | ||
| 508 | if (!error && logdev && logdev != ddev) { | ||
| 509 | unsigned int log_sector_size = BBSIZE; | ||
| 510 | |||
| 511 | if (xfs_sb_version_hassector(&mp->m_sb)) | ||
| 512 | log_sector_size = mp->m_sb.sb_logsectsize; | ||
| 513 | error = xfs_setsize_buftarg(mp->m_logdev_targp, | ||
| 514 | mp->m_sb.sb_blocksize, | ||
| 515 | log_sector_size); | ||
| 516 | } | ||
| 517 | if (!error && rtdev) | ||
| 518 | error = xfs_setsize_buftarg(mp->m_rtdev_targp, | ||
| 519 | mp->m_sb.sb_blocksize, | ||
| 520 | mp->m_sb.sb_sectsize); | ||
| 521 | if (error) | ||
| 522 | goto error2; | ||
| 523 | |||
| 524 | if (mp->m_flags & XFS_MOUNT_BARRIER) | ||
| 525 | xfs_mountfs_check_barriers(mp); | ||
| 526 | |||
| 527 | if ((error = xfs_filestream_mount(mp))) | ||
| 528 | goto error2; | ||
| 529 | |||
| 530 | error = xfs_mountfs(mp, flags); | ||
| 531 | if (error) | ||
| 532 | goto error2; | ||
| 533 | |||
| 534 | XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, args->mtpt, args->fsname); | ||
| 535 | |||
| 536 | return 0; | ||
| 537 | |||
| 538 | error2: | ||
| 539 | if (mp->m_sb_bp) | ||
| 540 | xfs_freesb(mp); | ||
| 541 | error1: | ||
| 542 | xfs_binval(mp->m_ddev_targp); | ||
| 543 | if (logdev && logdev != ddev) | ||
| 544 | xfs_binval(mp->m_logdev_targp); | ||
| 545 | if (rtdev) | ||
| 546 | xfs_binval(mp->m_rtdev_targp); | ||
| 547 | error0: | ||
| 548 | xfs_unmountfs_close(mp, credp); | ||
| 549 | xfs_qmops_put(mp); | ||
| 550 | xfs_dmops_put(mp); | ||
| 551 | return error; | ||
| 552 | } | ||
| 553 | |||
| 554 | int | ||
| 555 | xfs_unmount( | ||
| 556 | xfs_mount_t *mp, | ||
| 557 | int flags, | ||
| 558 | cred_t *credp) | ||
| 559 | { | ||
| 560 | xfs_inode_t *rip; | ||
| 561 | bhv_vnode_t *rvp; | ||
| 562 | int unmount_event_wanted = 0; | ||
| 563 | int unmount_event_flags = 0; | ||
| 564 | int xfs_unmountfs_needed = 0; | ||
| 565 | int error; | ||
| 566 | |||
| 567 | rip = mp->m_rootip; | ||
| 568 | rvp = XFS_ITOV(rip); | ||
| 569 | |||
| 570 | #ifdef HAVE_DMAPI | ||
| 571 | if (mp->m_flags & XFS_MOUNT_DMAPI) { | ||
| 572 | error = XFS_SEND_PREUNMOUNT(mp, | ||
| 573 | rip, DM_RIGHT_NULL, rip, DM_RIGHT_NULL, | ||
| 574 | NULL, NULL, 0, 0, | ||
| 575 | (mp->m_dmevmask & (1<<DM_EVENT_PREUNMOUNT))? | ||
| 576 | 0:DM_FLAGS_UNWANTED); | ||
| 577 | if (error) | ||
| 578 | return XFS_ERROR(error); | ||
| 579 | unmount_event_wanted = 1; | ||
| 580 | unmount_event_flags = (mp->m_dmevmask & (1<<DM_EVENT_UNMOUNT))? | ||
| 581 | 0 : DM_FLAGS_UNWANTED; | ||
| 582 | } | ||
| 583 | #endif | ||
| 584 | |||
| 585 | /* | ||
| 586 | * Blow away any referenced inode in the filestreams cache. | ||
| 587 | * This can and will cause log traffic as inodes go inactive | ||
| 588 | * here. | ||
| 589 | */ | ||
| 590 | xfs_filestream_unmount(mp); | ||
| 591 | |||
| 592 | XFS_bflush(mp->m_ddev_targp); | ||
| 593 | error = xfs_unmount_flush(mp, 0); | ||
| 594 | if (error) | ||
| 595 | goto out; | ||
| 596 | |||
| 597 | ASSERT(vn_count(rvp) == 1); | ||
| 598 | |||
| 599 | /* | ||
| 600 | * Drop the reference count | ||
| 601 | */ | ||
| 602 | IRELE(rip); | ||
| 603 | |||
| 604 | /* | ||
| 605 | * If we're forcing a shutdown, typically because of a media error, | ||
| 606 | * we want to make sure we invalidate dirty pages that belong to | ||
| 607 | * referenced vnodes as well. | ||
| 608 | */ | ||
| 609 | if (XFS_FORCED_SHUTDOWN(mp)) { | ||
| 610 | error = xfs_sync(mp, SYNC_WAIT | SYNC_CLOSE); | ||
| 611 | ASSERT(error != EFSCORRUPTED); | ||
| 612 | } | ||
| 613 | xfs_unmountfs_needed = 1; | ||
| 614 | |||
| 615 | out: | ||
| 616 | /* Send DMAPI event, if required. | ||
| 617 | * Then do xfs_unmountfs() if needed. | ||
| 618 | * Then return error (or zero). | ||
| 619 | */ | ||
| 620 | if (unmount_event_wanted) { | ||
| 621 | /* Note: mp structure must still exist for | ||
| 622 | * XFS_SEND_UNMOUNT() call. | ||
| 623 | */ | ||
| 624 | XFS_SEND_UNMOUNT(mp, error == 0 ? rip : NULL, | ||
| 625 | DM_RIGHT_NULL, 0, error, unmount_event_flags); | ||
| 626 | } | ||
| 627 | if (xfs_unmountfs_needed) { | ||
| 628 | /* | ||
| 629 | * Call common unmount function to flush to disk | ||
| 630 | * and free the super block buffer & mount structures. | ||
| 631 | */ | ||
| 632 | xfs_unmountfs(mp, credp); | ||
| 633 | xfs_qmops_put(mp); | ||
| 634 | xfs_dmops_put(mp); | ||
| 635 | kmem_free(mp, sizeof(xfs_mount_t)); | ||
| 636 | } | ||
| 637 | |||
| 638 | return XFS_ERROR(error); | ||
| 639 | } | ||
| 640 | |||
| 641 | STATIC void | 61 | STATIC void |
| 642 | xfs_quiesce_fs( | 62 | xfs_quiesce_fs( |
| 643 | xfs_mount_t *mp) | 63 | xfs_mount_t *mp) |
| @@ -694,30 +114,6 @@ xfs_attr_quiesce( | |||
| 694 | xfs_unmountfs_writesb(mp); | 114 | xfs_unmountfs_writesb(mp); |
| 695 | } | 115 | } |
| 696 | 116 | ||
| 697 | int | ||
| 698 | xfs_mntupdate( | ||
| 699 | struct xfs_mount *mp, | ||
| 700 | int *flags, | ||
| 701 | struct xfs_mount_args *args) | ||
| 702 | { | ||
| 703 | if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */ | ||
| 704 | if (mp->m_flags & XFS_MOUNT_RDONLY) | ||
| 705 | mp->m_flags &= ~XFS_MOUNT_RDONLY; | ||
| 706 | if (args->flags & XFSMNT_BARRIER) { | ||
| 707 | mp->m_flags |= XFS_MOUNT_BARRIER; | ||
| 708 | xfs_mountfs_check_barriers(mp); | ||
| 709 | } else { | ||
| 710 | mp->m_flags &= ~XFS_MOUNT_BARRIER; | ||
| 711 | } | ||
| 712 | } else if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { /* rw -> ro */ | ||
| 713 | xfs_filestream_flush(mp); | ||
| 714 | xfs_sync(mp, SYNC_DATA_QUIESCE); | ||
| 715 | xfs_attr_quiesce(mp); | ||
| 716 | mp->m_flags |= XFS_MOUNT_RDONLY; | ||
| 717 | } | ||
| 718 | return 0; | ||
| 719 | } | ||
| 720 | |||
| 721 | /* | 117 | /* |
| 722 | * xfs_unmount_flush implements a set of flush operation on special | 118 | * xfs_unmount_flush implements a set of flush operation on special |
| 723 | * inodes, which are needed as a separate set of operations so that | 119 | * inodes, which are needed as a separate set of operations so that |
| @@ -732,7 +128,6 @@ xfs_unmount_flush( | |||
| 732 | xfs_inode_t *rip = mp->m_rootip; | 128 | xfs_inode_t *rip = mp->m_rootip; |
| 733 | xfs_inode_t *rbmip; | 129 | xfs_inode_t *rbmip; |
| 734 | xfs_inode_t *rsumip = NULL; | 130 | xfs_inode_t *rsumip = NULL; |
| 735 | bhv_vnode_t *rvp = XFS_ITOV(rip); | ||
| 736 | int error; | 131 | int error; |
| 737 | 132 | ||
| 738 | xfs_ilock(rip, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | 133 | xfs_ilock(rip, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); |
| @@ -750,7 +145,7 @@ xfs_unmount_flush( | |||
| 750 | if (error == EFSCORRUPTED) | 145 | if (error == EFSCORRUPTED) |
| 751 | goto fscorrupt_out; | 146 | goto fscorrupt_out; |
| 752 | 147 | ||
| 753 | ASSERT(vn_count(XFS_ITOV(rbmip)) == 1); | 148 | ASSERT(vn_count(VFS_I(rbmip)) == 1); |
| 754 | 149 | ||
| 755 | rsumip = mp->m_rsumip; | 150 | rsumip = mp->m_rsumip; |
| 756 | xfs_ilock(rsumip, XFS_ILOCK_EXCL); | 151 | xfs_ilock(rsumip, XFS_ILOCK_EXCL); |
| @@ -761,7 +156,7 @@ xfs_unmount_flush( | |||
| 761 | if (error == EFSCORRUPTED) | 156 | if (error == EFSCORRUPTED) |
| 762 | goto fscorrupt_out; | 157 | goto fscorrupt_out; |
| 763 | 158 | ||
| 764 | ASSERT(vn_count(XFS_ITOV(rsumip)) == 1); | 159 | ASSERT(vn_count(VFS_I(rsumip)) == 1); |
| 765 | } | 160 | } |
| 766 | 161 | ||
| 767 | /* | 162 | /* |
| @@ -771,7 +166,7 @@ xfs_unmount_flush( | |||
| 771 | if (error == EFSCORRUPTED) | 166 | if (error == EFSCORRUPTED) |
| 772 | goto fscorrupt_out2; | 167 | goto fscorrupt_out2; |
| 773 | 168 | ||
| 774 | if (vn_count(rvp) != 1 && !relocation) { | 169 | if (vn_count(VFS_I(rip)) != 1 && !relocation) { |
| 775 | xfs_iunlock(rip, XFS_ILOCK_EXCL); | 170 | xfs_iunlock(rip, XFS_ILOCK_EXCL); |
| 776 | return XFS_ERROR(EBUSY); | 171 | return XFS_ERROR(EBUSY); |
| 777 | } | 172 | } |
| @@ -888,7 +283,7 @@ xfs_sync_inodes( | |||
| 888 | int *bypassed) | 283 | int *bypassed) |
| 889 | { | 284 | { |
| 890 | xfs_inode_t *ip = NULL; | 285 | xfs_inode_t *ip = NULL; |
| 891 | bhv_vnode_t *vp = NULL; | 286 | struct inode *vp = NULL; |
| 892 | int error; | 287 | int error; |
| 893 | int last_error; | 288 | int last_error; |
| 894 | uint64_t fflag; | 289 | uint64_t fflag; |
| @@ -1008,7 +403,7 @@ xfs_sync_inodes( | |||
| 1008 | continue; | 403 | continue; |
| 1009 | } | 404 | } |
| 1010 | 405 | ||
| 1011 | vp = XFS_ITOV_NULL(ip); | 406 | vp = VFS_I(ip); |
| 1012 | 407 | ||
| 1013 | /* | 408 | /* |
| 1014 | * If the vnode is gone then this is being torn down, | 409 | * If the vnode is gone then this is being torn down, |
| @@ -1048,7 +443,7 @@ xfs_sync_inodes( | |||
| 1048 | 443 | ||
| 1049 | if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) { | 444 | if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) { |
| 1050 | XFS_MOUNT_IUNLOCK(mp); | 445 | XFS_MOUNT_IUNLOCK(mp); |
| 1051 | kmem_free(ipointer, sizeof(xfs_iptr_t)); | 446 | kmem_free(ipointer); |
| 1052 | return 0; | 447 | return 0; |
| 1053 | } | 448 | } |
| 1054 | 449 | ||
| @@ -1083,7 +478,7 @@ xfs_sync_inodes( | |||
| 1083 | IPOINTER_INSERT(ip, mp); | 478 | IPOINTER_INSERT(ip, mp); |
| 1084 | xfs_ilock(ip, lock_flags); | 479 | xfs_ilock(ip, lock_flags); |
| 1085 | 480 | ||
| 1086 | ASSERT(vp == XFS_ITOV(ip)); | 481 | ASSERT(vp == VFS_I(ip)); |
| 1087 | ASSERT(ip->i_mount == mp); | 482 | ASSERT(ip->i_mount == mp); |
| 1088 | 483 | ||
| 1089 | vnode_refed = B_TRUE; | 484 | vnode_refed = B_TRUE; |
| @@ -1194,7 +589,7 @@ xfs_sync_inodes( | |||
| 1194 | } | 589 | } |
| 1195 | XFS_MOUNT_IUNLOCK(mp); | 590 | XFS_MOUNT_IUNLOCK(mp); |
| 1196 | ASSERT(ipointer_in == B_FALSE); | 591 | ASSERT(ipointer_in == B_FALSE); |
| 1197 | kmem_free(ipointer, sizeof(xfs_iptr_t)); | 592 | kmem_free(ipointer); |
| 1198 | return XFS_ERROR(error); | 593 | return XFS_ERROR(error); |
| 1199 | } | 594 | } |
| 1200 | 595 | ||
| @@ -1224,7 +619,7 @@ xfs_sync_inodes( | |||
| 1224 | 619 | ||
| 1225 | ASSERT(ipointer_in == B_FALSE); | 620 | ASSERT(ipointer_in == B_FALSE); |
| 1226 | 621 | ||
| 1227 | kmem_free(ipointer, sizeof(xfs_iptr_t)); | 622 | kmem_free(ipointer); |
| 1228 | return XFS_ERROR(last_error); | 623 | return XFS_ERROR(last_error); |
| 1229 | } | 624 | } |
| 1230 | 625 | ||
diff --git a/fs/xfs/xfs_vfsops.h b/fs/xfs/xfs_vfsops.h index 1688817c55ed..a74b05087da4 100644 --- a/fs/xfs/xfs_vfsops.h +++ b/fs/xfs/xfs_vfsops.h | |||
| @@ -8,11 +8,6 @@ struct kstatfs; | |||
| 8 | struct xfs_mount; | 8 | struct xfs_mount; |
| 9 | struct xfs_mount_args; | 9 | struct xfs_mount_args; |
| 10 | 10 | ||
| 11 | int xfs_mount(struct xfs_mount *mp, struct xfs_mount_args *args, | ||
| 12 | struct cred *credp); | ||
| 13 | int xfs_unmount(struct xfs_mount *mp, int flags, struct cred *credp); | ||
| 14 | int xfs_mntupdate(struct xfs_mount *mp, int *flags, | ||
| 15 | struct xfs_mount_args *args); | ||
| 16 | int xfs_sync(struct xfs_mount *mp, int flags); | 11 | int xfs_sync(struct xfs_mount *mp, int flags); |
| 17 | void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, | 12 | void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, |
| 18 | int lnnum); | 13 | int lnnum); |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index e475e3717eb3..8b6812f66a15 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -75,26 +75,23 @@ xfs_open( | |||
| 75 | return 0; | 75 | return 0; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | /* | ||
| 79 | * xfs_setattr | ||
| 80 | */ | ||
| 81 | int | 78 | int |
| 82 | xfs_setattr( | 79 | xfs_setattr( |
| 83 | xfs_inode_t *ip, | 80 | struct xfs_inode *ip, |
| 84 | bhv_vattr_t *vap, | 81 | struct iattr *iattr, |
| 85 | int flags, | 82 | int flags, |
| 86 | cred_t *credp) | 83 | cred_t *credp) |
| 87 | { | 84 | { |
| 88 | xfs_mount_t *mp = ip->i_mount; | 85 | xfs_mount_t *mp = ip->i_mount; |
| 86 | struct inode *inode = VFS_I(ip); | ||
| 87 | int mask = iattr->ia_valid; | ||
| 89 | xfs_trans_t *tp; | 88 | xfs_trans_t *tp; |
| 90 | int mask; | ||
| 91 | int code; | 89 | int code; |
| 92 | uint lock_flags; | 90 | uint lock_flags; |
| 93 | uint commit_flags=0; | 91 | uint commit_flags=0; |
| 94 | uid_t uid=0, iuid=0; | 92 | uid_t uid=0, iuid=0; |
| 95 | gid_t gid=0, igid=0; | 93 | gid_t gid=0, igid=0; |
| 96 | int timeflags = 0; | 94 | int timeflags = 0; |
| 97 | xfs_prid_t projid=0, iprojid=0; | ||
| 98 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; | 95 | struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; |
| 99 | int file_owner; | 96 | int file_owner; |
| 100 | int need_iolock = 1; | 97 | int need_iolock = 1; |
| @@ -104,30 +101,9 @@ xfs_setattr( | |||
| 104 | if (mp->m_flags & XFS_MOUNT_RDONLY) | 101 | if (mp->m_flags & XFS_MOUNT_RDONLY) |
| 105 | return XFS_ERROR(EROFS); | 102 | return XFS_ERROR(EROFS); |
| 106 | 103 | ||
| 107 | /* | ||
| 108 | * Cannot set certain attributes. | ||
| 109 | */ | ||
| 110 | mask = vap->va_mask; | ||
| 111 | if (mask & XFS_AT_NOSET) { | ||
| 112 | return XFS_ERROR(EINVAL); | ||
| 113 | } | ||
| 114 | |||
| 115 | if (XFS_FORCED_SHUTDOWN(mp)) | 104 | if (XFS_FORCED_SHUTDOWN(mp)) |
| 116 | return XFS_ERROR(EIO); | 105 | return XFS_ERROR(EIO); |
| 117 | 106 | ||
| 118 | /* | ||
| 119 | * Timestamps do not need to be logged and hence do not | ||
| 120 | * need to be done within a transaction. | ||
| 121 | */ | ||
| 122 | if (mask & XFS_AT_UPDTIMES) { | ||
| 123 | ASSERT((mask & ~XFS_AT_UPDTIMES) == 0); | ||
| 124 | timeflags = ((mask & XFS_AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) | | ||
| 125 | ((mask & XFS_AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) | | ||
| 126 | ((mask & XFS_AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0); | ||
| 127 | xfs_ichgtime(ip, timeflags); | ||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | olddquot1 = olddquot2 = NULL; | 107 | olddquot1 = olddquot2 = NULL; |
| 132 | udqp = gdqp = NULL; | 108 | udqp = gdqp = NULL; |
| 133 | 109 | ||
| @@ -139,28 +115,22 @@ xfs_setattr( | |||
| 139 | * If the IDs do change before we take the ilock, we're covered | 115 | * If the IDs do change before we take the ilock, we're covered |
| 140 | * because the i_*dquot fields will get updated anyway. | 116 | * because the i_*dquot fields will get updated anyway. |
| 141 | */ | 117 | */ |
| 142 | if (XFS_IS_QUOTA_ON(mp) && | 118 | if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) { |
| 143 | (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID))) { | ||
| 144 | uint qflags = 0; | 119 | uint qflags = 0; |
| 145 | 120 | ||
| 146 | if ((mask & XFS_AT_UID) && XFS_IS_UQUOTA_ON(mp)) { | 121 | if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) { |
| 147 | uid = vap->va_uid; | 122 | uid = iattr->ia_uid; |
| 148 | qflags |= XFS_QMOPT_UQUOTA; | 123 | qflags |= XFS_QMOPT_UQUOTA; |
| 149 | } else { | 124 | } else { |
| 150 | uid = ip->i_d.di_uid; | 125 | uid = ip->i_d.di_uid; |
| 151 | } | 126 | } |
| 152 | if ((mask & XFS_AT_GID) && XFS_IS_GQUOTA_ON(mp)) { | 127 | if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) { |
| 153 | gid = vap->va_gid; | 128 | gid = iattr->ia_gid; |
| 154 | qflags |= XFS_QMOPT_GQUOTA; | 129 | qflags |= XFS_QMOPT_GQUOTA; |
| 155 | } else { | 130 | } else { |
| 156 | gid = ip->i_d.di_gid; | 131 | gid = ip->i_d.di_gid; |
| 157 | } | 132 | } |
| 158 | if ((mask & XFS_AT_PROJID) && XFS_IS_PQUOTA_ON(mp)) { | 133 | |
| 159 | projid = vap->va_projid; | ||
| 160 | qflags |= XFS_QMOPT_PQUOTA; | ||
| 161 | } else { | ||
| 162 | projid = ip->i_d.di_projid; | ||
| 163 | } | ||
| 164 | /* | 134 | /* |
| 165 | * We take a reference when we initialize udqp and gdqp, | 135 | * We take a reference when we initialize udqp and gdqp, |
| 166 | * so it is important that we never blindly double trip on | 136 | * so it is important that we never blindly double trip on |
| @@ -168,8 +138,8 @@ xfs_setattr( | |||
| 168 | */ | 138 | */ |
| 169 | ASSERT(udqp == NULL); | 139 | ASSERT(udqp == NULL); |
| 170 | ASSERT(gdqp == NULL); | 140 | ASSERT(gdqp == NULL); |
| 171 | code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, projid, qflags, | 141 | code = XFS_QM_DQVOPALLOC(mp, ip, uid, gid, ip->i_d.di_projid, |
| 172 | &udqp, &gdqp); | 142 | qflags, &udqp, &gdqp); |
| 173 | if (code) | 143 | if (code) |
| 174 | return code; | 144 | return code; |
| 175 | } | 145 | } |
| @@ -180,10 +150,10 @@ xfs_setattr( | |||
| 180 | */ | 150 | */ |
| 181 | tp = NULL; | 151 | tp = NULL; |
| 182 | lock_flags = XFS_ILOCK_EXCL; | 152 | lock_flags = XFS_ILOCK_EXCL; |
| 183 | if (flags & ATTR_NOLOCK) | 153 | if (flags & XFS_ATTR_NOLOCK) |
| 184 | need_iolock = 0; | 154 | need_iolock = 0; |
| 185 | if (!(mask & XFS_AT_SIZE)) { | 155 | if (!(mask & ATTR_SIZE)) { |
| 186 | if ((mask != (XFS_AT_CTIME|XFS_AT_ATIME|XFS_AT_MTIME)) || | 156 | if ((mask != (ATTR_CTIME|ATTR_ATIME|ATTR_MTIME)) || |
| 187 | (mp->m_flags & XFS_MOUNT_WSYNC)) { | 157 | (mp->m_flags & XFS_MOUNT_WSYNC)) { |
| 188 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | 158 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); |
| 189 | commit_flags = 0; | 159 | commit_flags = 0; |
| @@ -196,10 +166,10 @@ xfs_setattr( | |||
| 196 | } | 166 | } |
| 197 | } else { | 167 | } else { |
| 198 | if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && | 168 | if (DM_EVENT_ENABLED(ip, DM_EVENT_TRUNCATE) && |
| 199 | !(flags & ATTR_DMI)) { | 169 | !(flags & XFS_ATTR_DMI)) { |
| 200 | int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; | 170 | int dmflags = AT_DELAY_FLAG(flags) | DM_SEM_FLAG_WR; |
| 201 | code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip, | 171 | code = XFS_SEND_DATA(mp, DM_EVENT_TRUNCATE, ip, |
| 202 | vap->va_size, 0, dmflags, NULL); | 172 | iattr->ia_size, 0, dmflags, NULL); |
| 203 | if (code) { | 173 | if (code) { |
| 204 | lock_flags = 0; | 174 | lock_flags = 0; |
| 205 | goto error_return; | 175 | goto error_return; |
| @@ -212,16 +182,14 @@ xfs_setattr( | |||
| 212 | xfs_ilock(ip, lock_flags); | 182 | xfs_ilock(ip, lock_flags); |
| 213 | 183 | ||
| 214 | /* boolean: are we the file owner? */ | 184 | /* boolean: are we the file owner? */ |
| 215 | file_owner = (current_fsuid(credp) == ip->i_d.di_uid); | 185 | file_owner = (current_fsuid() == ip->i_d.di_uid); |
| 216 | 186 | ||
| 217 | /* | 187 | /* |
| 218 | * Change various properties of a file. | 188 | * Change various properties of a file. |
| 219 | * Only the owner or users with CAP_FOWNER | 189 | * Only the owner or users with CAP_FOWNER |
| 220 | * capability may do these things. | 190 | * capability may do these things. |
| 221 | */ | 191 | */ |
| 222 | if (mask & | 192 | if (mask & (ATTR_MODE|ATTR_UID|ATTR_GID)) { |
| 223 | (XFS_AT_MODE|XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_UID| | ||
| 224 | XFS_AT_GID|XFS_AT_PROJID)) { | ||
| 225 | /* | 193 | /* |
| 226 | * CAP_FOWNER overrides the following restrictions: | 194 | * CAP_FOWNER overrides the following restrictions: |
| 227 | * | 195 | * |
| @@ -245,21 +213,21 @@ xfs_setattr( | |||
| 245 | * IDs of the calling process shall match the group owner of | 213 | * IDs of the calling process shall match the group owner of |
| 246 | * the file when setting the set-group-ID bit on that file | 214 | * the file when setting the set-group-ID bit on that file |
| 247 | */ | 215 | */ |
| 248 | if (mask & XFS_AT_MODE) { | 216 | if (mask & ATTR_MODE) { |
| 249 | mode_t m = 0; | 217 | mode_t m = 0; |
| 250 | 218 | ||
| 251 | if ((vap->va_mode & S_ISUID) && !file_owner) | 219 | if ((iattr->ia_mode & S_ISUID) && !file_owner) |
| 252 | m |= S_ISUID; | 220 | m |= S_ISUID; |
| 253 | if ((vap->va_mode & S_ISGID) && | 221 | if ((iattr->ia_mode & S_ISGID) && |
| 254 | !in_group_p((gid_t)ip->i_d.di_gid)) | 222 | !in_group_p((gid_t)ip->i_d.di_gid)) |
| 255 | m |= S_ISGID; | 223 | m |= S_ISGID; |
| 256 | #if 0 | 224 | #if 0 |
| 257 | /* Linux allows this, Irix doesn't. */ | 225 | /* Linux allows this, Irix doesn't. */ |
| 258 | if ((vap->va_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) | 226 | if ((iattr->ia_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode)) |
| 259 | m |= S_ISVTX; | 227 | m |= S_ISVTX; |
| 260 | #endif | 228 | #endif |
| 261 | if (m && !capable(CAP_FSETID)) | 229 | if (m && !capable(CAP_FSETID)) |
| 262 | vap->va_mode &= ~m; | 230 | iattr->ia_mode &= ~m; |
| 263 | } | 231 | } |
| 264 | } | 232 | } |
| 265 | 233 | ||
| @@ -270,7 +238,7 @@ xfs_setattr( | |||
| 270 | * and can change the group id only to a group of which he | 238 | * and can change the group id only to a group of which he |
| 271 | * or she is a member. | 239 | * or she is a member. |
| 272 | */ | 240 | */ |
| 273 | if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { | 241 | if (mask & (ATTR_UID|ATTR_GID)) { |
| 274 | /* | 242 | /* |
| 275 | * These IDs could have changed since we last looked at them. | 243 | * These IDs could have changed since we last looked at them. |
| 276 | * But, we're assured that if the ownership did change | 244 | * But, we're assured that if the ownership did change |
| @@ -278,12 +246,9 @@ xfs_setattr( | |||
| 278 | * would have changed also. | 246 | * would have changed also. |
| 279 | */ | 247 | */ |
| 280 | iuid = ip->i_d.di_uid; | 248 | iuid = ip->i_d.di_uid; |
| 281 | iprojid = ip->i_d.di_projid; | ||
| 282 | igid = ip->i_d.di_gid; | 249 | igid = ip->i_d.di_gid; |
| 283 | gid = (mask & XFS_AT_GID) ? vap->va_gid : igid; | 250 | gid = (mask & ATTR_GID) ? iattr->ia_gid : igid; |
| 284 | uid = (mask & XFS_AT_UID) ? vap->va_uid : iuid; | 251 | uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; |
| 285 | projid = (mask & XFS_AT_PROJID) ? (xfs_prid_t)vap->va_projid : | ||
| 286 | iprojid; | ||
| 287 | 252 | ||
| 288 | /* | 253 | /* |
| 289 | * CAP_CHOWN overrides the following restrictions: | 254 | * CAP_CHOWN overrides the following restrictions: |
| @@ -303,11 +268,10 @@ xfs_setattr( | |||
| 303 | goto error_return; | 268 | goto error_return; |
| 304 | } | 269 | } |
| 305 | /* | 270 | /* |
| 306 | * Do a quota reservation only if uid/projid/gid is actually | 271 | * Do a quota reservation only if uid/gid is actually |
| 307 | * going to change. | 272 | * going to change. |
| 308 | */ | 273 | */ |
| 309 | if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || | 274 | if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || |
| 310 | (XFS_IS_PQUOTA_ON(mp) && iprojid != projid) || | ||
| 311 | (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { | 275 | (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { |
| 312 | ASSERT(tp); | 276 | ASSERT(tp); |
| 313 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, | 277 | code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, |
| @@ -321,13 +285,13 @@ xfs_setattr( | |||
| 321 | /* | 285 | /* |
| 322 | * Truncate file. Must have write permission and not be a directory. | 286 | * Truncate file. Must have write permission and not be a directory. |
| 323 | */ | 287 | */ |
| 324 | if (mask & XFS_AT_SIZE) { | 288 | if (mask & ATTR_SIZE) { |
| 325 | /* Short circuit the truncate case for zero length files */ | 289 | /* Short circuit the truncate case for zero length files */ |
| 326 | if ((vap->va_size == 0) && | 290 | if (iattr->ia_size == 0 && |
| 327 | (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) { | 291 | ip->i_size == 0 && ip->i_d.di_nextents == 0) { |
| 328 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 292 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 329 | lock_flags &= ~XFS_ILOCK_EXCL; | 293 | lock_flags &= ~XFS_ILOCK_EXCL; |
| 330 | if (mask & XFS_AT_CTIME) | 294 | if (mask & ATTR_CTIME) |
| 331 | xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 295 | xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 332 | code = 0; | 296 | code = 0; |
| 333 | goto error_return; | 297 | goto error_return; |
| @@ -350,9 +314,9 @@ xfs_setattr( | |||
| 350 | /* | 314 | /* |
| 351 | * Change file access or modified times. | 315 | * Change file access or modified times. |
| 352 | */ | 316 | */ |
| 353 | if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { | 317 | if (mask & (ATTR_ATIME|ATTR_MTIME)) { |
| 354 | if (!file_owner) { | 318 | if (!file_owner) { |
| 355 | if ((flags & ATTR_UTIME) && | 319 | if ((mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)) && |
| 356 | !capable(CAP_FOWNER)) { | 320 | !capable(CAP_FOWNER)) { |
| 357 | code = XFS_ERROR(EPERM); | 321 | code = XFS_ERROR(EPERM); |
| 358 | goto error_return; | 322 | goto error_return; |
| @@ -361,90 +325,23 @@ xfs_setattr( | |||
| 361 | } | 325 | } |
| 362 | 326 | ||
| 363 | /* | 327 | /* |
| 364 | * Change extent size or realtime flag. | ||
| 365 | */ | ||
| 366 | if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) { | ||
| 367 | /* | ||
| 368 | * Can't change extent size if any extents are allocated. | ||
| 369 | */ | ||
| 370 | if (ip->i_d.di_nextents && (mask & XFS_AT_EXTSIZE) && | ||
| 371 | ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != | ||
| 372 | vap->va_extsize) ) { | ||
| 373 | code = XFS_ERROR(EINVAL); /* EFBIG? */ | ||
| 374 | goto error_return; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* | ||
| 378 | * Can't change realtime flag if any extents are allocated. | ||
| 379 | */ | ||
| 380 | if ((ip->i_d.di_nextents || ip->i_delayed_blks) && | ||
| 381 | (mask & XFS_AT_XFLAGS) && | ||
| 382 | (XFS_IS_REALTIME_INODE(ip)) != | ||
| 383 | (vap->va_xflags & XFS_XFLAG_REALTIME)) { | ||
| 384 | code = XFS_ERROR(EINVAL); /* EFBIG? */ | ||
| 385 | goto error_return; | ||
| 386 | } | ||
| 387 | /* | ||
| 388 | * Extent size must be a multiple of the appropriate block | ||
| 389 | * size, if set at all. | ||
| 390 | */ | ||
| 391 | if ((mask & XFS_AT_EXTSIZE) && vap->va_extsize != 0) { | ||
| 392 | xfs_extlen_t size; | ||
| 393 | |||
| 394 | if (XFS_IS_REALTIME_INODE(ip) || | ||
| 395 | ((mask & XFS_AT_XFLAGS) && | ||
| 396 | (vap->va_xflags & XFS_XFLAG_REALTIME))) { | ||
| 397 | size = mp->m_sb.sb_rextsize << | ||
| 398 | mp->m_sb.sb_blocklog; | ||
| 399 | } else { | ||
| 400 | size = mp->m_sb.sb_blocksize; | ||
| 401 | } | ||
| 402 | if (vap->va_extsize % size) { | ||
| 403 | code = XFS_ERROR(EINVAL); | ||
| 404 | goto error_return; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | /* | ||
| 408 | * If realtime flag is set then must have realtime data. | ||
| 409 | */ | ||
| 410 | if ((mask & XFS_AT_XFLAGS) && | ||
| 411 | (vap->va_xflags & XFS_XFLAG_REALTIME)) { | ||
| 412 | if ((mp->m_sb.sb_rblocks == 0) || | ||
| 413 | (mp->m_sb.sb_rextsize == 0) || | ||
| 414 | (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { | ||
| 415 | code = XFS_ERROR(EINVAL); | ||
| 416 | goto error_return; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | /* | ||
| 421 | * Can't modify an immutable/append-only file unless | ||
| 422 | * we have appropriate permission. | ||
| 423 | */ | ||
| 424 | if ((mask & XFS_AT_XFLAGS) && | ||
| 425 | (ip->i_d.di_flags & | ||
| 426 | (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) || | ||
| 427 | (vap->va_xflags & | ||
| 428 | (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) && | ||
| 429 | !capable(CAP_LINUX_IMMUTABLE)) { | ||
| 430 | code = XFS_ERROR(EPERM); | ||
| 431 | goto error_return; | ||
| 432 | } | ||
| 433 | } | ||
| 434 | |||
| 435 | /* | ||
| 436 | * Now we can make the changes. Before we join the inode | 328 | * Now we can make the changes. Before we join the inode |
| 437 | * to the transaction, if XFS_AT_SIZE is set then take care of | 329 | * to the transaction, if ATTR_SIZE is set then take care of |
| 438 | * the part of the truncation that must be done without the | 330 | * the part of the truncation that must be done without the |
| 439 | * inode lock. This needs to be done before joining the inode | 331 | * inode lock. This needs to be done before joining the inode |
| 440 | * to the transaction, because the inode cannot be unlocked | 332 | * to the transaction, because the inode cannot be unlocked |
| 441 | * once it is a part of the transaction. | 333 | * once it is a part of the transaction. |
| 442 | */ | 334 | */ |
| 443 | if (mask & XFS_AT_SIZE) { | 335 | if (mask & ATTR_SIZE) { |
| 444 | code = 0; | 336 | code = 0; |
| 445 | if ((vap->va_size > ip->i_size) && | 337 | if (iattr->ia_size > ip->i_size) { |
| 446 | (flags & ATTR_NOSIZETOK) == 0) { | 338 | /* |
| 447 | code = xfs_igrow_start(ip, vap->va_size, credp); | 339 | * Do the first part of growing a file: zero any data |
| 340 | * in the last block that is beyond the old EOF. We | ||
| 341 | * need to do this before the inode is joined to the | ||
| 342 | * transaction to modify the i_size. | ||
| 343 | */ | ||
| 344 | code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); | ||
| 448 | } | 345 | } |
| 449 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 346 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 450 | 347 | ||
| @@ -461,10 +358,10 @@ xfs_setattr( | |||
| 461 | * not within the range we care about here. | 358 | * not within the range we care about here. |
| 462 | */ | 359 | */ |
| 463 | if (!code && | 360 | if (!code && |
| 464 | (ip->i_size != ip->i_d.di_size) && | 361 | ip->i_size != ip->i_d.di_size && |
| 465 | (vap->va_size > ip->i_d.di_size)) { | 362 | iattr->ia_size > ip->i_d.di_size) { |
| 466 | code = xfs_flush_pages(ip, | 363 | code = xfs_flush_pages(ip, |
| 467 | ip->i_d.di_size, vap->va_size, | 364 | ip->i_d.di_size, iattr->ia_size, |
| 468 | XFS_B_ASYNC, FI_NONE); | 365 | XFS_B_ASYNC, FI_NONE); |
| 469 | } | 366 | } |
| 470 | 367 | ||
| @@ -472,7 +369,7 @@ xfs_setattr( | |||
| 472 | vn_iowait(ip); | 369 | vn_iowait(ip); |
| 473 | 370 | ||
| 474 | if (!code) | 371 | if (!code) |
| 475 | code = xfs_itruncate_data(ip, vap->va_size); | 372 | code = xfs_itruncate_data(ip, iattr->ia_size); |
| 476 | if (code) { | 373 | if (code) { |
| 477 | ASSERT(tp == NULL); | 374 | ASSERT(tp == NULL); |
| 478 | lock_flags &= ~XFS_ILOCK_EXCL; | 375 | lock_flags &= ~XFS_ILOCK_EXCL; |
| @@ -501,28 +398,30 @@ xfs_setattr( | |||
| 501 | /* | 398 | /* |
| 502 | * Truncate file. Must have write permission and not be a directory. | 399 | * Truncate file. Must have write permission and not be a directory. |
| 503 | */ | 400 | */ |
| 504 | if (mask & XFS_AT_SIZE) { | 401 | if (mask & ATTR_SIZE) { |
| 505 | /* | 402 | /* |
| 506 | * Only change the c/mtime if we are changing the size | 403 | * Only change the c/mtime if we are changing the size |
| 507 | * or we are explicitly asked to change it. This handles | 404 | * or we are explicitly asked to change it. This handles |
| 508 | * the semantic difference between truncate() and ftruncate() | 405 | * the semantic difference between truncate() and ftruncate() |
| 509 | * as implemented in the VFS. | 406 | * as implemented in the VFS. |
| 510 | */ | 407 | */ |
| 511 | if (vap->va_size != ip->i_size || (mask & XFS_AT_CTIME)) | 408 | if (iattr->ia_size != ip->i_size || (mask & ATTR_CTIME)) |
| 512 | timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; | 409 | timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; |
| 513 | 410 | ||
| 514 | if (vap->va_size > ip->i_size) { | 411 | if (iattr->ia_size > ip->i_size) { |
| 515 | xfs_igrow_finish(tp, ip, vap->va_size, | 412 | ip->i_d.di_size = iattr->ia_size; |
| 516 | !(flags & ATTR_DMI)); | 413 | ip->i_size = iattr->ia_size; |
| 517 | } else if ((vap->va_size <= ip->i_size) || | 414 | if (!(flags & XFS_ATTR_DMI)) |
| 518 | ((vap->va_size == 0) && ip->i_d.di_nextents)) { | 415 | xfs_ichgtime(ip, XFS_ICHGTIME_CHG); |
| 416 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 417 | } else if (iattr->ia_size <= ip->i_size || | ||
| 418 | (iattr->ia_size == 0 && ip->i_d.di_nextents)) { | ||
| 519 | /* | 419 | /* |
| 520 | * signal a sync transaction unless | 420 | * signal a sync transaction unless |
| 521 | * we're truncating an already unlinked | 421 | * we're truncating an already unlinked |
| 522 | * file on a wsync filesystem | 422 | * file on a wsync filesystem |
| 523 | */ | 423 | */ |
| 524 | code = xfs_itruncate_finish(&tp, ip, | 424 | code = xfs_itruncate_finish(&tp, ip, iattr->ia_size, |
| 525 | (xfs_fsize_t)vap->va_size, | ||
| 526 | XFS_DATA_FORK, | 425 | XFS_DATA_FORK, |
| 527 | ((ip->i_d.di_nlink != 0 || | 426 | ((ip->i_d.di_nlink != 0 || |
| 528 | !(mp->m_flags & XFS_MOUNT_WSYNC)) | 427 | !(mp->m_flags & XFS_MOUNT_WSYNC)) |
| @@ -544,9 +443,12 @@ xfs_setattr( | |||
| 544 | /* | 443 | /* |
| 545 | * Change file access modes. | 444 | * Change file access modes. |
| 546 | */ | 445 | */ |
| 547 | if (mask & XFS_AT_MODE) { | 446 | if (mask & ATTR_MODE) { |
| 548 | ip->i_d.di_mode &= S_IFMT; | 447 | ip->i_d.di_mode &= S_IFMT; |
| 549 | ip->i_d.di_mode |= vap->va_mode & ~S_IFMT; | 448 | ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT; |
| 449 | |||
| 450 | inode->i_mode &= S_IFMT; | ||
| 451 | inode->i_mode |= iattr->ia_mode & ~S_IFMT; | ||
| 550 | 452 | ||
| 551 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | 453 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); |
| 552 | timeflags |= XFS_ICHGTIME_CHG; | 454 | timeflags |= XFS_ICHGTIME_CHG; |
| @@ -559,7 +461,7 @@ xfs_setattr( | |||
| 559 | * and can change the group id only to a group of which he | 461 | * and can change the group id only to a group of which he |
| 560 | * or she is a member. | 462 | * or she is a member. |
| 561 | */ | 463 | */ |
| 562 | if (mask & (XFS_AT_UID|XFS_AT_GID|XFS_AT_PROJID)) { | 464 | if (mask & (ATTR_UID|ATTR_GID)) { |
| 563 | /* | 465 | /* |
| 564 | * CAP_FSETID overrides the following restrictions: | 466 | * CAP_FSETID overrides the following restrictions: |
| 565 | * | 467 | * |
| @@ -577,39 +479,24 @@ xfs_setattr( | |||
| 577 | */ | 479 | */ |
| 578 | if (iuid != uid) { | 480 | if (iuid != uid) { |
| 579 | if (XFS_IS_UQUOTA_ON(mp)) { | 481 | if (XFS_IS_UQUOTA_ON(mp)) { |
| 580 | ASSERT(mask & XFS_AT_UID); | 482 | ASSERT(mask & ATTR_UID); |
| 581 | ASSERT(udqp); | 483 | ASSERT(udqp); |
| 582 | olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | 484 | olddquot1 = XFS_QM_DQVOPCHOWN(mp, tp, ip, |
| 583 | &ip->i_udquot, udqp); | 485 | &ip->i_udquot, udqp); |
| 584 | } | 486 | } |
| 585 | ip->i_d.di_uid = uid; | 487 | ip->i_d.di_uid = uid; |
| 488 | inode->i_uid = uid; | ||
| 586 | } | 489 | } |
| 587 | if (igid != gid) { | 490 | if (igid != gid) { |
| 588 | if (XFS_IS_GQUOTA_ON(mp)) { | 491 | if (XFS_IS_GQUOTA_ON(mp)) { |
| 589 | ASSERT(!XFS_IS_PQUOTA_ON(mp)); | 492 | ASSERT(!XFS_IS_PQUOTA_ON(mp)); |
| 590 | ASSERT(mask & XFS_AT_GID); | 493 | ASSERT(mask & ATTR_GID); |
| 591 | ASSERT(gdqp); | 494 | ASSERT(gdqp); |
| 592 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | 495 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, |
| 593 | &ip->i_gdquot, gdqp); | 496 | &ip->i_gdquot, gdqp); |
| 594 | } | 497 | } |
| 595 | ip->i_d.di_gid = gid; | 498 | ip->i_d.di_gid = gid; |
| 596 | } | 499 | inode->i_gid = gid; |
| 597 | if (iprojid != projid) { | ||
| 598 | if (XFS_IS_PQUOTA_ON(mp)) { | ||
| 599 | ASSERT(!XFS_IS_GQUOTA_ON(mp)); | ||
| 600 | ASSERT(mask & XFS_AT_PROJID); | ||
| 601 | ASSERT(gdqp); | ||
| 602 | olddquot2 = XFS_QM_DQVOPCHOWN(mp, tp, ip, | ||
| 603 | &ip->i_gdquot, gdqp); | ||
| 604 | } | ||
| 605 | ip->i_d.di_projid = projid; | ||
| 606 | /* | ||
| 607 | * We may have to rev the inode as well as | ||
| 608 | * the superblock version number since projids didn't | ||
| 609 | * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. | ||
| 610 | */ | ||
| 611 | if (ip->i_d.di_version == XFS_DINODE_VERSION_1) | ||
| 612 | xfs_bump_ino_vers2(tp, ip); | ||
| 613 | } | 500 | } |
| 614 | 501 | ||
| 615 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | 502 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); |
| @@ -620,82 +507,33 @@ xfs_setattr( | |||
| 620 | /* | 507 | /* |
| 621 | * Change file access or modified times. | 508 | * Change file access or modified times. |
| 622 | */ | 509 | */ |
| 623 | if (mask & (XFS_AT_ATIME|XFS_AT_MTIME)) { | 510 | if (mask & (ATTR_ATIME|ATTR_MTIME)) { |
| 624 | if (mask & XFS_AT_ATIME) { | 511 | if (mask & ATTR_ATIME) { |
| 625 | ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec; | 512 | inode->i_atime = iattr->ia_atime; |
| 626 | ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec; | 513 | ip->i_d.di_atime.t_sec = iattr->ia_atime.tv_sec; |
| 514 | ip->i_d.di_atime.t_nsec = iattr->ia_atime.tv_nsec; | ||
| 627 | ip->i_update_core = 1; | 515 | ip->i_update_core = 1; |
| 628 | timeflags &= ~XFS_ICHGTIME_ACC; | ||
| 629 | } | 516 | } |
| 630 | if (mask & XFS_AT_MTIME) { | 517 | if (mask & ATTR_MTIME) { |
| 631 | ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec; | 518 | inode->i_mtime = iattr->ia_mtime; |
| 632 | ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec; | 519 | ip->i_d.di_mtime.t_sec = iattr->ia_mtime.tv_sec; |
| 520 | ip->i_d.di_mtime.t_nsec = iattr->ia_mtime.tv_nsec; | ||
| 633 | timeflags &= ~XFS_ICHGTIME_MOD; | 521 | timeflags &= ~XFS_ICHGTIME_MOD; |
| 634 | timeflags |= XFS_ICHGTIME_CHG; | 522 | timeflags |= XFS_ICHGTIME_CHG; |
| 635 | } | 523 | } |
| 636 | if (tp && (flags & ATTR_UTIME)) | 524 | if (tp && (mask & (ATTR_MTIME_SET|ATTR_ATIME_SET))) |
| 637 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); | 525 | xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); |
| 638 | } | 526 | } |
| 639 | 527 | ||
| 640 | /* | 528 | /* |
| 641 | * Change XFS-added attributes. | 529 | * Change file inode change time only if ATTR_CTIME set |
| 642 | */ | ||
| 643 | if (mask & (XFS_AT_EXTSIZE|XFS_AT_XFLAGS)) { | ||
| 644 | if (mask & XFS_AT_EXTSIZE) { | ||
| 645 | /* | ||
| 646 | * Converting bytes to fs blocks. | ||
| 647 | */ | ||
| 648 | ip->i_d.di_extsize = vap->va_extsize >> | ||
| 649 | mp->m_sb.sb_blocklog; | ||
| 650 | } | ||
| 651 | if (mask & XFS_AT_XFLAGS) { | ||
| 652 | uint di_flags; | ||
| 653 | |||
| 654 | /* can't set PREALLOC this way, just preserve it */ | ||
| 655 | di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); | ||
| 656 | if (vap->va_xflags & XFS_XFLAG_IMMUTABLE) | ||
| 657 | di_flags |= XFS_DIFLAG_IMMUTABLE; | ||
| 658 | if (vap->va_xflags & XFS_XFLAG_APPEND) | ||
| 659 | di_flags |= XFS_DIFLAG_APPEND; | ||
| 660 | if (vap->va_xflags & XFS_XFLAG_SYNC) | ||
| 661 | di_flags |= XFS_DIFLAG_SYNC; | ||
| 662 | if (vap->va_xflags & XFS_XFLAG_NOATIME) | ||
| 663 | di_flags |= XFS_DIFLAG_NOATIME; | ||
| 664 | if (vap->va_xflags & XFS_XFLAG_NODUMP) | ||
| 665 | di_flags |= XFS_DIFLAG_NODUMP; | ||
| 666 | if (vap->va_xflags & XFS_XFLAG_PROJINHERIT) | ||
| 667 | di_flags |= XFS_DIFLAG_PROJINHERIT; | ||
| 668 | if (vap->va_xflags & XFS_XFLAG_NODEFRAG) | ||
| 669 | di_flags |= XFS_DIFLAG_NODEFRAG; | ||
| 670 | if (vap->va_xflags & XFS_XFLAG_FILESTREAM) | ||
| 671 | di_flags |= XFS_DIFLAG_FILESTREAM; | ||
| 672 | if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { | ||
| 673 | if (vap->va_xflags & XFS_XFLAG_RTINHERIT) | ||
| 674 | di_flags |= XFS_DIFLAG_RTINHERIT; | ||
| 675 | if (vap->va_xflags & XFS_XFLAG_NOSYMLINKS) | ||
| 676 | di_flags |= XFS_DIFLAG_NOSYMLINKS; | ||
| 677 | if (vap->va_xflags & XFS_XFLAG_EXTSZINHERIT) | ||
| 678 | di_flags |= XFS_DIFLAG_EXTSZINHERIT; | ||
| 679 | } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { | ||
| 680 | if (vap->va_xflags & XFS_XFLAG_REALTIME) | ||
| 681 | di_flags |= XFS_DIFLAG_REALTIME; | ||
| 682 | if (vap->va_xflags & XFS_XFLAG_EXTSIZE) | ||
| 683 | di_flags |= XFS_DIFLAG_EXTSIZE; | ||
| 684 | } | ||
| 685 | ip->i_d.di_flags = di_flags; | ||
| 686 | } | ||
| 687 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
| 688 | timeflags |= XFS_ICHGTIME_CHG; | ||
| 689 | } | ||
| 690 | |||
| 691 | /* | ||
| 692 | * Change file inode change time only if XFS_AT_CTIME set | ||
| 693 | * AND we have been called by a DMI function. | 530 | * AND we have been called by a DMI function. |
| 694 | */ | 531 | */ |
| 695 | 532 | ||
| 696 | if ( (flags & ATTR_DMI) && (mask & XFS_AT_CTIME) ) { | 533 | if ((flags & XFS_ATTR_DMI) && (mask & ATTR_CTIME)) { |
| 697 | ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec; | 534 | inode->i_ctime = iattr->ia_ctime; |
| 698 | ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec; | 535 | ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; |
| 536 | ip->i_d.di_ctime.t_nsec = iattr->ia_ctime.tv_nsec; | ||
| 699 | ip->i_update_core = 1; | 537 | ip->i_update_core = 1; |
| 700 | timeflags &= ~XFS_ICHGTIME_CHG; | 538 | timeflags &= ~XFS_ICHGTIME_CHG; |
| 701 | } | 539 | } |
| @@ -704,7 +542,7 @@ xfs_setattr( | |||
| 704 | * Send out timestamp changes that need to be set to the | 542 | * Send out timestamp changes that need to be set to the |
| 705 | * current time. Not done when called by a DMI function. | 543 | * current time. Not done when called by a DMI function. |
| 706 | */ | 544 | */ |
| 707 | if (timeflags && !(flags & ATTR_DMI)) | 545 | if (timeflags && !(flags & XFS_ATTR_DMI)) |
| 708 | xfs_ichgtime(ip, timeflags); | 546 | xfs_ichgtime(ip, timeflags); |
| 709 | 547 | ||
| 710 | XFS_STATS_INC(xs_ig_attrchg); | 548 | XFS_STATS_INC(xs_ig_attrchg); |
| @@ -742,7 +580,7 @@ xfs_setattr( | |||
| 742 | } | 580 | } |
| 743 | 581 | ||
| 744 | if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) && | 582 | if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE) && |
| 745 | !(flags & ATTR_DMI)) { | 583 | !(flags & XFS_ATTR_DMI)) { |
| 746 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL, | 584 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL, |
| 747 | NULL, DM_RIGHT_NULL, NULL, NULL, | 585 | NULL, DM_RIGHT_NULL, NULL, NULL, |
| 748 | 0, 0, AT_DELAY_FLAG(flags)); | 586 | 0, 0, AT_DELAY_FLAG(flags)); |
| @@ -875,7 +713,7 @@ xfs_fsync( | |||
| 875 | return XFS_ERROR(EIO); | 713 | return XFS_ERROR(EIO); |
| 876 | 714 | ||
| 877 | /* capture size updates in I/O completion before writing the inode. */ | 715 | /* capture size updates in I/O completion before writing the inode. */ |
| 878 | error = filemap_fdatawait(vn_to_inode(XFS_ITOV(ip))->i_mapping); | 716 | error = filemap_fdatawait(VFS_I(ip)->i_mapping); |
| 879 | if (error) | 717 | if (error) |
| 880 | return XFS_ERROR(error); | 718 | return XFS_ERROR(error); |
| 881 | 719 | ||
| @@ -1321,7 +1159,6 @@ int | |||
| 1321 | xfs_release( | 1159 | xfs_release( |
| 1322 | xfs_inode_t *ip) | 1160 | xfs_inode_t *ip) |
| 1323 | { | 1161 | { |
| 1324 | bhv_vnode_t *vp = XFS_ITOV(ip); | ||
| 1325 | xfs_mount_t *mp = ip->i_mount; | 1162 | xfs_mount_t *mp = ip->i_mount; |
| 1326 | int error; | 1163 | int error; |
| 1327 | 1164 | ||
| @@ -1356,13 +1193,13 @@ xfs_release( | |||
| 1356 | * be exposed to that problem. | 1193 | * be exposed to that problem. |
| 1357 | */ | 1194 | */ |
| 1358 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); | 1195 | truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); |
| 1359 | if (truncated && VN_DIRTY(vp) && ip->i_delayed_blks > 0) | 1196 | if (truncated && VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) |
| 1360 | xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); | 1197 | xfs_flush_pages(ip, 0, -1, XFS_B_ASYNC, FI_NONE); |
| 1361 | } | 1198 | } |
| 1362 | 1199 | ||
| 1363 | if (ip->i_d.di_nlink != 0) { | 1200 | if (ip->i_d.di_nlink != 0) { |
| 1364 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && | 1201 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && |
| 1365 | ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || | 1202 | ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || |
| 1366 | ip->i_delayed_blks > 0)) && | 1203 | ip->i_delayed_blks > 0)) && |
| 1367 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && | 1204 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && |
| 1368 | (!(ip->i_d.di_flags & | 1205 | (!(ip->i_d.di_flags & |
| @@ -1388,7 +1225,6 @@ int | |||
| 1388 | xfs_inactive( | 1225 | xfs_inactive( |
| 1389 | xfs_inode_t *ip) | 1226 | xfs_inode_t *ip) |
| 1390 | { | 1227 | { |
| 1391 | bhv_vnode_t *vp = XFS_ITOV(ip); | ||
| 1392 | xfs_bmap_free_t free_list; | 1228 | xfs_bmap_free_t free_list; |
| 1393 | xfs_fsblock_t first_block; | 1229 | xfs_fsblock_t first_block; |
| 1394 | int committed; | 1230 | int committed; |
| @@ -1403,7 +1239,7 @@ xfs_inactive( | |||
| 1403 | * If the inode is already free, then there can be nothing | 1239 | * If the inode is already free, then there can be nothing |
| 1404 | * to clean up here. | 1240 | * to clean up here. |
| 1405 | */ | 1241 | */ |
| 1406 | if (ip->i_d.di_mode == 0 || VN_BAD(vp)) { | 1242 | if (ip->i_d.di_mode == 0 || VN_BAD(VFS_I(ip))) { |
| 1407 | ASSERT(ip->i_df.if_real_bytes == 0); | 1243 | ASSERT(ip->i_df.if_real_bytes == 0); |
| 1408 | ASSERT(ip->i_df.if_broot_bytes == 0); | 1244 | ASSERT(ip->i_df.if_broot_bytes == 0); |
| 1409 | return VN_INACTIVE_CACHE; | 1245 | return VN_INACTIVE_CACHE; |
| @@ -1433,7 +1269,7 @@ xfs_inactive( | |||
| 1433 | 1269 | ||
| 1434 | if (ip->i_d.di_nlink != 0) { | 1270 | if (ip->i_d.di_nlink != 0) { |
| 1435 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && | 1271 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && |
| 1436 | ((ip->i_size > 0) || (VN_CACHED(vp) > 0 || | 1272 | ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || |
| 1437 | ip->i_delayed_blks > 0)) && | 1273 | ip->i_delayed_blks > 0)) && |
| 1438 | (ip->i_df.if_flags & XFS_IFEXTENTS) && | 1274 | (ip->i_df.if_flags & XFS_IFEXTENTS) && |
| 1439 | (!(ip->i_d.di_flags & | 1275 | (!(ip->i_d.di_flags & |
| @@ -1601,12 +1437,18 @@ xfs_inactive( | |||
| 1601 | return VN_INACTIVE_CACHE; | 1437 | return VN_INACTIVE_CACHE; |
| 1602 | } | 1438 | } |
| 1603 | 1439 | ||
| 1604 | 1440 | /* | |
| 1441 | * Lookups up an inode from "name". If ci_name is not NULL, then a CI match | ||
| 1442 | * is allowed, otherwise it has to be an exact match. If a CI match is found, | ||
| 1443 | * ci_name->name will point to a the actual name (caller must free) or | ||
| 1444 | * will be set to NULL if an exact match is found. | ||
| 1445 | */ | ||
| 1605 | int | 1446 | int |
| 1606 | xfs_lookup( | 1447 | xfs_lookup( |
| 1607 | xfs_inode_t *dp, | 1448 | xfs_inode_t *dp, |
| 1608 | struct xfs_name *name, | 1449 | struct xfs_name *name, |
| 1609 | xfs_inode_t **ipp) | 1450 | xfs_inode_t **ipp, |
| 1451 | struct xfs_name *ci_name) | ||
| 1610 | { | 1452 | { |
| 1611 | xfs_ino_t inum; | 1453 | xfs_ino_t inum; |
| 1612 | int error; | 1454 | int error; |
| @@ -1618,7 +1460,7 @@ xfs_lookup( | |||
| 1618 | return XFS_ERROR(EIO); | 1460 | return XFS_ERROR(EIO); |
| 1619 | 1461 | ||
| 1620 | lock_mode = xfs_ilock_map_shared(dp); | 1462 | lock_mode = xfs_ilock_map_shared(dp); |
| 1621 | error = xfs_dir_lookup(NULL, dp, name, &inum); | 1463 | error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name); |
| 1622 | xfs_iunlock_map_shared(dp, lock_mode); | 1464 | xfs_iunlock_map_shared(dp, lock_mode); |
| 1623 | 1465 | ||
| 1624 | if (error) | 1466 | if (error) |
| @@ -1626,12 +1468,15 @@ xfs_lookup( | |||
| 1626 | 1468 | ||
| 1627 | error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0); | 1469 | error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0); |
| 1628 | if (error) | 1470 | if (error) |
| 1629 | goto out; | 1471 | goto out_free_name; |
| 1630 | 1472 | ||
| 1631 | xfs_itrace_ref(*ipp); | 1473 | xfs_itrace_ref(*ipp); |
| 1632 | return 0; | 1474 | return 0; |
| 1633 | 1475 | ||
| 1634 | out: | 1476 | out_free_name: |
| 1477 | if (ci_name) | ||
| 1478 | kmem_free(ci_name->name); | ||
| 1479 | out: | ||
| 1635 | *ipp = NULL; | 1480 | *ipp = NULL; |
| 1636 | return error; | 1481 | return error; |
| 1637 | } | 1482 | } |
| @@ -1688,7 +1533,7 @@ xfs_create( | |||
| 1688 | * Make sure that we have allocated dquot(s) on disk. | 1533 | * Make sure that we have allocated dquot(s) on disk. |
| 1689 | */ | 1534 | */ |
| 1690 | error = XFS_QM_DQVOPALLOC(mp, dp, | 1535 | error = XFS_QM_DQVOPALLOC(mp, dp, |
| 1691 | current_fsuid(credp), current_fsgid(credp), prid, | 1536 | current_fsuid(), current_fsgid(), prid, |
| 1692 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); | 1537 | XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, &udqp, &gdqp); |
| 1693 | if (error) | 1538 | if (error) |
| 1694 | goto std_return; | 1539 | goto std_return; |
| @@ -1860,111 +1705,6 @@ std_return: | |||
| 1860 | } | 1705 | } |
| 1861 | 1706 | ||
| 1862 | #ifdef DEBUG | 1707 | #ifdef DEBUG |
| 1863 | /* | ||
| 1864 | * Some counters to see if (and how often) we are hitting some deadlock | ||
| 1865 | * prevention code paths. | ||
| 1866 | */ | ||
| 1867 | |||
| 1868 | int xfs_rm_locks; | ||
| 1869 | int xfs_rm_lock_delays; | ||
| 1870 | int xfs_rm_attempts; | ||
| 1871 | #endif | ||
| 1872 | |||
| 1873 | /* | ||
| 1874 | * The following routine will lock the inodes associated with the | ||
| 1875 | * directory and the named entry in the directory. The locks are | ||
| 1876 | * acquired in increasing inode number. | ||
| 1877 | * | ||
| 1878 | * If the entry is "..", then only the directory is locked. The | ||
| 1879 | * vnode ref count will still include that from the .. entry in | ||
| 1880 | * this case. | ||
| 1881 | * | ||
| 1882 | * There is a deadlock we need to worry about. If the locked directory is | ||
| 1883 | * in the AIL, it might be blocking up the log. The next inode we lock | ||
| 1884 | * could be already locked by another thread waiting for log space (e.g | ||
| 1885 | * a permanent log reservation with a long running transaction (see | ||
| 1886 | * xfs_itruncate_finish)). To solve this, we must check if the directory | ||
| 1887 | * is in the ail and use lock_nowait. If we can't lock, we need to | ||
| 1888 | * drop the inode lock on the directory and try again. xfs_iunlock will | ||
| 1889 | * potentially push the tail if we were holding up the log. | ||
| 1890 | */ | ||
| 1891 | STATIC int | ||
| 1892 | xfs_lock_dir_and_entry( | ||
| 1893 | xfs_inode_t *dp, | ||
| 1894 | xfs_inode_t *ip) /* inode of entry 'name' */ | ||
| 1895 | { | ||
| 1896 | int attempts; | ||
| 1897 | xfs_ino_t e_inum; | ||
| 1898 | xfs_inode_t *ips[2]; | ||
| 1899 | xfs_log_item_t *lp; | ||
| 1900 | |||
| 1901 | #ifdef DEBUG | ||
| 1902 | xfs_rm_locks++; | ||
| 1903 | #endif | ||
| 1904 | attempts = 0; | ||
| 1905 | |||
| 1906 | again: | ||
| 1907 | xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); | ||
| 1908 | |||
| 1909 | e_inum = ip->i_ino; | ||
| 1910 | |||
| 1911 | xfs_itrace_ref(ip); | ||
| 1912 | |||
| 1913 | /* | ||
| 1914 | * We want to lock in increasing inum. Since we've already | ||
| 1915 | * acquired the lock on the directory, we may need to release | ||
| 1916 | * if if the inum of the entry turns out to be less. | ||
| 1917 | */ | ||
| 1918 | if (e_inum > dp->i_ino) { | ||
| 1919 | /* | ||
| 1920 | * We are already in the right order, so just | ||
| 1921 | * lock on the inode of the entry. | ||
| 1922 | * We need to use nowait if dp is in the AIL. | ||
| 1923 | */ | ||
| 1924 | |||
| 1925 | lp = (xfs_log_item_t *)dp->i_itemp; | ||
| 1926 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { | ||
| 1927 | if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { | ||
| 1928 | attempts++; | ||
| 1929 | #ifdef DEBUG | ||
| 1930 | xfs_rm_attempts++; | ||
| 1931 | #endif | ||
| 1932 | |||
| 1933 | /* | ||
| 1934 | * Unlock dp and try again. | ||
| 1935 | * xfs_iunlock will try to push the tail | ||
| 1936 | * if the inode is in the AIL. | ||
| 1937 | */ | ||
| 1938 | |||
| 1939 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
| 1940 | |||
| 1941 | if ((attempts % 5) == 0) { | ||
| 1942 | delay(1); /* Don't just spin the CPU */ | ||
| 1943 | #ifdef DEBUG | ||
| 1944 | xfs_rm_lock_delays++; | ||
| 1945 | #endif | ||
| 1946 | } | ||
| 1947 | goto again; | ||
| 1948 | } | ||
| 1949 | } else { | ||
| 1950 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
| 1951 | } | ||
| 1952 | } else if (e_inum < dp->i_ino) { | ||
| 1953 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
| 1954 | |||
| 1955 | ips[0] = ip; | ||
| 1956 | ips[1] = dp; | ||
| 1957 | xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL); | ||
| 1958 | } | ||
| 1959 | /* else e_inum == dp->i_ino */ | ||
| 1960 | /* This can happen if we're asked to lock /x/.. | ||
| 1961 | * the entry is "..", which is also the parent directory. | ||
| 1962 | */ | ||
| 1963 | |||
| 1964 | return 0; | ||
| 1965 | } | ||
| 1966 | |||
| 1967 | #ifdef DEBUG | ||
| 1968 | int xfs_locked_n; | 1708 | int xfs_locked_n; |
| 1969 | int xfs_small_retries; | 1709 | int xfs_small_retries; |
| 1970 | int xfs_middle_retries; | 1710 | int xfs_middle_retries; |
| @@ -2098,12 +1838,52 @@ again: | |||
| 2098 | #endif | 1838 | #endif |
| 2099 | } | 1839 | } |
| 2100 | 1840 | ||
| 2101 | #ifdef DEBUG | 1841 | /* |
| 2102 | #define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);} | 1842 | * xfs_lock_two_inodes() can only be used to lock one type of lock |
| 2103 | int remove_which_error_return = 0; | 1843 | * at a time - the iolock or the ilock, but not both at once. If |
| 2104 | #else /* ! DEBUG */ | 1844 | * we lock both at once, lockdep will report false positives saying |
| 2105 | #define REMOVE_DEBUG_TRACE(x) | 1845 | * we have violated locking orders. |
| 2106 | #endif /* ! DEBUG */ | 1846 | */ |
| 1847 | void | ||
| 1848 | xfs_lock_two_inodes( | ||
| 1849 | xfs_inode_t *ip0, | ||
| 1850 | xfs_inode_t *ip1, | ||
| 1851 | uint lock_mode) | ||
| 1852 | { | ||
| 1853 | xfs_inode_t *temp; | ||
| 1854 | int attempts = 0; | ||
| 1855 | xfs_log_item_t *lp; | ||
| 1856 | |||
| 1857 | if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)) | ||
| 1858 | ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0); | ||
| 1859 | ASSERT(ip0->i_ino != ip1->i_ino); | ||
| 1860 | |||
| 1861 | if (ip0->i_ino > ip1->i_ino) { | ||
| 1862 | temp = ip0; | ||
| 1863 | ip0 = ip1; | ||
| 1864 | ip1 = temp; | ||
| 1865 | } | ||
| 1866 | |||
| 1867 | again: | ||
| 1868 | xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0)); | ||
| 1869 | |||
| 1870 | /* | ||
| 1871 | * If the first lock we have locked is in the AIL, we must TRY to get | ||
| 1872 | * the second lock. If we can't get it, we must release the first one | ||
| 1873 | * and try again. | ||
| 1874 | */ | ||
| 1875 | lp = (xfs_log_item_t *)ip0->i_itemp; | ||
| 1876 | if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { | ||
| 1877 | if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) { | ||
| 1878 | xfs_iunlock(ip0, lock_mode); | ||
| 1879 | if ((++attempts % 5) == 0) | ||
| 1880 | delay(1); /* Don't just spin the CPU */ | ||
| 1881 | goto again; | ||
| 1882 | } | ||
| 1883 | } else { | ||
| 1884 | xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1)); | ||
| 1885 | } | ||
| 1886 | } | ||
| 2107 | 1887 | ||
| 2108 | int | 1888 | int |
| 2109 | xfs_remove( | 1889 | xfs_remove( |
| @@ -2113,6 +1893,7 @@ xfs_remove( | |||
| 2113 | { | 1893 | { |
| 2114 | xfs_mount_t *mp = dp->i_mount; | 1894 | xfs_mount_t *mp = dp->i_mount; |
| 2115 | xfs_trans_t *tp = NULL; | 1895 | xfs_trans_t *tp = NULL; |
| 1896 | int is_dir = S_ISDIR(ip->i_d.di_mode); | ||
| 2116 | int error = 0; | 1897 | int error = 0; |
| 2117 | xfs_bmap_free_t free_list; | 1898 | xfs_bmap_free_t free_list; |
| 2118 | xfs_fsblock_t first_block; | 1899 | xfs_fsblock_t first_block; |
| @@ -2120,8 +1901,10 @@ xfs_remove( | |||
| 2120 | int committed; | 1901 | int committed; |
| 2121 | int link_zero; | 1902 | int link_zero; |
| 2122 | uint resblks; | 1903 | uint resblks; |
| 1904 | uint log_count; | ||
| 2123 | 1905 | ||
| 2124 | xfs_itrace_entry(dp); | 1906 | xfs_itrace_entry(dp); |
| 1907 | xfs_itrace_entry(ip); | ||
| 2125 | 1908 | ||
| 2126 | if (XFS_FORCED_SHUTDOWN(mp)) | 1909 | if (XFS_FORCED_SHUTDOWN(mp)) |
| 2127 | return XFS_ERROR(EIO); | 1910 | return XFS_ERROR(EIO); |
| @@ -2134,19 +1917,23 @@ xfs_remove( | |||
| 2134 | return error; | 1917 | return error; |
| 2135 | } | 1918 | } |
| 2136 | 1919 | ||
| 2137 | xfs_itrace_entry(ip); | ||
| 2138 | xfs_itrace_ref(ip); | ||
| 2139 | |||
| 2140 | error = XFS_QM_DQATTACH(mp, dp, 0); | 1920 | error = XFS_QM_DQATTACH(mp, dp, 0); |
| 2141 | if (!error) | 1921 | if (error) |
| 2142 | error = XFS_QM_DQATTACH(mp, ip, 0); | ||
| 2143 | if (error) { | ||
| 2144 | REMOVE_DEBUG_TRACE(__LINE__); | ||
| 2145 | goto std_return; | 1922 | goto std_return; |
| 2146 | } | ||
| 2147 | 1923 | ||
| 2148 | tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); | 1924 | error = XFS_QM_DQATTACH(mp, ip, 0); |
| 1925 | if (error) | ||
| 1926 | goto std_return; | ||
| 1927 | |||
| 1928 | if (is_dir) { | ||
| 1929 | tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); | ||
| 1930 | log_count = XFS_DEFAULT_LOG_COUNT; | ||
| 1931 | } else { | ||
| 1932 | tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); | ||
| 1933 | log_count = XFS_REMOVE_LOG_COUNT; | ||
| 1934 | } | ||
| 2149 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | 1935 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; |
| 1936 | |||
| 2150 | /* | 1937 | /* |
| 2151 | * We try to get the real space reservation first, | 1938 | * We try to get the real space reservation first, |
| 2152 | * allowing for directory btree deletion(s) implying | 1939 | * allowing for directory btree deletion(s) implying |
| @@ -2158,25 +1945,19 @@ xfs_remove( | |||
| 2158 | */ | 1945 | */ |
| 2159 | resblks = XFS_REMOVE_SPACE_RES(mp); | 1946 | resblks = XFS_REMOVE_SPACE_RES(mp); |
| 2160 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, | 1947 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, |
| 2161 | XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); | 1948 | XFS_TRANS_PERM_LOG_RES, log_count); |
| 2162 | if (error == ENOSPC) { | 1949 | if (error == ENOSPC) { |
| 2163 | resblks = 0; | 1950 | resblks = 0; |
| 2164 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, | 1951 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, |
| 2165 | XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); | 1952 | XFS_TRANS_PERM_LOG_RES, log_count); |
| 2166 | } | 1953 | } |
| 2167 | if (error) { | 1954 | if (error) { |
| 2168 | ASSERT(error != ENOSPC); | 1955 | ASSERT(error != ENOSPC); |
| 2169 | REMOVE_DEBUG_TRACE(__LINE__); | 1956 | cancel_flags = 0; |
| 2170 | xfs_trans_cancel(tp, 0); | 1957 | goto out_trans_cancel; |
| 2171 | return error; | ||
| 2172 | } | 1958 | } |
| 2173 | 1959 | ||
| 2174 | error = xfs_lock_dir_and_entry(dp, ip); | 1960 | xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL); |
| 2175 | if (error) { | ||
| 2176 | REMOVE_DEBUG_TRACE(__LINE__); | ||
| 2177 | xfs_trans_cancel(tp, cancel_flags); | ||
| 2178 | goto std_return; | ||
| 2179 | } | ||
| 2180 | 1961 | ||
| 2181 | /* | 1962 | /* |
| 2182 | * At this point, we've gotten both the directory and the entry | 1963 | * At this point, we've gotten both the directory and the entry |
| @@ -2189,46 +1970,83 @@ xfs_remove( | |||
| 2189 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 1970 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
| 2190 | 1971 | ||
| 2191 | /* | 1972 | /* |
| 2192 | * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. | 1973 | * If we're removing a directory perform some additional validation. |
| 2193 | */ | 1974 | */ |
| 1975 | if (is_dir) { | ||
| 1976 | ASSERT(ip->i_d.di_nlink >= 2); | ||
| 1977 | if (ip->i_d.di_nlink != 2) { | ||
| 1978 | error = XFS_ERROR(ENOTEMPTY); | ||
| 1979 | goto out_trans_cancel; | ||
| 1980 | } | ||
| 1981 | if (!xfs_dir_isempty(ip)) { | ||
| 1982 | error = XFS_ERROR(ENOTEMPTY); | ||
| 1983 | goto out_trans_cancel; | ||
| 1984 | } | ||
| 1985 | } | ||
| 1986 | |||
| 2194 | XFS_BMAP_INIT(&free_list, &first_block); | 1987 | XFS_BMAP_INIT(&free_list, &first_block); |
| 2195 | error = xfs_dir_removename(tp, dp, name, ip->i_ino, | 1988 | error = xfs_dir_removename(tp, dp, name, ip->i_ino, |
| 2196 | &first_block, &free_list, resblks); | 1989 | &first_block, &free_list, resblks); |
| 2197 | if (error) { | 1990 | if (error) { |
| 2198 | ASSERT(error != ENOENT); | 1991 | ASSERT(error != ENOENT); |
| 2199 | REMOVE_DEBUG_TRACE(__LINE__); | 1992 | goto out_bmap_cancel; |
| 2200 | goto error1; | ||
| 2201 | } | 1993 | } |
| 2202 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 1994 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 2203 | 1995 | ||
| 1996 | /* | ||
| 1997 | * Bump the in memory generation count on the parent | ||
| 1998 | * directory so that other can know that it has changed. | ||
| 1999 | */ | ||
| 2204 | dp->i_gen++; | 2000 | dp->i_gen++; |
| 2205 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 2001 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
| 2206 | 2002 | ||
| 2207 | error = xfs_droplink(tp, ip); | 2003 | if (is_dir) { |
| 2208 | if (error) { | 2004 | /* |
| 2209 | REMOVE_DEBUG_TRACE(__LINE__); | 2005 | * Drop the link from ip's "..". |
| 2210 | goto error1; | 2006 | */ |
| 2007 | error = xfs_droplink(tp, dp); | ||
| 2008 | if (error) | ||
| 2009 | goto out_bmap_cancel; | ||
| 2010 | |||
| 2011 | /* | ||
| 2012 | * Drop the link from dp to ip. | ||
| 2013 | */ | ||
| 2014 | error = xfs_droplink(tp, ip); | ||
| 2015 | if (error) | ||
| 2016 | goto out_bmap_cancel; | ||
| 2017 | } else { | ||
| 2018 | /* | ||
| 2019 | * When removing a non-directory we need to log the parent | ||
| 2020 | * inode here for the i_gen update. For a directory this is | ||
| 2021 | * done implicitly by the xfs_droplink call for the ".." entry. | ||
| 2022 | */ | ||
| 2023 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | ||
| 2211 | } | 2024 | } |
| 2212 | 2025 | ||
| 2213 | /* Determine if this is the last link while | 2026 | /* |
| 2027 | * Drop the "." link from ip to self. | ||
| 2028 | */ | ||
| 2029 | error = xfs_droplink(tp, ip); | ||
| 2030 | if (error) | ||
| 2031 | goto out_bmap_cancel; | ||
| 2032 | |||
| 2033 | /* | ||
| 2034 | * Determine if this is the last link while | ||
| 2214 | * we are in the transaction. | 2035 | * we are in the transaction. |
| 2215 | */ | 2036 | */ |
| 2216 | link_zero = (ip)->i_d.di_nlink==0; | 2037 | link_zero = (ip->i_d.di_nlink == 0); |
| 2217 | 2038 | ||
| 2218 | /* | 2039 | /* |
| 2219 | * If this is a synchronous mount, make sure that the | 2040 | * If this is a synchronous mount, make sure that the |
| 2220 | * remove transaction goes to disk before returning to | 2041 | * remove transaction goes to disk before returning to |
| 2221 | * the user. | 2042 | * the user. |
| 2222 | */ | 2043 | */ |
| 2223 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | 2044 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) |
| 2224 | xfs_trans_set_sync(tp); | 2045 | xfs_trans_set_sync(tp); |
| 2225 | } | ||
| 2226 | 2046 | ||
| 2227 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 2047 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
| 2228 | if (error) { | 2048 | if (error) |
| 2229 | REMOVE_DEBUG_TRACE(__LINE__); | 2049 | goto out_bmap_cancel; |
| 2230 | goto error_rele; | ||
| 2231 | } | ||
| 2232 | 2050 | ||
| 2233 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 2051 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
| 2234 | if (error) | 2052 | if (error) |
| @@ -2240,38 +2058,26 @@ xfs_remove( | |||
| 2240 | * will get killed on last close in xfs_close() so we don't | 2058 | * will get killed on last close in xfs_close() so we don't |
| 2241 | * have to worry about that. | 2059 | * have to worry about that. |
| 2242 | */ | 2060 | */ |
| 2243 | if (link_zero && xfs_inode_is_filestream(ip)) | 2061 | if (!is_dir && link_zero && xfs_inode_is_filestream(ip)) |
| 2244 | xfs_filestream_deassociate(ip); | 2062 | xfs_filestream_deassociate(ip); |
| 2245 | 2063 | ||
| 2246 | xfs_itrace_exit(ip); | 2064 | xfs_itrace_exit(ip); |
| 2065 | xfs_itrace_exit(dp); | ||
| 2247 | 2066 | ||
| 2248 | /* Fall through to std_return with error = 0 */ | ||
| 2249 | std_return: | 2067 | std_return: |
| 2250 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { | 2068 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { |
| 2251 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, | 2069 | XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, dp, DM_RIGHT_NULL, |
| 2252 | dp, DM_RIGHT_NULL, | 2070 | NULL, DM_RIGHT_NULL, name->name, NULL, |
| 2253 | NULL, DM_RIGHT_NULL, | 2071 | ip->i_d.di_mode, error, 0); |
| 2254 | name->name, NULL, ip->i_d.di_mode, error, 0); | ||
| 2255 | } | 2072 | } |
| 2256 | return error; | ||
| 2257 | 2073 | ||
| 2258 | error1: | 2074 | return error; |
| 2259 | xfs_bmap_cancel(&free_list); | ||
| 2260 | cancel_flags |= XFS_TRANS_ABORT; | ||
| 2261 | xfs_trans_cancel(tp, cancel_flags); | ||
| 2262 | goto std_return; | ||
| 2263 | 2075 | ||
| 2264 | error_rele: | 2076 | out_bmap_cancel: |
| 2265 | /* | ||
| 2266 | * In this case make sure to not release the inode until after | ||
| 2267 | * the current transaction is aborted. Releasing it beforehand | ||
| 2268 | * can cause us to go to xfs_inactive and start a recursive | ||
| 2269 | * transaction which can easily deadlock with the current one. | ||
| 2270 | */ | ||
| 2271 | xfs_bmap_cancel(&free_list); | 2077 | xfs_bmap_cancel(&free_list); |
| 2272 | cancel_flags |= XFS_TRANS_ABORT; | 2078 | cancel_flags |= XFS_TRANS_ABORT; |
| 2079 | out_trans_cancel: | ||
| 2273 | xfs_trans_cancel(tp, cancel_flags); | 2080 | xfs_trans_cancel(tp, cancel_flags); |
| 2274 | |||
| 2275 | goto std_return; | 2081 | goto std_return; |
| 2276 | } | 2082 | } |
| 2277 | 2083 | ||
| @@ -2283,7 +2089,6 @@ xfs_link( | |||
| 2283 | { | 2089 | { |
| 2284 | xfs_mount_t *mp = tdp->i_mount; | 2090 | xfs_mount_t *mp = tdp->i_mount; |
| 2285 | xfs_trans_t *tp; | 2091 | xfs_trans_t *tp; |
| 2286 | xfs_inode_t *ips[2]; | ||
| 2287 | int error; | 2092 | int error; |
| 2288 | xfs_bmap_free_t free_list; | 2093 | xfs_bmap_free_t free_list; |
| 2289 | xfs_fsblock_t first_block; | 2094 | xfs_fsblock_t first_block; |
| @@ -2331,15 +2136,7 @@ xfs_link( | |||
| 2331 | goto error_return; | 2136 | goto error_return; |
| 2332 | } | 2137 | } |
| 2333 | 2138 | ||
| 2334 | if (sip->i_ino < tdp->i_ino) { | 2139 | xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL); |
| 2335 | ips[0] = sip; | ||
| 2336 | ips[1] = tdp; | ||
| 2337 | } else { | ||
| 2338 | ips[0] = tdp; | ||
| 2339 | ips[1] = sip; | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL); | ||
| 2343 | 2140 | ||
| 2344 | /* | 2141 | /* |
| 2345 | * Increment vnode ref counts since xfs_trans_commit & | 2142 | * Increment vnode ref counts since xfs_trans_commit & |
| @@ -2480,7 +2277,7 @@ xfs_mkdir( | |||
| 2480 | * Make sure that we have allocated dquot(s) on disk. | 2277 | * Make sure that we have allocated dquot(s) on disk. |
| 2481 | */ | 2278 | */ |
| 2482 | error = XFS_QM_DQVOPALLOC(mp, dp, | 2279 | error = XFS_QM_DQVOPALLOC(mp, dp, |
| 2483 | current_fsuid(credp), current_fsgid(credp), prid, | 2280 | current_fsuid(), current_fsgid(), prid, |
| 2484 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 2281 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
| 2485 | if (error) | 2282 | if (error) |
| 2486 | goto std_return; | 2283 | goto std_return; |
| @@ -2638,186 +2435,6 @@ std_return: | |||
| 2638 | } | 2435 | } |
| 2639 | 2436 | ||
| 2640 | int | 2437 | int |
| 2641 | xfs_rmdir( | ||
| 2642 | xfs_inode_t *dp, | ||
| 2643 | struct xfs_name *name, | ||
| 2644 | xfs_inode_t *cdp) | ||
| 2645 | { | ||
| 2646 | xfs_mount_t *mp = dp->i_mount; | ||
| 2647 | xfs_trans_t *tp; | ||
| 2648 | int error; | ||
| 2649 | xfs_bmap_free_t free_list; | ||
| 2650 | xfs_fsblock_t first_block; | ||
| 2651 | int cancel_flags; | ||
| 2652 | int committed; | ||
| 2653 | int last_cdp_link; | ||
| 2654 | uint resblks; | ||
| 2655 | |||
| 2656 | xfs_itrace_entry(dp); | ||
| 2657 | |||
| 2658 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 2659 | return XFS_ERROR(EIO); | ||
| 2660 | |||
| 2661 | if (DM_EVENT_ENABLED(dp, DM_EVENT_REMOVE)) { | ||
| 2662 | error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, | ||
| 2663 | dp, DM_RIGHT_NULL, | ||
| 2664 | NULL, DM_RIGHT_NULL, name->name, | ||
| 2665 | NULL, cdp->i_d.di_mode, 0, 0); | ||
| 2666 | if (error) | ||
| 2667 | return XFS_ERROR(error); | ||
| 2668 | } | ||
| 2669 | |||
| 2670 | /* | ||
| 2671 | * Get the dquots for the inodes. | ||
| 2672 | */ | ||
| 2673 | error = XFS_QM_DQATTACH(mp, dp, 0); | ||
| 2674 | if (!error) | ||
| 2675 | error = XFS_QM_DQATTACH(mp, cdp, 0); | ||
| 2676 | if (error) { | ||
| 2677 | REMOVE_DEBUG_TRACE(__LINE__); | ||
| 2678 | goto std_return; | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); | ||
| 2682 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | ||
| 2683 | /* | ||
| 2684 | * We try to get the real space reservation first, | ||
| 2685 | * allowing for directory btree deletion(s) implying | ||
| 2686 | * possible bmap insert(s). If we can't get the space | ||
| 2687 | * reservation then we use 0 instead, and avoid the bmap | ||
| 2688 | * btree insert(s) in the directory code by, if the bmap | ||
| 2689 | * insert tries to happen, instead trimming the LAST | ||
| 2690 | * block from the directory. | ||
| 2691 | */ | ||
| 2692 | resblks = XFS_REMOVE_SPACE_RES(mp); | ||
| 2693 | error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, | ||
| 2694 | XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); | ||
| 2695 | if (error == ENOSPC) { | ||
| 2696 | resblks = 0; | ||
| 2697 | error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, | ||
| 2698 | XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); | ||
| 2699 | } | ||
| 2700 | if (error) { | ||
| 2701 | ASSERT(error != ENOSPC); | ||
| 2702 | cancel_flags = 0; | ||
| 2703 | goto error_return; | ||
| 2704 | } | ||
| 2705 | XFS_BMAP_INIT(&free_list, &first_block); | ||
| 2706 | |||
| 2707 | /* | ||
| 2708 | * Now lock the child directory inode and the parent directory | ||
| 2709 | * inode in the proper order. This will take care of validating | ||
| 2710 | * that the directory entry for the child directory inode has | ||
| 2711 | * not changed while we were obtaining a log reservation. | ||
| 2712 | */ | ||
| 2713 | error = xfs_lock_dir_and_entry(dp, cdp); | ||
| 2714 | if (error) { | ||
| 2715 | xfs_trans_cancel(tp, cancel_flags); | ||
| 2716 | goto std_return; | ||
| 2717 | } | ||
| 2718 | |||
| 2719 | IHOLD(dp); | ||
| 2720 | xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); | ||
| 2721 | |||
| 2722 | IHOLD(cdp); | ||
| 2723 | xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); | ||
| 2724 | |||
| 2725 | ASSERT(cdp->i_d.di_nlink >= 2); | ||
| 2726 | if (cdp->i_d.di_nlink != 2) { | ||
| 2727 | error = XFS_ERROR(ENOTEMPTY); | ||
| 2728 | goto error_return; | ||
| 2729 | } | ||
| 2730 | if (!xfs_dir_isempty(cdp)) { | ||
| 2731 | error = XFS_ERROR(ENOTEMPTY); | ||
| 2732 | goto error_return; | ||
| 2733 | } | ||
| 2734 | |||
| 2735 | error = xfs_dir_removename(tp, dp, name, cdp->i_ino, | ||
| 2736 | &first_block, &free_list, resblks); | ||
| 2737 | if (error) | ||
| 2738 | goto error1; | ||
| 2739 | |||
| 2740 | xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | ||
| 2741 | |||
| 2742 | /* | ||
| 2743 | * Bump the in memory generation count on the parent | ||
| 2744 | * directory so that other can know that it has changed. | ||
| 2745 | */ | ||
| 2746 | dp->i_gen++; | ||
| 2747 | |||
| 2748 | /* | ||
| 2749 | * Drop the link from cdp's "..". | ||
| 2750 | */ | ||
| 2751 | error = xfs_droplink(tp, dp); | ||
| 2752 | if (error) { | ||
| 2753 | goto error1; | ||
| 2754 | } | ||
| 2755 | |||
| 2756 | /* | ||
| 2757 | * Drop the link from dp to cdp. | ||
| 2758 | */ | ||
| 2759 | error = xfs_droplink(tp, cdp); | ||
| 2760 | if (error) { | ||
| 2761 | goto error1; | ||
| 2762 | } | ||
| 2763 | |||
| 2764 | /* | ||
| 2765 | * Drop the "." link from cdp to self. | ||
| 2766 | */ | ||
| 2767 | error = xfs_droplink(tp, cdp); | ||
| 2768 | if (error) { | ||
| 2769 | goto error1; | ||
| 2770 | } | ||
| 2771 | |||
| 2772 | /* Determine these before committing transaction */ | ||
| 2773 | last_cdp_link = (cdp)->i_d.di_nlink==0; | ||
| 2774 | |||
| 2775 | /* | ||
| 2776 | * If this is a synchronous mount, make sure that the | ||
| 2777 | * rmdir transaction goes to disk before returning to | ||
| 2778 | * the user. | ||
| 2779 | */ | ||
| 2780 | if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { | ||
| 2781 | xfs_trans_set_sync(tp); | ||
| 2782 | } | ||
| 2783 | |||
| 2784 | error = xfs_bmap_finish (&tp, &free_list, &committed); | ||
| 2785 | if (error) { | ||
| 2786 | xfs_bmap_cancel(&free_list); | ||
| 2787 | xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | | ||
| 2788 | XFS_TRANS_ABORT)); | ||
| 2789 | goto std_return; | ||
| 2790 | } | ||
| 2791 | |||
| 2792 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | ||
| 2793 | if (error) { | ||
| 2794 | goto std_return; | ||
| 2795 | } | ||
| 2796 | |||
| 2797 | |||
| 2798 | /* Fall through to std_return with error = 0 or the errno | ||
| 2799 | * from xfs_trans_commit. */ | ||
| 2800 | std_return: | ||
| 2801 | if (DM_EVENT_ENABLED(dp, DM_EVENT_POSTREMOVE)) { | ||
| 2802 | (void) XFS_SEND_NAMESP(mp, DM_EVENT_POSTREMOVE, | ||
| 2803 | dp, DM_RIGHT_NULL, | ||
| 2804 | NULL, DM_RIGHT_NULL, | ||
| 2805 | name->name, NULL, cdp->i_d.di_mode, | ||
| 2806 | error, 0); | ||
| 2807 | } | ||
| 2808 | return error; | ||
| 2809 | |||
| 2810 | error1: | ||
| 2811 | xfs_bmap_cancel(&free_list); | ||
| 2812 | cancel_flags |= XFS_TRANS_ABORT; | ||
| 2813 | /* FALLTHROUGH */ | ||
| 2814 | |||
| 2815 | error_return: | ||
| 2816 | xfs_trans_cancel(tp, cancel_flags); | ||
| 2817 | goto std_return; | ||
| 2818 | } | ||
| 2819 | |||
| 2820 | int | ||
| 2821 | xfs_symlink( | 2438 | xfs_symlink( |
| 2822 | xfs_inode_t *dp, | 2439 | xfs_inode_t *dp, |
| 2823 | struct xfs_name *link_name, | 2440 | struct xfs_name *link_name, |
| @@ -2886,7 +2503,7 @@ xfs_symlink( | |||
| 2886 | * Make sure that we have allocated dquot(s) on disk. | 2503 | * Make sure that we have allocated dquot(s) on disk. |
| 2887 | */ | 2504 | */ |
| 2888 | error = XFS_QM_DQVOPALLOC(mp, dp, | 2505 | error = XFS_QM_DQVOPALLOC(mp, dp, |
| 2889 | current_fsuid(credp), current_fsgid(credp), prid, | 2506 | current_fsuid(), current_fsgid(), prid, |
| 2890 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 2507 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
| 2891 | if (error) | 2508 | if (error) |
| 2892 | goto std_return; | 2509 | goto std_return; |
| @@ -3181,14 +2798,13 @@ int | |||
| 3181 | xfs_reclaim( | 2798 | xfs_reclaim( |
| 3182 | xfs_inode_t *ip) | 2799 | xfs_inode_t *ip) |
| 3183 | { | 2800 | { |
| 3184 | bhv_vnode_t *vp = XFS_ITOV(ip); | ||
| 3185 | 2801 | ||
| 3186 | xfs_itrace_entry(ip); | 2802 | xfs_itrace_entry(ip); |
| 3187 | 2803 | ||
| 3188 | ASSERT(!VN_MAPPED(vp)); | 2804 | ASSERT(!VN_MAPPED(VFS_I(ip))); |
| 3189 | 2805 | ||
| 3190 | /* bad inode, get out here ASAP */ | 2806 | /* bad inode, get out here ASAP */ |
| 3191 | if (VN_BAD(vp)) { | 2807 | if (VN_BAD(VFS_I(ip))) { |
| 3192 | xfs_ireclaim(ip); | 2808 | xfs_ireclaim(ip); |
| 3193 | return 0; | 2809 | return 0; |
| 3194 | } | 2810 | } |
| @@ -3225,7 +2841,7 @@ xfs_reclaim( | |||
| 3225 | XFS_MOUNT_ILOCK(mp); | 2841 | XFS_MOUNT_ILOCK(mp); |
| 3226 | spin_lock(&ip->i_flags_lock); | 2842 | spin_lock(&ip->i_flags_lock); |
| 3227 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); | 2843 | __xfs_iflags_set(ip, XFS_IRECLAIMABLE); |
| 3228 | vn_to_inode(vp)->i_private = NULL; | 2844 | VFS_I(ip)->i_private = NULL; |
| 3229 | ip->i_vnode = NULL; | 2845 | ip->i_vnode = NULL; |
| 3230 | spin_unlock(&ip->i_flags_lock); | 2846 | spin_unlock(&ip->i_flags_lock); |
| 3231 | list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); | 2847 | list_add_tail(&ip->i_reclaim, &mp->m_del_inodes); |
| @@ -3241,8 +2857,7 @@ xfs_finish_reclaim( | |||
| 3241 | int sync_mode) | 2857 | int sync_mode) |
| 3242 | { | 2858 | { |
| 3243 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); | 2859 | xfs_perag_t *pag = xfs_get_perag(ip->i_mount, ip->i_ino); |
| 3244 | bhv_vnode_t *vp = XFS_ITOV_NULL(ip); | 2860 | struct inode *vp = VFS_I(ip); |
| 3245 | int error; | ||
| 3246 | 2861 | ||
| 3247 | if (vp && VN_BAD(vp)) | 2862 | if (vp && VN_BAD(vp)) |
| 3248 | goto reclaim; | 2863 | goto reclaim; |
| @@ -3285,29 +2900,16 @@ xfs_finish_reclaim( | |||
| 3285 | xfs_iflock(ip); | 2900 | xfs_iflock(ip); |
| 3286 | } | 2901 | } |
| 3287 | 2902 | ||
| 3288 | if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { | 2903 | /* |
| 3289 | if (ip->i_update_core || | 2904 | * In the case of a forced shutdown we rely on xfs_iflush() to |
| 3290 | ((ip->i_itemp != NULL) && | 2905 | * wait for the inode to be unpinned before returning an error. |
| 3291 | (ip->i_itemp->ili_format.ilf_fields != 0))) { | 2906 | */ |
| 3292 | error = xfs_iflush(ip, sync_mode); | 2907 | if (xfs_iflush(ip, sync_mode) == 0) { |
| 3293 | /* | 2908 | /* synchronize with xfs_iflush_done */ |
| 3294 | * If we hit an error, typically because of filesystem | 2909 | xfs_iflock(ip); |
| 3295 | * shutdown, we don't need to let vn_reclaim to know | 2910 | xfs_ifunlock(ip); |
| 3296 | * because we're gonna reclaim the inode anyway. | ||
| 3297 | */ | ||
| 3298 | if (error) { | ||
| 3299 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | ||
| 3300 | goto reclaim; | ||
| 3301 | } | ||
| 3302 | xfs_iflock(ip); /* synchronize with xfs_iflush_done */ | ||
| 3303 | } | ||
| 3304 | |||
| 3305 | ASSERT(ip->i_update_core == 0); | ||
| 3306 | ASSERT(ip->i_itemp == NULL || | ||
| 3307 | ip->i_itemp->ili_format.ilf_fields == 0); | ||
| 3308 | } | 2911 | } |
| 3309 | 2912 | ||
| 3310 | xfs_ifunlock(ip); | ||
| 3311 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 2913 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 3312 | 2914 | ||
| 3313 | reclaim: | 2915 | reclaim: |
| @@ -3418,7 +3020,7 @@ xfs_alloc_file_space( | |||
| 3418 | 3020 | ||
| 3419 | /* Generate a DMAPI event if needed. */ | 3021 | /* Generate a DMAPI event if needed. */ |
| 3420 | if (alloc_type != 0 && offset < ip->i_size && | 3022 | if (alloc_type != 0 && offset < ip->i_size && |
| 3421 | (attr_flags&ATTR_DMI) == 0 && | 3023 | (attr_flags & XFS_ATTR_DMI) == 0 && |
| 3422 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { | 3024 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { |
| 3423 | xfs_off_t end_dmi_offset; | 3025 | xfs_off_t end_dmi_offset; |
| 3424 | 3026 | ||
| @@ -3532,7 +3134,7 @@ retry: | |||
| 3532 | allocatesize_fsb -= allocated_fsb; | 3134 | allocatesize_fsb -= allocated_fsb; |
| 3533 | } | 3135 | } |
| 3534 | dmapi_enospc_check: | 3136 | dmapi_enospc_check: |
| 3535 | if (error == ENOSPC && (attr_flags & ATTR_DMI) == 0 && | 3137 | if (error == ENOSPC && (attr_flags & XFS_ATTR_DMI) == 0 && |
| 3536 | DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) { | 3138 | DM_EVENT_ENABLED(ip, DM_EVENT_NOSPACE)) { |
| 3537 | error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE, | 3139 | error = XFS_SEND_NAMESP(mp, DM_EVENT_NOSPACE, |
| 3538 | ip, DM_RIGHT_NULL, | 3140 | ip, DM_RIGHT_NULL, |
| @@ -3558,6 +3160,13 @@ error1: /* Just cancel transaction */ | |||
| 3558 | /* | 3160 | /* |
| 3559 | * Zero file bytes between startoff and endoff inclusive. | 3161 | * Zero file bytes between startoff and endoff inclusive. |
| 3560 | * The iolock is held exclusive and no blocks are buffered. | 3162 | * The iolock is held exclusive and no blocks are buffered. |
| 3163 | * | ||
| 3164 | * This function is used by xfs_free_file_space() to zero | ||
| 3165 | * partial blocks when the range to free is not block aligned. | ||
| 3166 | * When unreserving space with boundaries that are not block | ||
| 3167 | * aligned we round up the start and round down the end | ||
| 3168 | * boundaries and then use this function to zero the parts of | ||
| 3169 | * the blocks that got dropped during the rounding. | ||
| 3561 | */ | 3170 | */ |
| 3562 | STATIC int | 3171 | STATIC int |
| 3563 | xfs_zero_remaining_bytes( | 3172 | xfs_zero_remaining_bytes( |
| @@ -3574,6 +3183,17 @@ xfs_zero_remaining_bytes( | |||
| 3574 | int nimap; | 3183 | int nimap; |
| 3575 | int error = 0; | 3184 | int error = 0; |
| 3576 | 3185 | ||
| 3186 | /* | ||
| 3187 | * Avoid doing I/O beyond eof - it's not necessary | ||
| 3188 | * since nothing can read beyond eof. The space will | ||
| 3189 | * be zeroed when the file is extended anyway. | ||
| 3190 | */ | ||
| 3191 | if (startoff >= ip->i_size) | ||
| 3192 | return 0; | ||
| 3193 | |||
| 3194 | if (endoff > ip->i_size) | ||
| 3195 | endoff = ip->i_size; | ||
| 3196 | |||
| 3577 | bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, | 3197 | bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize, |
| 3578 | XFS_IS_REALTIME_INODE(ip) ? | 3198 | XFS_IS_REALTIME_INODE(ip) ? |
| 3579 | mp->m_rtdev_targp : mp->m_ddev_targp); | 3199 | mp->m_rtdev_targp : mp->m_ddev_targp); |
| @@ -3643,7 +3263,6 @@ xfs_free_file_space( | |||
| 3643 | xfs_off_t len, | 3263 | xfs_off_t len, |
| 3644 | int attr_flags) | 3264 | int attr_flags) |
| 3645 | { | 3265 | { |
| 3646 | bhv_vnode_t *vp; | ||
| 3647 | int committed; | 3266 | int committed; |
| 3648 | int done; | 3267 | int done; |
| 3649 | xfs_off_t end_dmi_offset; | 3268 | xfs_off_t end_dmi_offset; |
| @@ -3663,7 +3282,6 @@ xfs_free_file_space( | |||
| 3663 | xfs_trans_t *tp; | 3282 | xfs_trans_t *tp; |
| 3664 | int need_iolock = 1; | 3283 | int need_iolock = 1; |
| 3665 | 3284 | ||
| 3666 | vp = XFS_ITOV(ip); | ||
| 3667 | mp = ip->i_mount; | 3285 | mp = ip->i_mount; |
| 3668 | 3286 | ||
| 3669 | xfs_itrace_entry(ip); | 3287 | xfs_itrace_entry(ip); |
| @@ -3679,7 +3297,7 @@ xfs_free_file_space( | |||
| 3679 | end_dmi_offset = offset + len; | 3297 | end_dmi_offset = offset + len; |
| 3680 | endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); | 3298 | endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); |
| 3681 | 3299 | ||
| 3682 | if (offset < ip->i_size && (attr_flags & ATTR_DMI) == 0 && | 3300 | if (offset < ip->i_size && (attr_flags & XFS_ATTR_DMI) == 0 && |
| 3683 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { | 3301 | DM_EVENT_ENABLED(ip, DM_EVENT_WRITE)) { |
| 3684 | if (end_dmi_offset > ip->i_size) | 3302 | if (end_dmi_offset > ip->i_size) |
| 3685 | end_dmi_offset = ip->i_size; | 3303 | end_dmi_offset = ip->i_size; |
| @@ -3690,7 +3308,7 @@ xfs_free_file_space( | |||
| 3690 | return error; | 3308 | return error; |
| 3691 | } | 3309 | } |
| 3692 | 3310 | ||
| 3693 | if (attr_flags & ATTR_NOLOCK) | 3311 | if (attr_flags & XFS_ATTR_NOLOCK) |
| 3694 | need_iolock = 0; | 3312 | need_iolock = 0; |
| 3695 | if (need_iolock) { | 3313 | if (need_iolock) { |
| 3696 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 3314 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
| @@ -3700,7 +3318,7 @@ xfs_free_file_space( | |||
| 3700 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); | 3318 | rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE); |
| 3701 | ioffset = offset & ~(rounding - 1); | 3319 | ioffset = offset & ~(rounding - 1); |
| 3702 | 3320 | ||
| 3703 | if (VN_CACHED(vp) != 0) { | 3321 | if (VN_CACHED(VFS_I(ip)) != 0) { |
| 3704 | xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1); | 3322 | xfs_inval_cached_trace(ip, ioffset, -1, ioffset, -1); |
| 3705 | error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); | 3323 | error = xfs_flushinval_pages(ip, ioffset, -1, FI_REMAPF_LOCKED); |
| 3706 | if (error) | 3324 | if (error) |
| @@ -3867,7 +3485,7 @@ xfs_change_file_space( | |||
| 3867 | xfs_off_t startoffset; | 3485 | xfs_off_t startoffset; |
| 3868 | xfs_off_t llen; | 3486 | xfs_off_t llen; |
| 3869 | xfs_trans_t *tp; | 3487 | xfs_trans_t *tp; |
| 3870 | bhv_vattr_t va; | 3488 | struct iattr iattr; |
| 3871 | 3489 | ||
| 3872 | xfs_itrace_entry(ip); | 3490 | xfs_itrace_entry(ip); |
| 3873 | 3491 | ||
| @@ -3941,10 +3559,10 @@ xfs_change_file_space( | |||
| 3941 | break; | 3559 | break; |
| 3942 | } | 3560 | } |
| 3943 | 3561 | ||
| 3944 | va.va_mask = XFS_AT_SIZE; | 3562 | iattr.ia_valid = ATTR_SIZE; |
| 3945 | va.va_size = startoffset; | 3563 | iattr.ia_size = startoffset; |
| 3946 | 3564 | ||
| 3947 | error = xfs_setattr(ip, &va, attr_flags, credp); | 3565 | error = xfs_setattr(ip, &iattr, attr_flags, credp); |
| 3948 | 3566 | ||
| 3949 | if (error) | 3567 | if (error) |
| 3950 | return error; | 3568 | return error; |
| @@ -3974,7 +3592,7 @@ xfs_change_file_space( | |||
| 3974 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 3592 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); |
| 3975 | xfs_trans_ihold(tp, ip); | 3593 | xfs_trans_ihold(tp, ip); |
| 3976 | 3594 | ||
| 3977 | if ((attr_flags & ATTR_DMI) == 0) { | 3595 | if ((attr_flags & XFS_ATTR_DMI) == 0) { |
| 3978 | ip->i_d.di_mode &= ~S_ISUID; | 3596 | ip->i_d.di_mode &= ~S_ISUID; |
| 3979 | 3597 | ||
| 3980 | /* | 3598 | /* |
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h index 57335ba4ce53..e932a96bec54 100644 --- a/fs/xfs/xfs_vnodeops.h +++ b/fs/xfs/xfs_vnodeops.h | |||
| @@ -2,9 +2,9 @@ | |||
| 2 | #define _XFS_VNODEOPS_H 1 | 2 | #define _XFS_VNODEOPS_H 1 |
| 3 | 3 | ||
| 4 | struct attrlist_cursor_kern; | 4 | struct attrlist_cursor_kern; |
| 5 | struct bhv_vattr; | ||
| 6 | struct cred; | 5 | struct cred; |
| 7 | struct file; | 6 | struct file; |
| 7 | struct iattr; | ||
| 8 | struct inode; | 8 | struct inode; |
| 9 | struct iovec; | 9 | struct iovec; |
| 10 | struct kiocb; | 10 | struct kiocb; |
| @@ -15,14 +15,18 @@ struct xfs_iomap; | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | int xfs_open(struct xfs_inode *ip); | 17 | int xfs_open(struct xfs_inode *ip); |
| 18 | int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags, | 18 | int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags, |
| 19 | struct cred *credp); | 19 | struct cred *credp); |
| 20 | #define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */ | ||
| 21 | #define XFS_ATTR_NONBLOCK 0x02 /* return EAGAIN if operation would block */ | ||
| 22 | #define XFS_ATTR_NOLOCK 0x04 /* Don't grab any conflicting locks */ | ||
| 23 | |||
| 20 | int xfs_readlink(struct xfs_inode *ip, char *link); | 24 | int xfs_readlink(struct xfs_inode *ip, char *link); |
| 21 | int xfs_fsync(struct xfs_inode *ip); | 25 | int xfs_fsync(struct xfs_inode *ip); |
| 22 | int xfs_release(struct xfs_inode *ip); | 26 | int xfs_release(struct xfs_inode *ip); |
| 23 | int xfs_inactive(struct xfs_inode *ip); | 27 | int xfs_inactive(struct xfs_inode *ip); |
| 24 | int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, | 28 | int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, |
| 25 | struct xfs_inode **ipp); | 29 | struct xfs_inode **ipp, struct xfs_name *ci_name); |
| 26 | int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, | 30 | int xfs_create(struct xfs_inode *dp, struct xfs_name *name, mode_t mode, |
| 27 | xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp); | 31 | xfs_dev_t rdev, struct xfs_inode **ipp, struct cred *credp); |
| 28 | int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, | 32 | int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, |
| @@ -31,8 +35,6 @@ int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, | |||
| 31 | struct xfs_name *target_name); | 35 | struct xfs_name *target_name); |
| 32 | int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name, | 36 | int xfs_mkdir(struct xfs_inode *dp, struct xfs_name *dir_name, |
| 33 | mode_t mode, struct xfs_inode **ipp, struct cred *credp); | 37 | mode_t mode, struct xfs_inode **ipp, struct cred *credp); |
| 34 | int xfs_rmdir(struct xfs_inode *dp, struct xfs_name *name, | ||
| 35 | struct xfs_inode *cdp); | ||
| 36 | int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, | 38 | int xfs_readdir(struct xfs_inode *dp, void *dirent, size_t bufsize, |
| 37 | xfs_off_t *offset, filldir_t filldir); | 39 | xfs_off_t *offset, filldir_t filldir); |
| 38 | int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, | 40 | int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, |
