diff options
Diffstat (limited to 'fs')
372 files changed, 14446 insertions, 6784 deletions
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 6fcb1e7095cf..92828281a30b 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c | |||
@@ -57,7 +57,7 @@ static int v9fs_vfs_readpage(struct file *filp, struct page *page) | |||
57 | buffer = kmap(page); | 57 | buffer = kmap(page); |
58 | offset = page_offset(page); | 58 | offset = page_offset(page); |
59 | 59 | ||
60 | retval = v9fs_file_readn(filp, buffer, NULL, offset, PAGE_CACHE_SIZE); | 60 | retval = v9fs_file_readn(filp, buffer, NULL, PAGE_CACHE_SIZE, offset); |
61 | if (retval < 0) | 61 | if (retval < 0) |
62 | goto done; | 62 | goto done; |
63 | 63 | ||
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index ab5547ff29a1..38d695d66a0b 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/mount.h> | 37 | #include <linux/mount.h> |
38 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
40 | #include <linux/smp_lock.h> | ||
41 | #include <net/9p/9p.h> | 40 | #include <net/9p/9p.h> |
42 | #include <net/9p/client.h> | 41 | #include <net/9p/client.h> |
43 | 42 | ||
@@ -231,10 +230,8 @@ v9fs_umount_begin(struct super_block *sb) | |||
231 | { | 230 | { |
232 | struct v9fs_session_info *v9ses; | 231 | struct v9fs_session_info *v9ses; |
233 | 232 | ||
234 | lock_kernel(); | ||
235 | v9ses = sb->s_fs_info; | 233 | v9ses = sb->s_fs_info; |
236 | v9fs_session_cancel(v9ses); | 234 | v9fs_session_cancel(v9ses); |
237 | unlock_kernel(); | ||
238 | } | 235 | } |
239 | 236 | ||
240 | static const struct super_operations v9fs_super_ops = { | 237 | static const struct super_operations v9fs_super_ops = { |
diff --git a/fs/Kconfig b/fs/Kconfig index 525da2e8f73b..0e7da7bb5d93 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -39,6 +39,13 @@ config FS_POSIX_ACL | |||
39 | bool | 39 | bool |
40 | default n | 40 | default n |
41 | 41 | ||
42 | source "fs/xfs/Kconfig" | ||
43 | source "fs/gfs2/Kconfig" | ||
44 | source "fs/ocfs2/Kconfig" | ||
45 | source "fs/btrfs/Kconfig" | ||
46 | |||
47 | endif # BLOCK | ||
48 | |||
42 | config FILE_LOCKING | 49 | config FILE_LOCKING |
43 | bool "Enable POSIX file locking API" if EMBEDDED | 50 | bool "Enable POSIX file locking API" if EMBEDDED |
44 | default y | 51 | default y |
@@ -47,13 +54,6 @@ config FILE_LOCKING | |||
47 | for filesystems like NFS and for the flock() system | 54 | for filesystems like NFS and for the flock() system |
48 | call. Disabling this option saves about 11k. | 55 | call. Disabling this option saves about 11k. |
49 | 56 | ||
50 | source "fs/xfs/Kconfig" | ||
51 | source "fs/gfs2/Kconfig" | ||
52 | source "fs/ocfs2/Kconfig" | ||
53 | source "fs/btrfs/Kconfig" | ||
54 | |||
55 | endif # BLOCK | ||
56 | |||
57 | source "fs/notify/Kconfig" | 57 | source "fs/notify/Kconfig" |
58 | 58 | ||
59 | source "fs/quota/Kconfig" | 59 | source "fs/quota/Kconfig" |
@@ -134,7 +134,7 @@ config TMPFS_POSIX_ACL | |||
134 | config HUGETLBFS | 134 | config HUGETLBFS |
135 | bool "HugeTLB file system support" | 135 | bool "HugeTLB file system support" |
136 | depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || \ | 136 | depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || \ |
137 | (S390 && 64BIT) || BROKEN | 137 | (S390 && 64BIT) || SYS_SUPPORTS_HUGETLBFS || BROKEN |
138 | help | 138 | help |
139 | hugetlbfs is a filesystem backing for HugeTLB pages, based on | 139 | hugetlbfs is a filesystem backing for HugeTLB pages, based on |
140 | ramfs. For architectures that support it, say Y here and read | 140 | ramfs. For architectures that support it, say Y here and read |
@@ -186,32 +186,7 @@ source "fs/romfs/Kconfig" | |||
186 | source "fs/sysv/Kconfig" | 186 | source "fs/sysv/Kconfig" |
187 | source "fs/ufs/Kconfig" | 187 | source "fs/ufs/Kconfig" |
188 | source "fs/exofs/Kconfig" | 188 | source "fs/exofs/Kconfig" |
189 | 189 | source "fs/nilfs2/Kconfig" | |
190 | config NILFS2_FS | ||
191 | tristate "NILFS2 file system support (EXPERIMENTAL)" | ||
192 | depends on BLOCK && EXPERIMENTAL | ||
193 | select CRC32 | ||
194 | help | ||
195 | NILFS2 is a log-structured file system (LFS) supporting continuous | ||
196 | snapshotting. In addition to versioning capability of the entire | ||
197 | file system, users can even restore files mistakenly overwritten or | ||
198 | destroyed just a few seconds ago. Since this file system can keep | ||
199 | consistency like conventional LFS, it achieves quick recovery after | ||
200 | system crashes. | ||
201 | |||
202 | NILFS2 creates a number of checkpoints every few seconds or per | ||
203 | synchronous write basis (unless there is no change). Users can | ||
204 | select significant versions among continuously created checkpoints, | ||
205 | and can change them into snapshots which will be preserved for long | ||
206 | periods until they are changed back to checkpoints. Each | ||
207 | snapshot is mountable as a read-only file system concurrently with | ||
208 | its writable mount, and this feature is convenient for online backup. | ||
209 | |||
210 | Some features including atime, extended attributes, and POSIX ACLs, | ||
211 | are not supported yet. | ||
212 | |||
213 | To compile this file system support as a module, choose M here: the | ||
214 | module will be called nilfs2. If unsure, say N. | ||
215 | 190 | ||
216 | endif # MISC_FILESYSTEMS | 191 | endif # MISC_FILESYSTEMS |
217 | 192 | ||
@@ -236,10 +211,12 @@ source "fs/nfsd/Kconfig" | |||
236 | 211 | ||
237 | config LOCKD | 212 | config LOCKD |
238 | tristate | 213 | tristate |
214 | depends on FILE_LOCKING | ||
239 | 215 | ||
240 | config LOCKD_V4 | 216 | config LOCKD_V4 |
241 | bool | 217 | bool |
242 | depends on NFSD_V3 || NFS_V3 | 218 | depends on NFSD_V3 || NFS_V3 |
219 | depends on FILE_LOCKING | ||
243 | default y | 220 | default y |
244 | 221 | ||
245 | config EXPORTFS | 222 | config EXPORTFS |
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index a6665f37f456..9cc18775b832 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h | |||
@@ -1,3 +1,6 @@ | |||
1 | #include <linux/fs.h> | ||
2 | #include <linux/adfs_fs.h> | ||
3 | |||
1 | /* Internal data structures for ADFS */ | 4 | /* Internal data structures for ADFS */ |
2 | 5 | ||
3 | #define ADFS_FREE_FRAG 0 | 6 | #define ADFS_FREE_FRAG 0 |
@@ -17,6 +20,58 @@ | |||
17 | struct buffer_head; | 20 | struct buffer_head; |
18 | 21 | ||
19 | /* | 22 | /* |
23 | * adfs file system inode data in memory | ||
24 | */ | ||
25 | struct adfs_inode_info { | ||
26 | loff_t mmu_private; | ||
27 | unsigned long parent_id; /* object id of parent */ | ||
28 | __u32 loadaddr; /* RISC OS load address */ | ||
29 | __u32 execaddr; /* RISC OS exec address */ | ||
30 | unsigned int filetype; /* RISC OS file type */ | ||
31 | unsigned int attr; /* RISC OS permissions */ | ||
32 | unsigned int stamped:1; /* RISC OS file has date/time */ | ||
33 | struct inode vfs_inode; | ||
34 | }; | ||
35 | |||
36 | /* | ||
37 | * Forward-declare this | ||
38 | */ | ||
39 | struct adfs_discmap; | ||
40 | struct adfs_dir_ops; | ||
41 | |||
42 | /* | ||
43 | * ADFS file system superblock data in memory | ||
44 | */ | ||
45 | struct adfs_sb_info { | ||
46 | struct adfs_discmap *s_map; /* bh list containing map */ | ||
47 | struct adfs_dir_ops *s_dir; /* directory operations */ | ||
48 | |||
49 | uid_t s_uid; /* owner uid */ | ||
50 | gid_t s_gid; /* owner gid */ | ||
51 | umode_t s_owner_mask; /* ADFS owner perm -> unix perm */ | ||
52 | umode_t s_other_mask; /* ADFS other perm -> unix perm */ | ||
53 | |||
54 | __u32 s_ids_per_zone; /* max. no ids in one zone */ | ||
55 | __u32 s_idlen; /* length of ID in map */ | ||
56 | __u32 s_map_size; /* sector size of a map */ | ||
57 | unsigned long s_size; /* total size (in blocks) of this fs */ | ||
58 | signed int s_map2blk; /* shift left by this for map->sector */ | ||
59 | unsigned int s_log2sharesize;/* log2 share size */ | ||
60 | __le32 s_version; /* disc format version */ | ||
61 | unsigned int s_namelen; /* maximum number of characters in name */ | ||
62 | }; | ||
63 | |||
64 | static inline struct adfs_sb_info *ADFS_SB(struct super_block *sb) | ||
65 | { | ||
66 | return sb->s_fs_info; | ||
67 | } | ||
68 | |||
69 | static inline struct adfs_inode_info *ADFS_I(struct inode *inode) | ||
70 | { | ||
71 | return container_of(inode, struct adfs_inode_info, vfs_inode); | ||
72 | } | ||
73 | |||
74 | /* | ||
20 | * Directory handling | 75 | * Directory handling |
21 | */ | 76 | */ |
22 | struct adfs_dir { | 77 | struct adfs_dir { |
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 4d4073447d1a..23aa52f548a0 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c | |||
@@ -9,15 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Common directory handling for ADFS | 10 | * Common directory handling for ADFS |
11 | */ | 11 | */ |
12 | #include <linux/errno.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/adfs_fs.h> | ||
15 | #include <linux/time.h> | ||
16 | #include <linux/stat.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/smp_lock.h> | 12 | #include <linux/smp_lock.h> |
19 | #include <linux/buffer_head.h> /* for file_fsync() */ | ||
20 | |||
21 | #include "adfs.h" | 13 | #include "adfs.h" |
22 | 14 | ||
23 | /* | 15 | /* |
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c index 31df6adf0de6..bafc71222e25 100644 --- a/fs/adfs/dir_f.c +++ b/fs/adfs/dir_f.c | |||
@@ -9,15 +9,7 @@ | |||
9 | * | 9 | * |
10 | * E and F format directory handling | 10 | * E and F format directory handling |
11 | */ | 11 | */ |
12 | #include <linux/errno.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/adfs_fs.h> | ||
15 | #include <linux/time.h> | ||
16 | #include <linux/stat.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/buffer_head.h> | 12 | #include <linux/buffer_head.h> |
19 | #include <linux/string.h> | ||
20 | |||
21 | #include "adfs.h" | 13 | #include "adfs.h" |
22 | #include "dir_f.h" | 14 | #include "dir_f.h" |
23 | 15 | ||
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index 139e0f345f18..1796bb352d05 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c | |||
@@ -7,15 +7,7 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/errno.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/adfs_fs.h> | ||
13 | #include <linux/time.h> | ||
14 | #include <linux/stat.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/buffer_head.h> | 10 | #include <linux/buffer_head.h> |
17 | #include <linux/string.h> | ||
18 | |||
19 | #include "adfs.h" | 11 | #include "adfs.h" |
20 | #include "dir_fplus.h" | 12 | #include "dir_fplus.h" |
21 | 13 | ||
diff --git a/fs/adfs/file.c b/fs/adfs/file.c index 8224d54a2afb..005ea34d1758 100644 --- a/fs/adfs/file.c +++ b/fs/adfs/file.c | |||
@@ -19,10 +19,6 @@ | |||
19 | * | 19 | * |
20 | * adfs regular file handling primitives | 20 | * adfs regular file handling primitives |
21 | */ | 21 | */ |
22 | #include <linux/fs.h> | ||
23 | #include <linux/buffer_head.h> /* for file_fsync() */ | ||
24 | #include <linux/adfs_fs.h> | ||
25 | |||
26 | #include "adfs.h" | 22 | #include "adfs.h" |
27 | 23 | ||
28 | const struct file_operations adfs_file_operations = { | 24 | const struct file_operations adfs_file_operations = { |
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 05b3a677201d..798cb071d132 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c | |||
@@ -7,17 +7,8 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/errno.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/adfs_fs.h> | ||
13 | #include <linux/time.h> | ||
14 | #include <linux/stat.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/smp_lock.h> | 10 | #include <linux/smp_lock.h> |
18 | #include <linux/module.h> | ||
19 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
20 | |||
21 | #include "adfs.h" | 12 | #include "adfs.h" |
22 | 13 | ||
23 | /* | 14 | /* |
@@ -395,4 +386,3 @@ int adfs_write_inode(struct inode *inode, int wait) | |||
395 | unlock_kernel(); | 386 | unlock_kernel(); |
396 | return ret; | 387 | return ret; |
397 | } | 388 | } |
398 | MODULE_LICENSE("GPL"); | ||
diff --git a/fs/adfs/map.c b/fs/adfs/map.c index 568081b93f73..d1a5932bb0f1 100644 --- a/fs/adfs/map.c +++ b/fs/adfs/map.c | |||
@@ -7,14 +7,8 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/errno.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/adfs_fs.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <linux/buffer_head.h> | 10 | #include <linux/buffer_head.h> |
15 | |||
16 | #include <asm/unaligned.h> | 11 | #include <asm/unaligned.h> |
17 | |||
18 | #include "adfs.h" | 12 | #include "adfs.h" |
19 | 13 | ||
20 | /* | 14 | /* |
diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 0ec5aaf47aa7..6910a98bd73c 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c | |||
@@ -8,26 +8,13 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/errno.h> | ||
12 | #include <linux/fs.h> | ||
13 | #include <linux/adfs_fs.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/time.h> | ||
16 | #include <linux/stat.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/init.h> | 11 | #include <linux/init.h> |
19 | #include <linux/buffer_head.h> | 12 | #include <linux/buffer_head.h> |
20 | #include <linux/vfs.h> | ||
21 | #include <linux/parser.h> | 13 | #include <linux/parser.h> |
22 | #include <linux/bitops.h> | ||
23 | #include <linux/mount.h> | 14 | #include <linux/mount.h> |
24 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
25 | 16 | #include <linux/smp_lock.h> | |
26 | #include <asm/uaccess.h> | 17 | #include <linux/statfs.h> |
27 | #include <asm/system.h> | ||
28 | |||
29 | #include <stdarg.h> | ||
30 | |||
31 | #include "adfs.h" | 18 | #include "adfs.h" |
32 | #include "dir_f.h" | 19 | #include "dir_f.h" |
33 | #include "dir_fplus.h" | 20 | #include "dir_fplus.h" |
@@ -534,3 +521,4 @@ static void __exit exit_adfs_fs(void) | |||
534 | 521 | ||
535 | module_init(init_adfs_fs) | 522 | module_init(init_adfs_fs) |
536 | module_exit(exit_adfs_fs) | 523 | module_exit(exit_adfs_fs) |
524 | MODULE_LICENSE("GPL"); | ||
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 9bd757774c9e..88067f36e5e7 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -564,7 +564,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
564 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 564 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
565 | { | 565 | { |
566 | struct afs_vnode *vnode, *dir; | 566 | struct afs_vnode *vnode, *dir; |
567 | struct afs_fid fid; | 567 | struct afs_fid uninitialized_var(fid); |
568 | struct dentry *parent; | 568 | struct dentry *parent; |
569 | struct key *key; | 569 | struct key *key; |
570 | void *dir_version; | 570 | void *dir_version; |
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 210acafe4a9b..3ff8bdd18fb3 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -432,7 +432,6 @@ vfs_rejected_lock: | |||
432 | list_del_init(&fl->fl_u.afs.link); | 432 | list_del_init(&fl->fl_u.afs.link); |
433 | if (list_empty(&vnode->granted_locks)) | 433 | if (list_empty(&vnode->granted_locks)) |
434 | afs_defer_unlock(vnode, key); | 434 | afs_defer_unlock(vnode, key); |
435 | spin_unlock(&vnode->lock); | ||
436 | goto abort_attempt; | 435 | goto abort_attempt; |
437 | } | 436 | } |
438 | 437 | ||
diff --git a/fs/afs/misc.c b/fs/afs/misc.c index 2d33a5f7d218..0dd4dafee10b 100644 --- a/fs/afs/misc.c +++ b/fs/afs/misc.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <rxrpc/packet.h> | ||
15 | #include "internal.h" | 16 | #include "internal.h" |
16 | #include "afs_fs.h" | 17 | #include "afs_fs.h" |
17 | 18 | ||
@@ -54,6 +55,21 @@ int afs_abort_to_error(u32 abort_code) | |||
54 | case 0x2f6df24: return -ENOLCK; | 55 | case 0x2f6df24: return -ENOLCK; |
55 | case 0x2f6df26: return -ENOTEMPTY; | 56 | case 0x2f6df26: return -ENOTEMPTY; |
56 | case 0x2f6df78: return -EDQUOT; | 57 | case 0x2f6df78: return -EDQUOT; |
58 | |||
59 | case RXKADINCONSISTENCY: return -EPROTO; | ||
60 | case RXKADPACKETSHORT: return -EPROTO; | ||
61 | case RXKADLEVELFAIL: return -EKEYREJECTED; | ||
62 | case RXKADTICKETLEN: return -EKEYREJECTED; | ||
63 | case RXKADOUTOFSEQUENCE: return -EPROTO; | ||
64 | case RXKADNOAUTH: return -EKEYREJECTED; | ||
65 | case RXKADBADKEY: return -EKEYREJECTED; | ||
66 | case RXKADBADTICKET: return -EKEYREJECTED; | ||
67 | case RXKADUNKNOWNKEY: return -EKEYREJECTED; | ||
68 | case RXKADEXPIRED: return -EKEYEXPIRED; | ||
69 | case RXKADSEALEDINCON: return -EKEYREJECTED; | ||
70 | case RXKADDATALEN: return -EKEYREJECTED; | ||
71 | case RXKADILLEGALLEVEL: return -EKEYREJECTED; | ||
72 | |||
57 | default: return -EREMOTEIO; | 73 | default: return -EREMOTEIO; |
58 | } | 74 | } |
59 | } | 75 | } |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index c52be53f6946..5ffb570cd3a8 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
19 | #include <linux/namei.h> | 19 | #include <linux/namei.h> |
20 | #include <linux/mnt_namespace.h> | ||
21 | #include "internal.h" | 20 | #include "internal.h" |
22 | 21 | ||
23 | 22 | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index ad0514d0115f..e1ea1c240b6a 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/smp_lock.h> | ||
21 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
22 | #include <linux/pagemap.h> | 23 | #include <linux/pagemap.h> |
23 | #include <linux/parser.h> | 24 | #include <linux/parser.h> |
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index ec2a7431e458..6e689208def2 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c | |||
@@ -65,6 +65,8 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl, | |||
65 | goto out; | 65 | goto out; |
66 | goto rotate; | 66 | goto rotate; |
67 | case -ENOMEDIUM: | 67 | case -ENOMEDIUM: |
68 | case -EKEYREJECTED: | ||
69 | case -EKEYEXPIRED: | ||
68 | goto out; | 70 | goto out; |
69 | default: | 71 | default: |
70 | ret = -EIO; | 72 | ret = -EIO; |
@@ -485,6 +485,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req) | |||
485 | { | 485 | { |
486 | assert_spin_locked(&ctx->ctx_lock); | 486 | assert_spin_locked(&ctx->ctx_lock); |
487 | 487 | ||
488 | if (req->ki_eventfd != NULL) | ||
489 | eventfd_ctx_put(req->ki_eventfd); | ||
488 | if (req->ki_dtor) | 490 | if (req->ki_dtor) |
489 | req->ki_dtor(req); | 491 | req->ki_dtor(req); |
490 | if (req->ki_iovec != &req->ki_inline_vec) | 492 | if (req->ki_iovec != &req->ki_inline_vec) |
@@ -509,8 +511,6 @@ static void aio_fput_routine(struct work_struct *data) | |||
509 | /* Complete the fput(s) */ | 511 | /* Complete the fput(s) */ |
510 | if (req->ki_filp != NULL) | 512 | if (req->ki_filp != NULL) |
511 | __fput(req->ki_filp); | 513 | __fput(req->ki_filp); |
512 | if (req->ki_eventfd != NULL) | ||
513 | __fput(req->ki_eventfd); | ||
514 | 514 | ||
515 | /* Link the iocb into the context's free list */ | 515 | /* Link the iocb into the context's free list */ |
516 | spin_lock_irq(&ctx->ctx_lock); | 516 | spin_lock_irq(&ctx->ctx_lock); |
@@ -528,8 +528,6 @@ static void aio_fput_routine(struct work_struct *data) | |||
528 | */ | 528 | */ |
529 | static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | 529 | static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) |
530 | { | 530 | { |
531 | int schedule_putreq = 0; | ||
532 | |||
533 | dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n", | 531 | dprintk(KERN_DEBUG "aio_put(%p): f_count=%ld\n", |
534 | req, atomic_long_read(&req->ki_filp->f_count)); | 532 | req, atomic_long_read(&req->ki_filp->f_count)); |
535 | 533 | ||
@@ -549,24 +547,16 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | |||
549 | * we would not be holding the last reference to the file*, so | 547 | * we would not be holding the last reference to the file*, so |
550 | * this function will be executed w/out any aio kthread wakeup. | 548 | * this function will be executed w/out any aio kthread wakeup. |
551 | */ | 549 | */ |
552 | if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) | 550 | if (unlikely(atomic_long_dec_and_test(&req->ki_filp->f_count))) { |
553 | schedule_putreq++; | ||
554 | else | ||
555 | req->ki_filp = NULL; | ||
556 | if (req->ki_eventfd != NULL) { | ||
557 | if (unlikely(atomic_long_dec_and_test(&req->ki_eventfd->f_count))) | ||
558 | schedule_putreq++; | ||
559 | else | ||
560 | req->ki_eventfd = NULL; | ||
561 | } | ||
562 | if (unlikely(schedule_putreq)) { | ||
563 | get_ioctx(ctx); | 551 | get_ioctx(ctx); |
564 | spin_lock(&fput_lock); | 552 | spin_lock(&fput_lock); |
565 | list_add(&req->ki_list, &fput_head); | 553 | list_add(&req->ki_list, &fput_head); |
566 | spin_unlock(&fput_lock); | 554 | spin_unlock(&fput_lock); |
567 | queue_work(aio_wq, &fput_work); | 555 | queue_work(aio_wq, &fput_work); |
568 | } else | 556 | } else { |
557 | req->ki_filp = NULL; | ||
569 | really_put_req(ctx, req); | 558 | really_put_req(ctx, req); |
559 | } | ||
570 | return 1; | 560 | return 1; |
571 | } | 561 | } |
572 | 562 | ||
@@ -1622,7 +1612,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1622 | * an eventfd() fd, and will be signaled for each completed | 1612 | * an eventfd() fd, and will be signaled for each completed |
1623 | * event using the eventfd_signal() function. | 1613 | * event using the eventfd_signal() function. |
1624 | */ | 1614 | */ |
1625 | req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd); | 1615 | req->ki_eventfd = eventfd_ctx_fdget((int) iocb->aio_resfd); |
1626 | if (IS_ERR(req->ki_eventfd)) { | 1616 | if (IS_ERR(req->ki_eventfd)) { |
1627 | ret = PTR_ERR(req->ki_eventfd); | 1617 | ret = PTR_ERR(req->ki_eventfd); |
1628 | req->ki_eventfd = NULL; | 1618 | req->ki_eventfd = NULL; |
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 1dd96d4406c0..47d4a01c5393 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -52,6 +52,19 @@ static const struct dentry_operations anon_inodefs_dentry_operations = { | |||
52 | .d_delete = anon_inodefs_delete_dentry, | 52 | .d_delete = anon_inodefs_delete_dentry, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | /* | ||
56 | * nop .set_page_dirty method so that people can use .page_mkwrite on | ||
57 | * anon inodes. | ||
58 | */ | ||
59 | static int anon_set_page_dirty(struct page *page) | ||
60 | { | ||
61 | return 0; | ||
62 | }; | ||
63 | |||
64 | static const struct address_space_operations anon_aops = { | ||
65 | .set_page_dirty = anon_set_page_dirty, | ||
66 | }; | ||
67 | |||
55 | /** | 68 | /** |
56 | * anon_inode_getfd - creates a new file instance by hooking it up to an | 69 | * anon_inode_getfd - creates a new file instance by hooking it up to an |
57 | * anonymous inode, and a dentry that describe the "class" | 70 | * anonymous inode, and a dentry that describe the "class" |
@@ -151,6 +164,8 @@ static struct inode *anon_inode_mkinode(void) | |||
151 | 164 | ||
152 | inode->i_fop = &anon_inode_fops; | 165 | inode->i_fop = &anon_inode_fops; |
153 | 166 | ||
167 | inode->i_mapping->a_ops = &anon_aops; | ||
168 | |||
154 | /* | 169 | /* |
155 | * Mark the inode dirty from the very beginning, | 170 | * Mark the inode dirty from the very beginning, |
156 | * that way it will never be moved to the dirty | 171 | * that way it will never be moved to the dirty |
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index f3da2eb51f56..00bf8fcb245f 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
21 | #include <linux/syscalls.h> | 21 | #include <linux/syscalls.h> |
22 | #include <linux/smp_lock.h> | ||
23 | #include <linux/magic.h> | 22 | #include <linux/magic.h> |
24 | #include <linux/dcache.h> | 23 | #include <linux/dcache.h> |
25 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 9367b6297d84..615d5496fe0f 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
@@ -513,7 +513,7 @@ befs_utf2nls(struct super_block *sb, const char *in, | |||
513 | { | 513 | { |
514 | struct nls_table *nls = BEFS_SB(sb)->nls; | 514 | struct nls_table *nls = BEFS_SB(sb)->nls; |
515 | int i, o; | 515 | int i, o; |
516 | wchar_t uni; | 516 | unicode_t uni; |
517 | int unilen, utflen; | 517 | int unilen, utflen; |
518 | char *result; | 518 | char *result; |
519 | /* The utf8->nls conversion won't make the final nls string bigger | 519 | /* The utf8->nls conversion won't make the final nls string bigger |
@@ -539,16 +539,16 @@ befs_utf2nls(struct super_block *sb, const char *in, | |||
539 | for (i = o = 0; i < in_len; i += utflen, o += unilen) { | 539 | for (i = o = 0; i < in_len; i += utflen, o += unilen) { |
540 | 540 | ||
541 | /* convert from UTF-8 to Unicode */ | 541 | /* convert from UTF-8 to Unicode */ |
542 | utflen = utf8_mbtowc(&uni, &in[i], in_len - i); | 542 | utflen = utf8_to_utf32(&in[i], in_len - i, &uni); |
543 | if (utflen < 0) { | 543 | if (utflen < 0) |
544 | goto conv_err; | 544 | goto conv_err; |
545 | } | ||
546 | 545 | ||
547 | /* convert from Unicode to nls */ | 546 | /* convert from Unicode to nls */ |
547 | if (uni > MAX_WCHAR_T) | ||
548 | goto conv_err; | ||
548 | unilen = nls->uni2char(uni, &result[o], in_len - o); | 549 | unilen = nls->uni2char(uni, &result[o], in_len - o); |
549 | if (unilen < 0) { | 550 | if (unilen < 0) |
550 | goto conv_err; | 551 | goto conv_err; |
551 | } | ||
552 | } | 552 | } |
553 | result[o] = '\0'; | 553 | result[o] = '\0'; |
554 | *out_len = o; | 554 | *out_len = o; |
@@ -619,15 +619,13 @@ befs_nls2utf(struct super_block *sb, const char *in, | |||
619 | 619 | ||
620 | /* convert from nls to unicode */ | 620 | /* convert from nls to unicode */ |
621 | unilen = nls->char2uni(&in[i], in_len - i, &uni); | 621 | unilen = nls->char2uni(&in[i], in_len - i, &uni); |
622 | if (unilen < 0) { | 622 | if (unilen < 0) |
623 | goto conv_err; | 623 | goto conv_err; |
624 | } | ||
625 | 624 | ||
626 | /* convert from unicode to UTF-8 */ | 625 | /* convert from unicode to UTF-8 */ |
627 | utflen = utf8_wctomb(&result[o], uni, 3); | 626 | utflen = utf32_to_utf8(uni, &result[o], 3); |
628 | if (utflen <= 0) { | 627 | if (utflen <= 0) |
629 | goto conv_err; | 628 | goto conv_err; |
630 | } | ||
631 | } | 629 | } |
632 | 630 | ||
633 | result[o] = '\0'; | 631 | result[o] = '\0'; |
@@ -737,8 +735,6 @@ parse_options(char *options, befs_mount_options * opts) | |||
737 | static void | 735 | static void |
738 | befs_put_super(struct super_block *sb) | 736 | befs_put_super(struct super_block *sb) |
739 | { | 737 | { |
740 | lock_kernel(); | ||
741 | |||
742 | kfree(BEFS_SB(sb)->mount_opts.iocharset); | 738 | kfree(BEFS_SB(sb)->mount_opts.iocharset); |
743 | BEFS_SB(sb)->mount_opts.iocharset = NULL; | 739 | BEFS_SB(sb)->mount_opts.iocharset = NULL; |
744 | 740 | ||
@@ -749,8 +745,6 @@ befs_put_super(struct super_block *sb) | |||
749 | 745 | ||
750 | kfree(sb->s_fs_info); | 746 | kfree(sb->s_fs_info); |
751 | sb->s_fs_info = NULL; | 747 | sb->s_fs_info = NULL; |
752 | |||
753 | unlock_kernel(); | ||
754 | } | 748 | } |
755 | 749 | ||
756 | /* Allocate private field of the superblock, fill it. | 750 | /* Allocate private field of the superblock, fill it. |
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 54bd07d44e68..1e41aadb1068 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/time.h> | 8 | #include <linux/time.h> |
9 | #include <linux/string.h> | 9 | #include <linux/string.h> |
10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
11 | #include <linux/smp_lock.h> | ||
12 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
13 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
14 | #include "bfs.h" | 13 | #include "bfs.h" |
diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 6a021265f018..88b9a3ff44e4 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c | |||
@@ -11,7 +11,6 @@ | |||
11 | 11 | ||
12 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
13 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
14 | #include <linux/smp_lock.h> | ||
15 | #include "bfs.h" | 14 | #include "bfs.h" |
16 | 15 | ||
17 | #undef DEBUG | 16 | #undef DEBUG |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 40381df34869..b7c1603cd4bd 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1340,8 +1340,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1340 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | 1340 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
1341 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1341 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
1342 | prstatus->pr_sighold = p->blocked.sig[0]; | 1342 | prstatus->pr_sighold = p->blocked.sig[0]; |
1343 | rcu_read_lock(); | ||
1344 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1345 | rcu_read_unlock(); | ||
1343 | prstatus->pr_pid = task_pid_vnr(p); | 1346 | prstatus->pr_pid = task_pid_vnr(p); |
1344 | prstatus->pr_ppid = task_pid_vnr(p->real_parent); | ||
1345 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1347 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
1346 | prstatus->pr_sid = task_session_vnr(p); | 1348 | prstatus->pr_sid = task_session_vnr(p); |
1347 | if (thread_group_leader(p)) { | 1349 | if (thread_group_leader(p)) { |
@@ -1382,8 +1384,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
1382 | psinfo->pr_psargs[i] = ' '; | 1384 | psinfo->pr_psargs[i] = ' '; |
1383 | psinfo->pr_psargs[len] = 0; | 1385 | psinfo->pr_psargs[len] = 0; |
1384 | 1386 | ||
1387 | rcu_read_lock(); | ||
1388 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1389 | rcu_read_unlock(); | ||
1385 | psinfo->pr_pid = task_pid_vnr(p); | 1390 | psinfo->pr_pid = task_pid_vnr(p); |
1386 | psinfo->pr_ppid = task_pid_vnr(p->real_parent); | ||
1387 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1391 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
1388 | psinfo->pr_sid = task_session_vnr(p); | 1392 | psinfo->pr_sid = task_session_vnr(p); |
1389 | 1393 | ||
@@ -1518,11 +1522,11 @@ static int fill_note_info(struct elfhdr *elf, int phdrs, | |||
1518 | info->thread = NULL; | 1522 | info->thread = NULL; |
1519 | 1523 | ||
1520 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); | 1524 | psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL); |
1521 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | ||
1522 | |||
1523 | if (psinfo == NULL) | 1525 | if (psinfo == NULL) |
1524 | return 0; | 1526 | return 0; |
1525 | 1527 | ||
1528 | fill_note(&info->psinfo, "CORE", NT_PRPSINFO, sizeof(*psinfo), psinfo); | ||
1529 | |||
1526 | /* | 1530 | /* |
1527 | * Figure out how many notes we're going to need for each thread. | 1531 | * Figure out how many notes we're going to need for each thread. |
1528 | */ | 1532 | */ |
@@ -1925,7 +1929,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
1925 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); | 1929 | elf = kmalloc(sizeof(*elf), GFP_KERNEL); |
1926 | if (!elf) | 1930 | if (!elf) |
1927 | goto out; | 1931 | goto out; |
1928 | 1932 | /* | |
1933 | * The number of segs are recored into ELF header as 16bit value. | ||
1934 | * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. | ||
1935 | */ | ||
1929 | segs = current->mm->map_count; | 1936 | segs = current->mm->map_count; |
1930 | #ifdef ELF_CORE_EXTRA_PHDRS | 1937 | #ifdef ELF_CORE_EXTRA_PHDRS |
1931 | segs += ELF_CORE_EXTRA_PHDRS; | 1938 | segs += ELF_CORE_EXTRA_PHDRS; |
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index fdb66faa24f1..20fbeced472b 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -1387,8 +1387,10 @@ static void fill_prstatus(struct elf_prstatus *prstatus, | |||
1387 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; | 1387 | prstatus->pr_info.si_signo = prstatus->pr_cursig = signr; |
1388 | prstatus->pr_sigpend = p->pending.signal.sig[0]; | 1388 | prstatus->pr_sigpend = p->pending.signal.sig[0]; |
1389 | prstatus->pr_sighold = p->blocked.sig[0]; | 1389 | prstatus->pr_sighold = p->blocked.sig[0]; |
1390 | rcu_read_lock(); | ||
1391 | prstatus->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1392 | rcu_read_unlock(); | ||
1390 | prstatus->pr_pid = task_pid_vnr(p); | 1393 | prstatus->pr_pid = task_pid_vnr(p); |
1391 | prstatus->pr_ppid = task_pid_vnr(p->real_parent); | ||
1392 | prstatus->pr_pgrp = task_pgrp_vnr(p); | 1394 | prstatus->pr_pgrp = task_pgrp_vnr(p); |
1393 | prstatus->pr_sid = task_session_vnr(p); | 1395 | prstatus->pr_sid = task_session_vnr(p); |
1394 | if (thread_group_leader(p)) { | 1396 | if (thread_group_leader(p)) { |
@@ -1432,8 +1434,10 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p, | |||
1432 | psinfo->pr_psargs[i] = ' '; | 1434 | psinfo->pr_psargs[i] = ' '; |
1433 | psinfo->pr_psargs[len] = 0; | 1435 | psinfo->pr_psargs[len] = 0; |
1434 | 1436 | ||
1437 | rcu_read_lock(); | ||
1438 | psinfo->pr_ppid = task_pid_vnr(rcu_dereference(p->real_parent)); | ||
1439 | rcu_read_unlock(); | ||
1435 | psinfo->pr_pid = task_pid_vnr(p); | 1440 | psinfo->pr_pid = task_pid_vnr(p); |
1436 | psinfo->pr_ppid = task_pid_vnr(p->real_parent); | ||
1437 | psinfo->pr_pgrp = task_pgrp_vnr(p); | 1441 | psinfo->pr_pgrp = task_pgrp_vnr(p); |
1438 | psinfo->pr_sid = task_session_vnr(p); | 1442 | psinfo->pr_sid = task_session_vnr(p); |
1439 | 1443 | ||
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 697f6b5f1313..e92f229e3c6e 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c | |||
@@ -828,15 +828,22 @@ static int load_flat_shared_library(int id, struct lib_info *libs) | |||
828 | if (IS_ERR(bprm.file)) | 828 | if (IS_ERR(bprm.file)) |
829 | return res; | 829 | return res; |
830 | 830 | ||
831 | bprm.cred = prepare_exec_creds(); | ||
832 | res = -ENOMEM; | ||
833 | if (!bprm.cred) | ||
834 | goto out; | ||
835 | |||
831 | res = prepare_binprm(&bprm); | 836 | res = prepare_binprm(&bprm); |
832 | 837 | ||
833 | if (res <= (unsigned long)-4096) | 838 | if (res <= (unsigned long)-4096) |
834 | res = load_flat_file(&bprm, libs, id, NULL); | 839 | res = load_flat_file(&bprm, libs, id, NULL); |
835 | if (bprm.file) { | 840 | |
836 | allow_write_access(bprm.file); | 841 | abort_creds(bprm.cred); |
837 | fput(bprm.file); | 842 | |
838 | bprm.file = NULL; | 843 | out: |
839 | } | 844 | allow_write_access(bprm.file); |
845 | fput(bprm.file); | ||
846 | |||
840 | return(res); | 847 | return(res); |
841 | } | 848 | } |
842 | 849 | ||
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 31c46a241bac..49a34e7f7306 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * bio-integrity.c - bio data integrity extensions | 2 | * bio-integrity.c - bio data integrity extensions |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008 Oracle Corporation | 4 | * Copyright (C) 2007, 2008, 2009 Oracle Corporation |
5 | * Written by: Martin K. Petersen <martin.petersen@oracle.com> | 5 | * Written by: Martin K. Petersen <martin.petersen@oracle.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -25,63 +25,121 @@ | |||
25 | #include <linux/bio.h> | 25 | #include <linux/bio.h> |
26 | #include <linux/workqueue.h> | 26 | #include <linux/workqueue.h> |
27 | 27 | ||
28 | static struct kmem_cache *bio_integrity_slab __read_mostly; | 28 | struct integrity_slab { |
29 | static mempool_t *bio_integrity_pool; | 29 | struct kmem_cache *slab; |
30 | static struct bio_set *integrity_bio_set; | 30 | unsigned short nr_vecs; |
31 | char name[8]; | ||
32 | }; | ||
33 | |||
34 | #define IS(x) { .nr_vecs = x, .name = "bip-"__stringify(x) } | ||
35 | struct integrity_slab bip_slab[BIOVEC_NR_POOLS] __read_mostly = { | ||
36 | IS(1), IS(4), IS(16), IS(64), IS(128), IS(BIO_MAX_PAGES), | ||
37 | }; | ||
38 | #undef IS | ||
39 | |||
31 | static struct workqueue_struct *kintegrityd_wq; | 40 | static struct workqueue_struct *kintegrityd_wq; |
32 | 41 | ||
42 | static inline unsigned int vecs_to_idx(unsigned int nr) | ||
43 | { | ||
44 | switch (nr) { | ||
45 | case 1: | ||
46 | return 0; | ||
47 | case 2 ... 4: | ||
48 | return 1; | ||
49 | case 5 ... 16: | ||
50 | return 2; | ||
51 | case 17 ... 64: | ||
52 | return 3; | ||
53 | case 65 ... 128: | ||
54 | return 4; | ||
55 | case 129 ... BIO_MAX_PAGES: | ||
56 | return 5; | ||
57 | default: | ||
58 | BUG(); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | static inline int use_bip_pool(unsigned int idx) | ||
63 | { | ||
64 | if (idx == BIOVEC_NR_POOLS) | ||
65 | return 1; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
33 | /** | 70 | /** |
34 | * bio_integrity_alloc - Allocate integrity payload and attach it to bio | 71 | * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio |
35 | * @bio: bio to attach integrity metadata to | 72 | * @bio: bio to attach integrity metadata to |
36 | * @gfp_mask: Memory allocation mask | 73 | * @gfp_mask: Memory allocation mask |
37 | * @nr_vecs: Number of integrity metadata scatter-gather elements | 74 | * @nr_vecs: Number of integrity metadata scatter-gather elements |
75 | * @bs: bio_set to allocate from | ||
38 | * | 76 | * |
39 | * Description: This function prepares a bio for attaching integrity | 77 | * Description: This function prepares a bio for attaching integrity |
40 | * metadata. nr_vecs specifies the maximum number of pages containing | 78 | * metadata. nr_vecs specifies the maximum number of pages containing |
41 | * integrity metadata that can be attached. | 79 | * integrity metadata that can be attached. |
42 | */ | 80 | */ |
43 | struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, | 81 | struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, |
44 | gfp_t gfp_mask, | 82 | gfp_t gfp_mask, |
45 | unsigned int nr_vecs) | 83 | unsigned int nr_vecs, |
84 | struct bio_set *bs) | ||
46 | { | 85 | { |
47 | struct bio_integrity_payload *bip; | 86 | struct bio_integrity_payload *bip; |
48 | struct bio_vec *iv; | 87 | unsigned int idx = vecs_to_idx(nr_vecs); |
49 | unsigned long idx; | ||
50 | 88 | ||
51 | BUG_ON(bio == NULL); | 89 | BUG_ON(bio == NULL); |
90 | bip = NULL; | ||
52 | 91 | ||
53 | bip = mempool_alloc(bio_integrity_pool, gfp_mask); | 92 | /* Lower order allocations come straight from slab */ |
54 | if (unlikely(bip == NULL)) { | 93 | if (!use_bip_pool(idx)) |
55 | printk(KERN_ERR "%s: could not alloc bip\n", __func__); | 94 | bip = kmem_cache_alloc(bip_slab[idx].slab, gfp_mask); |
56 | return NULL; | ||
57 | } | ||
58 | 95 | ||
59 | memset(bip, 0, sizeof(*bip)); | 96 | /* Use mempool if lower order alloc failed or max vecs were requested */ |
97 | if (bip == NULL) { | ||
98 | bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask); | ||
60 | 99 | ||
61 | iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, integrity_bio_set); | 100 | if (unlikely(bip == NULL)) { |
62 | if (unlikely(iv == NULL)) { | 101 | printk(KERN_ERR "%s: could not alloc bip\n", __func__); |
63 | printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__); | 102 | return NULL; |
64 | mempool_free(bip, bio_integrity_pool); | 103 | } |
65 | return NULL; | ||
66 | } | 104 | } |
67 | 105 | ||
68 | bip->bip_pool = idx; | 106 | memset(bip, 0, sizeof(*bip)); |
69 | bip->bip_vec = iv; | 107 | |
108 | bip->bip_slab = idx; | ||
70 | bip->bip_bio = bio; | 109 | bip->bip_bio = bio; |
71 | bio->bi_integrity = bip; | 110 | bio->bi_integrity = bip; |
72 | 111 | ||
73 | return bip; | 112 | return bip; |
74 | } | 113 | } |
114 | EXPORT_SYMBOL(bio_integrity_alloc_bioset); | ||
115 | |||
116 | /** | ||
117 | * bio_integrity_alloc - Allocate integrity payload and attach it to bio | ||
118 | * @bio: bio to attach integrity metadata to | ||
119 | * @gfp_mask: Memory allocation mask | ||
120 | * @nr_vecs: Number of integrity metadata scatter-gather elements | ||
121 | * | ||
122 | * Description: This function prepares a bio for attaching integrity | ||
123 | * metadata. nr_vecs specifies the maximum number of pages containing | ||
124 | * integrity metadata that can be attached. | ||
125 | */ | ||
126 | struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, | ||
127 | gfp_t gfp_mask, | ||
128 | unsigned int nr_vecs) | ||
129 | { | ||
130 | return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set); | ||
131 | } | ||
75 | EXPORT_SYMBOL(bio_integrity_alloc); | 132 | EXPORT_SYMBOL(bio_integrity_alloc); |
76 | 133 | ||
77 | /** | 134 | /** |
78 | * bio_integrity_free - Free bio integrity payload | 135 | * bio_integrity_free - Free bio integrity payload |
79 | * @bio: bio containing bip to be freed | 136 | * @bio: bio containing bip to be freed |
137 | * @bs: bio_set this bio was allocated from | ||
80 | * | 138 | * |
81 | * Description: Used to free the integrity portion of a bio. Usually | 139 | * Description: Used to free the integrity portion of a bio. Usually |
82 | * called from bio_free(). | 140 | * called from bio_free(). |
83 | */ | 141 | */ |
84 | void bio_integrity_free(struct bio *bio) | 142 | void bio_integrity_free(struct bio *bio, struct bio_set *bs) |
85 | { | 143 | { |
86 | struct bio_integrity_payload *bip = bio->bi_integrity; | 144 | struct bio_integrity_payload *bip = bio->bi_integrity; |
87 | 145 | ||
@@ -92,8 +150,10 @@ void bio_integrity_free(struct bio *bio) | |||
92 | && bip->bip_buf != NULL) | 150 | && bip->bip_buf != NULL) |
93 | kfree(bip->bip_buf); | 151 | kfree(bip->bip_buf); |
94 | 152 | ||
95 | bvec_free_bs(integrity_bio_set, bip->bip_vec, bip->bip_pool); | 153 | if (use_bip_pool(bip->bip_slab)) |
96 | mempool_free(bip, bio_integrity_pool); | 154 | mempool_free(bip, bs->bio_integrity_pool); |
155 | else | ||
156 | kmem_cache_free(bip_slab[bip->bip_slab].slab, bip); | ||
97 | 157 | ||
98 | bio->bi_integrity = NULL; | 158 | bio->bi_integrity = NULL; |
99 | } | 159 | } |
@@ -114,7 +174,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, | |||
114 | struct bio_integrity_payload *bip = bio->bi_integrity; | 174 | struct bio_integrity_payload *bip = bio->bi_integrity; |
115 | struct bio_vec *iv; | 175 | struct bio_vec *iv; |
116 | 176 | ||
117 | if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) { | 177 | if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_slab)) { |
118 | printk(KERN_ERR "%s: bip_vec full\n", __func__); | 178 | printk(KERN_ERR "%s: bip_vec full\n", __func__); |
119 | return 0; | 179 | return 0; |
120 | } | 180 | } |
@@ -647,8 +707,8 @@ void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) | |||
647 | bp->iv1 = bip->bip_vec[0]; | 707 | bp->iv1 = bip->bip_vec[0]; |
648 | bp->iv2 = bip->bip_vec[0]; | 708 | bp->iv2 = bip->bip_vec[0]; |
649 | 709 | ||
650 | bp->bip1.bip_vec = &bp->iv1; | 710 | bp->bip1.bip_vec[0] = bp->iv1; |
651 | bp->bip2.bip_vec = &bp->iv2; | 711 | bp->bip2.bip_vec[0] = bp->iv2; |
652 | 712 | ||
653 | bp->iv1.bv_len = sectors * bi->tuple_size; | 713 | bp->iv1.bv_len = sectors * bi->tuple_size; |
654 | bp->iv2.bv_offset += sectors * bi->tuple_size; | 714 | bp->iv2.bv_offset += sectors * bi->tuple_size; |
@@ -667,17 +727,19 @@ EXPORT_SYMBOL(bio_integrity_split); | |||
667 | * @bio: New bio | 727 | * @bio: New bio |
668 | * @bio_src: Original bio | 728 | * @bio_src: Original bio |
669 | * @gfp_mask: Memory allocation mask | 729 | * @gfp_mask: Memory allocation mask |
730 | * @bs: bio_set to allocate bip from | ||
670 | * | 731 | * |
671 | * Description: Called to allocate a bip when cloning a bio | 732 | * Description: Called to allocate a bip when cloning a bio |
672 | */ | 733 | */ |
673 | int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask) | 734 | int bio_integrity_clone(struct bio *bio, struct bio *bio_src, |
735 | gfp_t gfp_mask, struct bio_set *bs) | ||
674 | { | 736 | { |
675 | struct bio_integrity_payload *bip_src = bio_src->bi_integrity; | 737 | struct bio_integrity_payload *bip_src = bio_src->bi_integrity; |
676 | struct bio_integrity_payload *bip; | 738 | struct bio_integrity_payload *bip; |
677 | 739 | ||
678 | BUG_ON(bip_src == NULL); | 740 | BUG_ON(bip_src == NULL); |
679 | 741 | ||
680 | bip = bio_integrity_alloc(bio, gfp_mask, bip_src->bip_vcnt); | 742 | bip = bio_integrity_alloc_bioset(bio, gfp_mask, bip_src->bip_vcnt, bs); |
681 | 743 | ||
682 | if (bip == NULL) | 744 | if (bip == NULL) |
683 | return -EIO; | 745 | return -EIO; |
@@ -693,25 +755,43 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src, gfp_t gfp_mask) | |||
693 | } | 755 | } |
694 | EXPORT_SYMBOL(bio_integrity_clone); | 756 | EXPORT_SYMBOL(bio_integrity_clone); |
695 | 757 | ||
696 | static int __init bio_integrity_init(void) | 758 | int bioset_integrity_create(struct bio_set *bs, int pool_size) |
697 | { | 759 | { |
698 | kintegrityd_wq = create_workqueue("kintegrityd"); | 760 | unsigned int max_slab = vecs_to_idx(BIO_MAX_PAGES); |
761 | |||
762 | bs->bio_integrity_pool = | ||
763 | mempool_create_slab_pool(pool_size, bip_slab[max_slab].slab); | ||
699 | 764 | ||
765 | if (!bs->bio_integrity_pool) | ||
766 | return -1; | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | EXPORT_SYMBOL(bioset_integrity_create); | ||
771 | |||
772 | void bioset_integrity_free(struct bio_set *bs) | ||
773 | { | ||
774 | if (bs->bio_integrity_pool) | ||
775 | mempool_destroy(bs->bio_integrity_pool); | ||
776 | } | ||
777 | EXPORT_SYMBOL(bioset_integrity_free); | ||
778 | |||
779 | void __init bio_integrity_init(void) | ||
780 | { | ||
781 | unsigned int i; | ||
782 | |||
783 | kintegrityd_wq = create_workqueue("kintegrityd"); | ||
700 | if (!kintegrityd_wq) | 784 | if (!kintegrityd_wq) |
701 | panic("Failed to create kintegrityd\n"); | 785 | panic("Failed to create kintegrityd\n"); |
702 | 786 | ||
703 | bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, | 787 | for (i = 0 ; i < BIOVEC_NR_POOLS ; i++) { |
704 | SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 788 | unsigned int size; |
705 | 789 | ||
706 | bio_integrity_pool = mempool_create_slab_pool(BIO_POOL_SIZE, | 790 | size = sizeof(struct bio_integrity_payload) |
707 | bio_integrity_slab); | 791 | + bip_slab[i].nr_vecs * sizeof(struct bio_vec); |
708 | if (!bio_integrity_pool) | ||
709 | panic("bio_integrity: can't allocate bip pool\n"); | ||
710 | 792 | ||
711 | integrity_bio_set = bioset_create(BIO_POOL_SIZE, 0); | 793 | bip_slab[i].slab = |
712 | if (!integrity_bio_set) | 794 | kmem_cache_create(bip_slab[i].name, size, 0, |
713 | panic("bio_integrity: can't allocate bio_set\n"); | 795 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); |
714 | 796 | } | |
715 | return 0; | ||
716 | } | 797 | } |
717 | subsys_initcall(bio_integrity_init); | ||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/mempool.h> | 26 | #include <linux/mempool.h> |
27 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
28 | #include <linux/blktrace_api.h> | ||
29 | #include <scsi/sg.h> /* for struct sg_iovec */ | 28 | #include <scsi/sg.h> /* for struct sg_iovec */ |
30 | 29 | ||
31 | #include <trace/events/block.h> | 30 | #include <trace/events/block.h> |
@@ -239,7 +238,7 @@ void bio_free(struct bio *bio, struct bio_set *bs) | |||
239 | bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); | 238 | bvec_free_bs(bs, bio->bi_io_vec, BIO_POOL_IDX(bio)); |
240 | 239 | ||
241 | if (bio_integrity(bio)) | 240 | if (bio_integrity(bio)) |
242 | bio_integrity_free(bio); | 241 | bio_integrity_free(bio, bs); |
243 | 242 | ||
244 | /* | 243 | /* |
245 | * If we have front padding, adjust the bio pointer before freeing | 244 | * If we have front padding, adjust the bio pointer before freeing |
@@ -342,7 +341,7 @@ struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs) | |||
342 | static void bio_kmalloc_destructor(struct bio *bio) | 341 | static void bio_kmalloc_destructor(struct bio *bio) |
343 | { | 342 | { |
344 | if (bio_integrity(bio)) | 343 | if (bio_integrity(bio)) |
345 | bio_integrity_free(bio); | 344 | bio_integrity_free(bio, fs_bio_set); |
346 | kfree(bio); | 345 | kfree(bio); |
347 | } | 346 | } |
348 | 347 | ||
@@ -358,9 +357,9 @@ static void bio_kmalloc_destructor(struct bio *bio) | |||
358 | * | 357 | * |
359 | * If %__GFP_WAIT is set, then bio_alloc will always be able to allocate | 358 | * If %__GFP_WAIT is set, then bio_alloc will always be able to allocate |
360 | * a bio. This is due to the mempool guarantees. To make this work, callers | 359 | * a bio. This is due to the mempool guarantees. To make this work, callers |
361 | * must never allocate more than 1 bio at the time from this pool. Callers | 360 | * must never allocate more than 1 bio at a time from this pool. Callers |
362 | * that need to allocate more than 1 bio must always submit the previously | 361 | * that need to allocate more than 1 bio must always submit the previously |
363 | * allocate bio for IO before attempting to allocate a new one. Failure to | 362 | * allocated bio for IO before attempting to allocate a new one. Failure to |
364 | * do so can cause livelocks under memory pressure. | 363 | * do so can cause livelocks under memory pressure. |
365 | * | 364 | * |
366 | **/ | 365 | **/ |
@@ -473,7 +472,7 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) | |||
473 | if (bio_integrity(bio)) { | 472 | if (bio_integrity(bio)) { |
474 | int ret; | 473 | int ret; |
475 | 474 | ||
476 | ret = bio_integrity_clone(b, bio, gfp_mask); | 475 | ret = bio_integrity_clone(b, bio, gfp_mask, fs_bio_set); |
477 | 476 | ||
478 | if (ret < 0) { | 477 | if (ret < 0) { |
479 | bio_put(b); | 478 | bio_put(b); |
@@ -706,14 +705,13 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count, | |||
706 | } | 705 | } |
707 | 706 | ||
708 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, | 707 | static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, |
709 | struct sg_iovec *iov, int iov_count, int uncopy, | 708 | struct sg_iovec *iov, int iov_count, |
710 | int do_free_page) | 709 | int to_user, int from_user, int do_free_page) |
711 | { | 710 | { |
712 | int ret = 0, i; | 711 | int ret = 0, i; |
713 | struct bio_vec *bvec; | 712 | struct bio_vec *bvec; |
714 | int iov_idx = 0; | 713 | int iov_idx = 0; |
715 | unsigned int iov_off = 0; | 714 | unsigned int iov_off = 0; |
716 | int read = bio_data_dir(bio) == READ; | ||
717 | 715 | ||
718 | __bio_for_each_segment(bvec, bio, i, 0) { | 716 | __bio_for_each_segment(bvec, bio, i, 0) { |
719 | char *bv_addr = page_address(bvec->bv_page); | 717 | char *bv_addr = page_address(bvec->bv_page); |
@@ -728,13 +726,14 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs, | |||
728 | iov_addr = iov[iov_idx].iov_base + iov_off; | 726 | iov_addr = iov[iov_idx].iov_base + iov_off; |
729 | 727 | ||
730 | if (!ret) { | 728 | if (!ret) { |
731 | if (!read && !uncopy) | 729 | if (to_user) |
732 | ret = copy_from_user(bv_addr, iov_addr, | ||
733 | bytes); | ||
734 | if (read && uncopy) | ||
735 | ret = copy_to_user(iov_addr, bv_addr, | 730 | ret = copy_to_user(iov_addr, bv_addr, |
736 | bytes); | 731 | bytes); |
737 | 732 | ||
733 | if (from_user) | ||
734 | ret = copy_from_user(bv_addr, iov_addr, | ||
735 | bytes); | ||
736 | |||
738 | if (ret) | 737 | if (ret) |
739 | ret = -EFAULT; | 738 | ret = -EFAULT; |
740 | } | 739 | } |
@@ -771,7 +770,8 @@ int bio_uncopy_user(struct bio *bio) | |||
771 | 770 | ||
772 | if (!bio_flagged(bio, BIO_NULL_MAPPED)) | 771 | if (!bio_flagged(bio, BIO_NULL_MAPPED)) |
773 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, | 772 | ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, |
774 | bmd->nr_sgvecs, 1, bmd->is_our_pages); | 773 | bmd->nr_sgvecs, bio_data_dir(bio) == READ, |
774 | 0, bmd->is_our_pages); | ||
775 | bio_free_map_data(bmd); | 775 | bio_free_map_data(bmd); |
776 | bio_put(bio); | 776 | bio_put(bio); |
777 | return ret; | 777 | return ret; |
@@ -876,8 +876,9 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
876 | /* | 876 | /* |
877 | * success | 877 | * success |
878 | */ | 878 | */ |
879 | if (!write_to_vm && (!map_data || !map_data->null_mapped)) { | 879 | if ((!write_to_vm && (!map_data || !map_data->null_mapped)) || |
880 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0); | 880 | (map_data && map_data->from_user)) { |
881 | ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0); | ||
881 | if (ret) | 882 | if (ret) |
882 | goto cleanup; | 883 | goto cleanup; |
883 | } | 884 | } |
@@ -1540,6 +1541,7 @@ void bioset_free(struct bio_set *bs) | |||
1540 | if (bs->bio_pool) | 1541 | if (bs->bio_pool) |
1541 | mempool_destroy(bs->bio_pool); | 1542 | mempool_destroy(bs->bio_pool); |
1542 | 1543 | ||
1544 | bioset_integrity_free(bs); | ||
1543 | biovec_free_pools(bs); | 1545 | biovec_free_pools(bs); |
1544 | bio_put_slab(bs); | 1546 | bio_put_slab(bs); |
1545 | 1547 | ||
@@ -1580,6 +1582,9 @@ struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad) | |||
1580 | if (!bs->bio_pool) | 1582 | if (!bs->bio_pool) |
1581 | goto bad; | 1583 | goto bad; |
1582 | 1584 | ||
1585 | if (bioset_integrity_create(bs, pool_size)) | ||
1586 | goto bad; | ||
1587 | |||
1583 | if (!biovec_create_pools(bs, pool_size)) | 1588 | if (!biovec_create_pools(bs, pool_size)) |
1584 | return bs; | 1589 | return bs; |
1585 | 1590 | ||
@@ -1617,6 +1622,7 @@ static int __init init_bio(void) | |||
1617 | if (!bio_slabs) | 1622 | if (!bio_slabs) |
1618 | panic("bio: can't allocate bios\n"); | 1623 | panic("bio: can't allocate bios\n"); |
1619 | 1624 | ||
1625 | bio_integrity_init(); | ||
1620 | biovec_init_slabs(); | 1626 | biovec_init_slabs(); |
1621 | 1627 | ||
1622 | fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); | 1628 | fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 3a6d4fb2a329..94dfda24c06e 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -564,6 +564,16 @@ struct block_device *bdget(dev_t dev) | |||
564 | 564 | ||
565 | EXPORT_SYMBOL(bdget); | 565 | EXPORT_SYMBOL(bdget); |
566 | 566 | ||
567 | /** | ||
568 | * bdgrab -- Grab a reference to an already referenced block device | ||
569 | * @bdev: Block device to grab a reference to. | ||
570 | */ | ||
571 | struct block_device *bdgrab(struct block_device *bdev) | ||
572 | { | ||
573 | atomic_inc(&bdev->bd_inode->i_count); | ||
574 | return bdev; | ||
575 | } | ||
576 | |||
567 | long nr_blockdev_pages(void) | 577 | long nr_blockdev_pages(void) |
568 | { | 578 | { |
569 | struct block_device *bdev; | 579 | struct block_device *bdev; |
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 603972576f0f..f128427b995b 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c | |||
@@ -29,51 +29,28 @@ | |||
29 | 29 | ||
30 | #ifdef CONFIG_FS_POSIX_ACL | 30 | #ifdef CONFIG_FS_POSIX_ACL |
31 | 31 | ||
32 | static void btrfs_update_cached_acl(struct inode *inode, | ||
33 | struct posix_acl **p_acl, | ||
34 | struct posix_acl *acl) | ||
35 | { | ||
36 | spin_lock(&inode->i_lock); | ||
37 | if (*p_acl && *p_acl != BTRFS_ACL_NOT_CACHED) | ||
38 | posix_acl_release(*p_acl); | ||
39 | *p_acl = posix_acl_dup(acl); | ||
40 | spin_unlock(&inode->i_lock); | ||
41 | } | ||
42 | |||
43 | static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) | 32 | static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) |
44 | { | 33 | { |
45 | int size; | 34 | int size; |
46 | const char *name; | 35 | const char *name; |
47 | char *value = NULL; | 36 | char *value = NULL; |
48 | struct posix_acl *acl = NULL, **p_acl; | 37 | struct posix_acl *acl; |
38 | |||
39 | acl = get_cached_acl(inode, type); | ||
40 | if (acl != ACL_NOT_CACHED) | ||
41 | return acl; | ||
49 | 42 | ||
50 | switch (type) { | 43 | switch (type) { |
51 | case ACL_TYPE_ACCESS: | 44 | case ACL_TYPE_ACCESS: |
52 | name = POSIX_ACL_XATTR_ACCESS; | 45 | name = POSIX_ACL_XATTR_ACCESS; |
53 | p_acl = &BTRFS_I(inode)->i_acl; | ||
54 | break; | 46 | break; |
55 | case ACL_TYPE_DEFAULT: | 47 | case ACL_TYPE_DEFAULT: |
56 | name = POSIX_ACL_XATTR_DEFAULT; | 48 | name = POSIX_ACL_XATTR_DEFAULT; |
57 | p_acl = &BTRFS_I(inode)->i_default_acl; | ||
58 | break; | 49 | break; |
59 | default: | 50 | default: |
60 | return ERR_PTR(-EINVAL); | 51 | BUG(); |
61 | } | 52 | } |
62 | 53 | ||
63 | /* Handle the cached NULL acl case without locking */ | ||
64 | acl = ACCESS_ONCE(*p_acl); | ||
65 | if (!acl) | ||
66 | return acl; | ||
67 | |||
68 | spin_lock(&inode->i_lock); | ||
69 | acl = *p_acl; | ||
70 | if (acl != BTRFS_ACL_NOT_CACHED) | ||
71 | acl = posix_acl_dup(acl); | ||
72 | spin_unlock(&inode->i_lock); | ||
73 | |||
74 | if (acl != BTRFS_ACL_NOT_CACHED) | ||
75 | return acl; | ||
76 | |||
77 | size = __btrfs_getxattr(inode, name, "", 0); | 54 | size = __btrfs_getxattr(inode, name, "", 0); |
78 | if (size > 0) { | 55 | if (size > 0) { |
79 | value = kzalloc(size, GFP_NOFS); | 56 | value = kzalloc(size, GFP_NOFS); |
@@ -82,13 +59,13 @@ static struct posix_acl *btrfs_get_acl(struct inode *inode, int type) | |||
82 | size = __btrfs_getxattr(inode, name, value, size); | 59 | size = __btrfs_getxattr(inode, name, value, size); |
83 | if (size > 0) { | 60 | if (size > 0) { |
84 | acl = posix_acl_from_xattr(value, size); | 61 | acl = posix_acl_from_xattr(value, size); |
85 | btrfs_update_cached_acl(inode, p_acl, acl); | 62 | set_cached_acl(inode, type, acl); |
86 | } | 63 | } |
87 | kfree(value); | 64 | kfree(value); |
88 | } else if (size == -ENOENT || size == -ENODATA || size == 0) { | 65 | } else if (size == -ENOENT || size == -ENODATA || size == 0) { |
89 | /* FIXME, who returns -ENOENT? I think nobody */ | 66 | /* FIXME, who returns -ENOENT? I think nobody */ |
90 | acl = NULL; | 67 | acl = NULL; |
91 | btrfs_update_cached_acl(inode, p_acl, acl); | 68 | set_cached_acl(inode, type, acl); |
92 | } else { | 69 | } else { |
93 | acl = ERR_PTR(-EIO); | 70 | acl = ERR_PTR(-EIO); |
94 | } | 71 | } |
@@ -121,7 +98,6 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) | |||
121 | { | 98 | { |
122 | int ret, size = 0; | 99 | int ret, size = 0; |
123 | const char *name; | 100 | const char *name; |
124 | struct posix_acl **p_acl; | ||
125 | char *value = NULL; | 101 | char *value = NULL; |
126 | mode_t mode; | 102 | mode_t mode; |
127 | 103 | ||
@@ -141,13 +117,11 @@ static int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) | |||
141 | ret = 0; | 117 | ret = 0; |
142 | inode->i_mode = mode; | 118 | inode->i_mode = mode; |
143 | name = POSIX_ACL_XATTR_ACCESS; | 119 | name = POSIX_ACL_XATTR_ACCESS; |
144 | p_acl = &BTRFS_I(inode)->i_acl; | ||
145 | break; | 120 | break; |
146 | case ACL_TYPE_DEFAULT: | 121 | case ACL_TYPE_DEFAULT: |
147 | if (!S_ISDIR(inode->i_mode)) | 122 | if (!S_ISDIR(inode->i_mode)) |
148 | return acl ? -EINVAL : 0; | 123 | return acl ? -EINVAL : 0; |
149 | name = POSIX_ACL_XATTR_DEFAULT; | 124 | name = POSIX_ACL_XATTR_DEFAULT; |
150 | p_acl = &BTRFS_I(inode)->i_default_acl; | ||
151 | break; | 125 | break; |
152 | default: | 126 | default: |
153 | return -EINVAL; | 127 | return -EINVAL; |
@@ -172,7 +146,7 @@ out: | |||
172 | kfree(value); | 146 | kfree(value); |
173 | 147 | ||
174 | if (!ret) | 148 | if (!ret) |
175 | btrfs_update_cached_acl(inode, p_acl, acl); | 149 | set_cached_acl(inode, type, acl); |
176 | 150 | ||
177 | return ret; | 151 | return ret; |
178 | } | 152 | } |
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 7f88628a1a72..019e8af449ab 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
@@ -299,8 +299,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers) | |||
299 | "btrfs-%s-%d", workers->name, | 299 | "btrfs-%s-%d", workers->name, |
300 | workers->num_workers + i); | 300 | workers->num_workers + i); |
301 | if (IS_ERR(worker->task)) { | 301 | if (IS_ERR(worker->task)) { |
302 | kfree(worker); | ||
303 | ret = PTR_ERR(worker->task); | 302 | ret = PTR_ERR(worker->task); |
303 | kfree(worker); | ||
304 | goto fail; | 304 | goto fail; |
305 | } | 305 | } |
306 | 306 | ||
@@ -424,11 +424,11 @@ int btrfs_requeue_work(struct btrfs_work *work) | |||
424 | * list | 424 | * list |
425 | */ | 425 | */ |
426 | if (worker->idle) { | 426 | if (worker->idle) { |
427 | spin_lock_irqsave(&worker->workers->lock, flags); | 427 | spin_lock(&worker->workers->lock); |
428 | worker->idle = 0; | 428 | worker->idle = 0; |
429 | list_move_tail(&worker->worker_list, | 429 | list_move_tail(&worker->worker_list, |
430 | &worker->workers->worker_list); | 430 | &worker->workers->worker_list); |
431 | spin_unlock_irqrestore(&worker->workers->lock, flags); | 431 | spin_unlock(&worker->workers->lock); |
432 | } | 432 | } |
433 | if (!worker->working) { | 433 | if (!worker->working) { |
434 | wake = 1; | 434 | wake = 1; |
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index acb4f3517582..ea1ea0af8c0e 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
@@ -53,10 +53,6 @@ struct btrfs_inode { | |||
53 | /* used to order data wrt metadata */ | 53 | /* used to order data wrt metadata */ |
54 | struct btrfs_ordered_inode_tree ordered_tree; | 54 | struct btrfs_ordered_inode_tree ordered_tree; |
55 | 55 | ||
56 | /* standard acl pointers */ | ||
57 | struct posix_acl *i_acl; | ||
58 | struct posix_acl *i_default_acl; | ||
59 | |||
60 | /* for keeping track of orphaned inodes */ | 56 | /* for keeping track of orphaned inodes */ |
61 | struct list_head i_orphan; | 57 | struct list_head i_orphan; |
62 | 58 | ||
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index de1e2fd32080..9d8ba4d54a37 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/time.h> | 26 | #include <linux/time.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/string.h> | 28 | #include <linux/string.h> |
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/backing-dev.h> | 29 | #include <linux/backing-dev.h> |
31 | #include <linux/mpage.h> | 30 | #include <linux/mpage.h> |
32 | #include <linux/swap.h> | 31 | #include <linux/swap.h> |
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 60a45f3a4e91..3fdcc0512d3a 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -557,19 +557,7 @@ static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) | |||
557 | 557 | ||
558 | btrfs_disk_key_to_cpu(&k1, disk); | 558 | btrfs_disk_key_to_cpu(&k1, disk); |
559 | 559 | ||
560 | if (k1.objectid > k2->objectid) | 560 | return btrfs_comp_cpu_keys(&k1, k2); |
561 | return 1; | ||
562 | if (k1.objectid < k2->objectid) | ||
563 | return -1; | ||
564 | if (k1.type > k2->type) | ||
565 | return 1; | ||
566 | if (k1.type < k2->type) | ||
567 | return -1; | ||
568 | if (k1.offset > k2->offset) | ||
569 | return 1; | ||
570 | if (k1.offset < k2->offset) | ||
571 | return -1; | ||
572 | return 0; | ||
573 | } | 561 | } |
574 | 562 | ||
575 | /* | 563 | /* |
@@ -1052,9 +1040,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
1052 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) | 1040 | BTRFS_NODEPTRS_PER_BLOCK(root) / 4) |
1053 | return 0; | 1041 | return 0; |
1054 | 1042 | ||
1055 | if (btrfs_header_nritems(mid) > 2) | ||
1056 | return 0; | ||
1057 | |||
1058 | if (btrfs_header_nritems(mid) < 2) | 1043 | if (btrfs_header_nritems(mid) < 2) |
1059 | err_on_enospc = 1; | 1044 | err_on_enospc = 1; |
1060 | 1045 | ||
@@ -1701,6 +1686,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1701 | struct extent_buffer *b; | 1686 | struct extent_buffer *b; |
1702 | int slot; | 1687 | int slot; |
1703 | int ret; | 1688 | int ret; |
1689 | int err; | ||
1704 | int level; | 1690 | int level; |
1705 | int lowest_unlock = 1; | 1691 | int lowest_unlock = 1; |
1706 | u8 lowest_level = 0; | 1692 | u8 lowest_level = 0; |
@@ -1737,8 +1723,6 @@ again: | |||
1737 | p->locks[level] = 1; | 1723 | p->locks[level] = 1; |
1738 | 1724 | ||
1739 | if (cow) { | 1725 | if (cow) { |
1740 | int wret; | ||
1741 | |||
1742 | /* | 1726 | /* |
1743 | * if we don't really need to cow this block | 1727 | * if we don't really need to cow this block |
1744 | * then we don't want to set the path blocking, | 1728 | * then we don't want to set the path blocking, |
@@ -1749,12 +1733,12 @@ again: | |||
1749 | 1733 | ||
1750 | btrfs_set_path_blocking(p); | 1734 | btrfs_set_path_blocking(p); |
1751 | 1735 | ||
1752 | wret = btrfs_cow_block(trans, root, b, | 1736 | err = btrfs_cow_block(trans, root, b, |
1753 | p->nodes[level + 1], | 1737 | p->nodes[level + 1], |
1754 | p->slots[level + 1], &b); | 1738 | p->slots[level + 1], &b); |
1755 | if (wret) { | 1739 | if (err) { |
1756 | free_extent_buffer(b); | 1740 | free_extent_buffer(b); |
1757 | ret = wret; | 1741 | ret = err; |
1758 | goto done; | 1742 | goto done; |
1759 | } | 1743 | } |
1760 | } | 1744 | } |
@@ -1793,41 +1777,45 @@ cow_done: | |||
1793 | ret = bin_search(b, key, level, &slot); | 1777 | ret = bin_search(b, key, level, &slot); |
1794 | 1778 | ||
1795 | if (level != 0) { | 1779 | if (level != 0) { |
1796 | if (ret && slot > 0) | 1780 | int dec = 0; |
1781 | if (ret && slot > 0) { | ||
1782 | dec = 1; | ||
1797 | slot -= 1; | 1783 | slot -= 1; |
1784 | } | ||
1798 | p->slots[level] = slot; | 1785 | p->slots[level] = slot; |
1799 | ret = setup_nodes_for_search(trans, root, p, b, level, | 1786 | err = setup_nodes_for_search(trans, root, p, b, level, |
1800 | ins_len); | 1787 | ins_len); |
1801 | if (ret == -EAGAIN) | 1788 | if (err == -EAGAIN) |
1802 | goto again; | 1789 | goto again; |
1803 | else if (ret) | 1790 | if (err) { |
1791 | ret = err; | ||
1804 | goto done; | 1792 | goto done; |
1793 | } | ||
1805 | b = p->nodes[level]; | 1794 | b = p->nodes[level]; |
1806 | slot = p->slots[level]; | 1795 | slot = p->slots[level]; |
1807 | 1796 | ||
1808 | unlock_up(p, level, lowest_unlock); | 1797 | unlock_up(p, level, lowest_unlock); |
1809 | 1798 | ||
1810 | /* this is only true while dropping a snapshot */ | ||
1811 | if (level == lowest_level) { | 1799 | if (level == lowest_level) { |
1812 | ret = 0; | 1800 | if (dec) |
1801 | p->slots[level]++; | ||
1813 | goto done; | 1802 | goto done; |
1814 | } | 1803 | } |
1815 | 1804 | ||
1816 | ret = read_block_for_search(trans, root, p, | 1805 | err = read_block_for_search(trans, root, p, |
1817 | &b, level, slot, key); | 1806 | &b, level, slot, key); |
1818 | if (ret == -EAGAIN) | 1807 | if (err == -EAGAIN) |
1819 | goto again; | 1808 | goto again; |
1820 | 1809 | if (err) { | |
1821 | if (ret == -EIO) | 1810 | ret = err; |
1822 | goto done; | 1811 | goto done; |
1812 | } | ||
1823 | 1813 | ||
1824 | if (!p->skip_locking) { | 1814 | if (!p->skip_locking) { |
1825 | int lret; | ||
1826 | |||
1827 | btrfs_clear_path_blocking(p, NULL); | 1815 | btrfs_clear_path_blocking(p, NULL); |
1828 | lret = btrfs_try_spin_lock(b); | 1816 | err = btrfs_try_spin_lock(b); |
1829 | 1817 | ||
1830 | if (!lret) { | 1818 | if (!err) { |
1831 | btrfs_set_path_blocking(p); | 1819 | btrfs_set_path_blocking(p); |
1832 | btrfs_tree_lock(b); | 1820 | btrfs_tree_lock(b); |
1833 | btrfs_clear_path_blocking(p, b); | 1821 | btrfs_clear_path_blocking(p, b); |
@@ -1837,16 +1825,14 @@ cow_done: | |||
1837 | p->slots[level] = slot; | 1825 | p->slots[level] = slot; |
1838 | if (ins_len > 0 && | 1826 | if (ins_len > 0 && |
1839 | btrfs_leaf_free_space(root, b) < ins_len) { | 1827 | btrfs_leaf_free_space(root, b) < ins_len) { |
1840 | int sret; | ||
1841 | |||
1842 | btrfs_set_path_blocking(p); | 1828 | btrfs_set_path_blocking(p); |
1843 | sret = split_leaf(trans, root, key, | 1829 | err = split_leaf(trans, root, key, |
1844 | p, ins_len, ret == 0); | 1830 | p, ins_len, ret == 0); |
1845 | btrfs_clear_path_blocking(p, NULL); | 1831 | btrfs_clear_path_blocking(p, NULL); |
1846 | 1832 | ||
1847 | BUG_ON(sret > 0); | 1833 | BUG_ON(err > 0); |
1848 | if (sret) { | 1834 | if (err) { |
1849 | ret = sret; | 1835 | ret = err; |
1850 | goto done; | 1836 | goto done; |
1851 | } | 1837 | } |
1852 | } | 1838 | } |
@@ -3807,7 +3793,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
3807 | } | 3793 | } |
3808 | 3794 | ||
3809 | /* delete the leaf if it is mostly empty */ | 3795 | /* delete the leaf if it is mostly empty */ |
3810 | if (used < BTRFS_LEAF_DATA_SIZE(root) / 2) { | 3796 | if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) { |
3811 | /* push_leaf_left fixes the path. | 3797 | /* push_leaf_left fixes the path. |
3812 | * make sure the path still points to our leaf | 3798 | * make sure the path still points to our leaf |
3813 | * for possible call to del_ptr below | 3799 | * for possible call to del_ptr below |
@@ -4042,10 +4028,9 @@ out: | |||
4042 | * calling this function. | 4028 | * calling this function. |
4043 | */ | 4029 | */ |
4044 | int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, | 4030 | int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, |
4045 | struct btrfs_key *key, int lowest_level, | 4031 | struct btrfs_key *key, int level, |
4046 | int cache_only, u64 min_trans) | 4032 | int cache_only, u64 min_trans) |
4047 | { | 4033 | { |
4048 | int level = lowest_level; | ||
4049 | int slot; | 4034 | int slot; |
4050 | struct extent_buffer *c; | 4035 | struct extent_buffer *c; |
4051 | 4036 | ||
@@ -4058,11 +4043,40 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, | |||
4058 | c = path->nodes[level]; | 4043 | c = path->nodes[level]; |
4059 | next: | 4044 | next: |
4060 | if (slot >= btrfs_header_nritems(c)) { | 4045 | if (slot >= btrfs_header_nritems(c)) { |
4061 | level++; | 4046 | int ret; |
4062 | if (level == BTRFS_MAX_LEVEL) | 4047 | int orig_lowest; |
4048 | struct btrfs_key cur_key; | ||
4049 | if (level + 1 >= BTRFS_MAX_LEVEL || | ||
4050 | !path->nodes[level + 1]) | ||
4063 | return 1; | 4051 | return 1; |
4064 | continue; | 4052 | |
4053 | if (path->locks[level + 1]) { | ||
4054 | level++; | ||
4055 | continue; | ||
4056 | } | ||
4057 | |||
4058 | slot = btrfs_header_nritems(c) - 1; | ||
4059 | if (level == 0) | ||
4060 | btrfs_item_key_to_cpu(c, &cur_key, slot); | ||
4061 | else | ||
4062 | btrfs_node_key_to_cpu(c, &cur_key, slot); | ||
4063 | |||
4064 | orig_lowest = path->lowest_level; | ||
4065 | btrfs_release_path(root, path); | ||
4066 | path->lowest_level = level; | ||
4067 | ret = btrfs_search_slot(NULL, root, &cur_key, path, | ||
4068 | 0, 0); | ||
4069 | path->lowest_level = orig_lowest; | ||
4070 | if (ret < 0) | ||
4071 | return ret; | ||
4072 | |||
4073 | c = path->nodes[level]; | ||
4074 | slot = path->slots[level]; | ||
4075 | if (ret == 0) | ||
4076 | slot++; | ||
4077 | goto next; | ||
4065 | } | 4078 | } |
4079 | |||
4066 | if (level == 0) | 4080 | if (level == 0) |
4067 | btrfs_item_key_to_cpu(c, key, slot); | 4081 | btrfs_item_key_to_cpu(c, key, slot); |
4068 | else { | 4082 | else { |
@@ -4146,7 +4160,8 @@ again: | |||
4146 | * advance the path if there are now more items available. | 4160 | * advance the path if there are now more items available. |
4147 | */ | 4161 | */ |
4148 | if (nritems > 0 && path->slots[0] < nritems - 1) { | 4162 | if (nritems > 0 && path->slots[0] < nritems - 1) { |
4149 | path->slots[0]++; | 4163 | if (ret == 0) |
4164 | path->slots[0]++; | ||
4150 | ret = 0; | 4165 | ret = 0; |
4151 | goto done; | 4166 | goto done; |
4152 | } | 4167 | } |
@@ -4278,10 +4293,10 @@ int btrfs_previous_item(struct btrfs_root *root, | |||
4278 | path->slots[0]--; | 4293 | path->slots[0]--; |
4279 | 4294 | ||
4280 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 4295 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
4281 | if (found_key.type == type) | ||
4282 | return 0; | ||
4283 | if (found_key.objectid < min_objectid) | 4296 | if (found_key.objectid < min_objectid) |
4284 | break; | 4297 | break; |
4298 | if (found_key.type == type) | ||
4299 | return 0; | ||
4285 | if (found_key.objectid == min_objectid && | 4300 | if (found_key.objectid == min_objectid && |
4286 | found_key.type < type) | 4301 | found_key.type < type) |
4287 | break; | 4302 | break; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 03441a99ea38..837435ce84ca 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -41,8 +41,6 @@ struct btrfs_ordered_sum; | |||
41 | 41 | ||
42 | #define BTRFS_MAGIC "_BHRfS_M" | 42 | #define BTRFS_MAGIC "_BHRfS_M" |
43 | 43 | ||
44 | #define BTRFS_ACL_NOT_CACHED ((void *)-1) | ||
45 | |||
46 | #define BTRFS_MAX_LEVEL 8 | 44 | #define BTRFS_MAX_LEVEL 8 |
47 | 45 | ||
48 | #define BTRFS_COMPAT_EXTENT_TREE_V0 | 46 | #define BTRFS_COMPAT_EXTENT_TREE_V0 |
@@ -483,7 +481,7 @@ struct btrfs_shared_data_ref { | |||
483 | 481 | ||
484 | struct btrfs_extent_inline_ref { | 482 | struct btrfs_extent_inline_ref { |
485 | u8 type; | 483 | u8 type; |
486 | u64 offset; | 484 | __le64 offset; |
487 | } __attribute__ ((__packed__)); | 485 | } __attribute__ ((__packed__)); |
488 | 486 | ||
489 | /* old style backrefs item */ | 487 | /* old style backrefs item */ |
@@ -691,6 +689,7 @@ struct btrfs_space_info { | |||
691 | struct list_head block_groups; | 689 | struct list_head block_groups; |
692 | spinlock_t lock; | 690 | spinlock_t lock; |
693 | struct rw_semaphore groups_sem; | 691 | struct rw_semaphore groups_sem; |
692 | atomic_t caching_threads; | ||
694 | }; | 693 | }; |
695 | 694 | ||
696 | /* | 695 | /* |
@@ -709,6 +708,9 @@ struct btrfs_free_cluster { | |||
709 | /* first extent starting offset */ | 708 | /* first extent starting offset */ |
710 | u64 window_start; | 709 | u64 window_start; |
711 | 710 | ||
711 | /* if this cluster simply points at a bitmap in the block group */ | ||
712 | bool points_to_bitmap; | ||
713 | |||
712 | struct btrfs_block_group_cache *block_group; | 714 | struct btrfs_block_group_cache *block_group; |
713 | /* | 715 | /* |
714 | * when a cluster is allocated from a block group, we put the | 716 | * when a cluster is allocated from a block group, we put the |
@@ -718,24 +720,37 @@ struct btrfs_free_cluster { | |||
718 | struct list_head block_group_list; | 720 | struct list_head block_group_list; |
719 | }; | 721 | }; |
720 | 722 | ||
723 | enum btrfs_caching_type { | ||
724 | BTRFS_CACHE_NO = 0, | ||
725 | BTRFS_CACHE_STARTED = 1, | ||
726 | BTRFS_CACHE_FINISHED = 2, | ||
727 | }; | ||
728 | |||
721 | struct btrfs_block_group_cache { | 729 | struct btrfs_block_group_cache { |
722 | struct btrfs_key key; | 730 | struct btrfs_key key; |
723 | struct btrfs_block_group_item item; | 731 | struct btrfs_block_group_item item; |
732 | struct btrfs_fs_info *fs_info; | ||
724 | spinlock_t lock; | 733 | spinlock_t lock; |
725 | struct mutex cache_mutex; | ||
726 | u64 pinned; | 734 | u64 pinned; |
727 | u64 reserved; | 735 | u64 reserved; |
728 | u64 flags; | 736 | u64 flags; |
729 | int cached; | 737 | u64 sectorsize; |
738 | int extents_thresh; | ||
739 | int free_extents; | ||
740 | int total_bitmaps; | ||
730 | int ro; | 741 | int ro; |
731 | int dirty; | 742 | int dirty; |
732 | 743 | ||
744 | /* cache tracking stuff */ | ||
745 | wait_queue_head_t caching_q; | ||
746 | int cached; | ||
747 | |||
733 | struct btrfs_space_info *space_info; | 748 | struct btrfs_space_info *space_info; |
734 | 749 | ||
735 | /* free space cache stuff */ | 750 | /* free space cache stuff */ |
736 | spinlock_t tree_lock; | 751 | spinlock_t tree_lock; |
737 | struct rb_root free_space_bytes; | ||
738 | struct rb_root free_space_offset; | 752 | struct rb_root free_space_offset; |
753 | u64 free_space; | ||
739 | 754 | ||
740 | /* block group cache stuff */ | 755 | /* block group cache stuff */ |
741 | struct rb_node cache_node; | 756 | struct rb_node cache_node; |
@@ -810,6 +825,7 @@ struct btrfs_fs_info { | |||
810 | struct mutex drop_mutex; | 825 | struct mutex drop_mutex; |
811 | struct mutex volume_mutex; | 826 | struct mutex volume_mutex; |
812 | struct mutex tree_reloc_mutex; | 827 | struct mutex tree_reloc_mutex; |
828 | struct rw_semaphore extent_commit_sem; | ||
813 | 829 | ||
814 | /* | 830 | /* |
815 | * this protects the ordered operations list only while we are | 831 | * this protects the ordered operations list only while we are |
@@ -1990,6 +2006,7 @@ void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode, | |||
1990 | u64 bytes); | 2006 | u64 bytes); |
1991 | void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode, | 2007 | void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode, |
1992 | u64 bytes); | 2008 | u64 bytes); |
2009 | void btrfs_free_pinned_extents(struct btrfs_fs_info *info); | ||
1993 | /* ctree.c */ | 2010 | /* ctree.c */ |
1994 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, | 2011 | int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, |
1995 | int level, int *slot); | 2012 | int level, int *slot); |
@@ -2076,8 +2093,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, | |||
2076 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); | 2093 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); |
2077 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); | 2094 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); |
2078 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); | 2095 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); |
2079 | int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | 2096 | int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref); |
2080 | *root); | ||
2081 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | 2097 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, |
2082 | struct btrfs_root *root, | 2098 | struct btrfs_root *root, |
2083 | struct extent_buffer *node, | 2099 | struct extent_buffer *node, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 0d50d49d990a..e83be2e4602c 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -42,6 +42,8 @@ | |||
42 | static struct extent_io_ops btree_extent_io_ops; | 42 | static struct extent_io_ops btree_extent_io_ops; |
43 | static void end_workqueue_fn(struct btrfs_work *work); | 43 | static void end_workqueue_fn(struct btrfs_work *work); |
44 | 44 | ||
45 | static atomic_t btrfs_bdi_num = ATOMIC_INIT(0); | ||
46 | |||
45 | /* | 47 | /* |
46 | * end_io_wq structs are used to do processing in task context when an IO is | 48 | * end_io_wq structs are used to do processing in task context when an IO is |
47 | * complete. This is used during reads to verify checksums, and it is used | 49 | * complete. This is used during reads to verify checksums, and it is used |
@@ -1342,12 +1344,25 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) | |||
1342 | free_extent_map(em); | 1344 | free_extent_map(em); |
1343 | } | 1345 | } |
1344 | 1346 | ||
1347 | /* | ||
1348 | * If this fails, caller must call bdi_destroy() to get rid of the | ||
1349 | * bdi again. | ||
1350 | */ | ||
1345 | static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) | 1351 | static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) |
1346 | { | 1352 | { |
1347 | bdi_init(bdi); | 1353 | int err; |
1354 | |||
1355 | bdi->capabilities = BDI_CAP_MAP_COPY; | ||
1356 | err = bdi_init(bdi); | ||
1357 | if (err) | ||
1358 | return err; | ||
1359 | |||
1360 | err = bdi_register(bdi, NULL, "btrfs-%d", | ||
1361 | atomic_inc_return(&btrfs_bdi_num)); | ||
1362 | if (err) | ||
1363 | return err; | ||
1364 | |||
1348 | bdi->ra_pages = default_backing_dev_info.ra_pages; | 1365 | bdi->ra_pages = default_backing_dev_info.ra_pages; |
1349 | bdi->state = 0; | ||
1350 | bdi->capabilities = default_backing_dev_info.capabilities; | ||
1351 | bdi->unplug_io_fn = btrfs_unplug_io_fn; | 1366 | bdi->unplug_io_fn = btrfs_unplug_io_fn; |
1352 | bdi->unplug_io_data = info; | 1367 | bdi->unplug_io_data = info; |
1353 | bdi->congested_fn = btrfs_congested_fn; | 1368 | bdi->congested_fn = btrfs_congested_fn; |
@@ -1569,7 +1584,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1569 | fs_info->sb = sb; | 1584 | fs_info->sb = sb; |
1570 | fs_info->max_extent = (u64)-1; | 1585 | fs_info->max_extent = (u64)-1; |
1571 | fs_info->max_inline = 8192 * 1024; | 1586 | fs_info->max_inline = 8192 * 1024; |
1572 | setup_bdi(fs_info, &fs_info->bdi); | 1587 | if (setup_bdi(fs_info, &fs_info->bdi)) |
1588 | goto fail_bdi; | ||
1573 | fs_info->btree_inode = new_inode(sb); | 1589 | fs_info->btree_inode = new_inode(sb); |
1574 | fs_info->btree_inode->i_ino = 1; | 1590 | fs_info->btree_inode->i_ino = 1; |
1575 | fs_info->btree_inode->i_nlink = 1; | 1591 | fs_info->btree_inode->i_nlink = 1; |
@@ -1623,6 +1639,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1623 | mutex_init(&fs_info->cleaner_mutex); | 1639 | mutex_init(&fs_info->cleaner_mutex); |
1624 | mutex_init(&fs_info->volume_mutex); | 1640 | mutex_init(&fs_info->volume_mutex); |
1625 | mutex_init(&fs_info->tree_reloc_mutex); | 1641 | mutex_init(&fs_info->tree_reloc_mutex); |
1642 | init_rwsem(&fs_info->extent_commit_sem); | ||
1626 | 1643 | ||
1627 | btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); | 1644 | btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); |
1628 | btrfs_init_free_cluster(&fs_info->data_alloc_cluster); | 1645 | btrfs_init_free_cluster(&fs_info->data_alloc_cluster); |
@@ -1783,6 +1800,11 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1783 | btrfs_super_chunk_root(disk_super), | 1800 | btrfs_super_chunk_root(disk_super), |
1784 | blocksize, generation); | 1801 | blocksize, generation); |
1785 | BUG_ON(!chunk_root->node); | 1802 | BUG_ON(!chunk_root->node); |
1803 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &chunk_root->node->bflags)) { | ||
1804 | printk(KERN_WARNING "btrfs: failed to read chunk root on %s\n", | ||
1805 | sb->s_id); | ||
1806 | goto fail_chunk_root; | ||
1807 | } | ||
1786 | btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); | 1808 | btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); |
1787 | chunk_root->commit_root = btrfs_root_node(chunk_root); | 1809 | chunk_root->commit_root = btrfs_root_node(chunk_root); |
1788 | 1810 | ||
@@ -1810,6 +1832,11 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
1810 | blocksize, generation); | 1832 | blocksize, generation); |
1811 | if (!tree_root->node) | 1833 | if (!tree_root->node) |
1812 | goto fail_chunk_root; | 1834 | goto fail_chunk_root; |
1835 | if (!test_bit(EXTENT_BUFFER_UPTODATE, &tree_root->node->bflags)) { | ||
1836 | printk(KERN_WARNING "btrfs: failed to read tree root on %s\n", | ||
1837 | sb->s_id); | ||
1838 | goto fail_tree_root; | ||
1839 | } | ||
1813 | btrfs_set_root_node(&tree_root->root_item, tree_root->node); | 1840 | btrfs_set_root_node(&tree_root->root_item, tree_root->node); |
1814 | tree_root->commit_root = btrfs_root_node(tree_root); | 1841 | tree_root->commit_root = btrfs_root_node(tree_root); |
1815 | 1842 | ||
@@ -1946,8 +1973,8 @@ fail_iput: | |||
1946 | 1973 | ||
1947 | btrfs_close_devices(fs_info->fs_devices); | 1974 | btrfs_close_devices(fs_info->fs_devices); |
1948 | btrfs_mapping_tree_free(&fs_info->mapping_tree); | 1975 | btrfs_mapping_tree_free(&fs_info->mapping_tree); |
1976 | fail_bdi: | ||
1949 | bdi_destroy(&fs_info->bdi); | 1977 | bdi_destroy(&fs_info->bdi); |
1950 | |||
1951 | fail: | 1978 | fail: |
1952 | kfree(extent_root); | 1979 | kfree(extent_root); |
1953 | kfree(tree_root); | 1980 | kfree(tree_root); |
@@ -2306,6 +2333,9 @@ int close_ctree(struct btrfs_root *root) | |||
2306 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); | 2333 | printk(KERN_ERR "btrfs: commit super ret %d\n", ret); |
2307 | } | 2334 | } |
2308 | 2335 | ||
2336 | fs_info->closing = 2; | ||
2337 | smp_mb(); | ||
2338 | |||
2309 | if (fs_info->delalloc_bytes) { | 2339 | if (fs_info->delalloc_bytes) { |
2310 | printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n", | 2340 | printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n", |
2311 | (unsigned long long)fs_info->delalloc_bytes); | 2341 | (unsigned long long)fs_info->delalloc_bytes); |
@@ -2327,6 +2357,7 @@ int close_ctree(struct btrfs_root *root) | |||
2327 | free_extent_buffer(root->fs_info->csum_root->commit_root); | 2357 | free_extent_buffer(root->fs_info->csum_root->commit_root); |
2328 | 2358 | ||
2329 | btrfs_free_block_groups(root->fs_info); | 2359 | btrfs_free_block_groups(root->fs_info); |
2360 | btrfs_free_pinned_extents(root->fs_info); | ||
2330 | 2361 | ||
2331 | del_fs_roots(fs_info); | 2362 | del_fs_roots(fs_info); |
2332 | 2363 | ||
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index edc7d208c5ce..72a2b9c28e9f 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
22 | #include <linux/sort.h> | 22 | #include <linux/sort.h> |
23 | #include <linux/rcupdate.h> | 23 | #include <linux/rcupdate.h> |
24 | #include <linux/kthread.h> | ||
24 | #include "compat.h" | 25 | #include "compat.h" |
25 | #include "hash.h" | 26 | #include "hash.h" |
26 | #include "ctree.h" | 27 | #include "ctree.h" |
@@ -61,6 +62,13 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, | |||
61 | struct btrfs_root *extent_root, u64 alloc_bytes, | 62 | struct btrfs_root *extent_root, u64 alloc_bytes, |
62 | u64 flags, int force); | 63 | u64 flags, int force); |
63 | 64 | ||
65 | static noinline int | ||
66 | block_group_cache_done(struct btrfs_block_group_cache *cache) | ||
67 | { | ||
68 | smp_mb(); | ||
69 | return cache->cached == BTRFS_CACHE_FINISHED; | ||
70 | } | ||
71 | |||
64 | static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) | 72 | static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) |
65 | { | 73 | { |
66 | return (cache->flags & bits) == bits; | 74 | return (cache->flags & bits) == bits; |
@@ -146,20 +154,70 @@ block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr, | |||
146 | } | 154 | } |
147 | 155 | ||
148 | /* | 156 | /* |
157 | * We always set EXTENT_LOCKED for the super mirror extents so we don't | ||
158 | * overwrite them, so those bits need to be unset. Also, if we are unmounting | ||
159 | * with pinned extents still sitting there because we had a block group caching, | ||
160 | * we need to clear those now, since we are done. | ||
161 | */ | ||
162 | void btrfs_free_pinned_extents(struct btrfs_fs_info *info) | ||
163 | { | ||
164 | u64 start, end, last = 0; | ||
165 | int ret; | ||
166 | |||
167 | while (1) { | ||
168 | ret = find_first_extent_bit(&info->pinned_extents, last, | ||
169 | &start, &end, | ||
170 | EXTENT_LOCKED|EXTENT_DIRTY); | ||
171 | if (ret) | ||
172 | break; | ||
173 | |||
174 | clear_extent_bits(&info->pinned_extents, start, end, | ||
175 | EXTENT_LOCKED|EXTENT_DIRTY, GFP_NOFS); | ||
176 | last = end+1; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | static int remove_sb_from_cache(struct btrfs_root *root, | ||
181 | struct btrfs_block_group_cache *cache) | ||
182 | { | ||
183 | struct btrfs_fs_info *fs_info = root->fs_info; | ||
184 | u64 bytenr; | ||
185 | u64 *logical; | ||
186 | int stripe_len; | ||
187 | int i, nr, ret; | ||
188 | |||
189 | for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { | ||
190 | bytenr = btrfs_sb_offset(i); | ||
191 | ret = btrfs_rmap_block(&root->fs_info->mapping_tree, | ||
192 | cache->key.objectid, bytenr, | ||
193 | 0, &logical, &nr, &stripe_len); | ||
194 | BUG_ON(ret); | ||
195 | while (nr--) { | ||
196 | try_lock_extent(&fs_info->pinned_extents, | ||
197 | logical[nr], | ||
198 | logical[nr] + stripe_len - 1, GFP_NOFS); | ||
199 | } | ||
200 | kfree(logical); | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* | ||
149 | * this is only called by cache_block_group, since we could have freed extents | 207 | * this is only called by cache_block_group, since we could have freed extents |
150 | * we need to check the pinned_extents for any extents that can't be used yet | 208 | * we need to check the pinned_extents for any extents that can't be used yet |
151 | * since their free space will be released as soon as the transaction commits. | 209 | * since their free space will be released as soon as the transaction commits. |
152 | */ | 210 | */ |
153 | static int add_new_free_space(struct btrfs_block_group_cache *block_group, | 211 | static u64 add_new_free_space(struct btrfs_block_group_cache *block_group, |
154 | struct btrfs_fs_info *info, u64 start, u64 end) | 212 | struct btrfs_fs_info *info, u64 start, u64 end) |
155 | { | 213 | { |
156 | u64 extent_start, extent_end, size; | 214 | u64 extent_start, extent_end, size, total_added = 0; |
157 | int ret; | 215 | int ret; |
158 | 216 | ||
159 | while (start < end) { | 217 | while (start < end) { |
160 | ret = find_first_extent_bit(&info->pinned_extents, start, | 218 | ret = find_first_extent_bit(&info->pinned_extents, start, |
161 | &extent_start, &extent_end, | 219 | &extent_start, &extent_end, |
162 | EXTENT_DIRTY); | 220 | EXTENT_DIRTY|EXTENT_LOCKED); |
163 | if (ret) | 221 | if (ret) |
164 | break; | 222 | break; |
165 | 223 | ||
@@ -167,6 +225,7 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group, | |||
167 | start = extent_end + 1; | 225 | start = extent_end + 1; |
168 | } else if (extent_start > start && extent_start < end) { | 226 | } else if (extent_start > start && extent_start < end) { |
169 | size = extent_start - start; | 227 | size = extent_start - start; |
228 | total_added += size; | ||
170 | ret = btrfs_add_free_space(block_group, start, | 229 | ret = btrfs_add_free_space(block_group, start, |
171 | size); | 230 | size); |
172 | BUG_ON(ret); | 231 | BUG_ON(ret); |
@@ -178,84 +237,93 @@ static int add_new_free_space(struct btrfs_block_group_cache *block_group, | |||
178 | 237 | ||
179 | if (start < end) { | 238 | if (start < end) { |
180 | size = end - start; | 239 | size = end - start; |
240 | total_added += size; | ||
181 | ret = btrfs_add_free_space(block_group, start, size); | 241 | ret = btrfs_add_free_space(block_group, start, size); |
182 | BUG_ON(ret); | 242 | BUG_ON(ret); |
183 | } | 243 | } |
184 | 244 | ||
185 | return 0; | 245 | return total_added; |
186 | } | 246 | } |
187 | 247 | ||
188 | static int remove_sb_from_cache(struct btrfs_root *root, | 248 | static int caching_kthread(void *data) |
189 | struct btrfs_block_group_cache *cache) | ||
190 | { | ||
191 | u64 bytenr; | ||
192 | u64 *logical; | ||
193 | int stripe_len; | ||
194 | int i, nr, ret; | ||
195 | |||
196 | for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { | ||
197 | bytenr = btrfs_sb_offset(i); | ||
198 | ret = btrfs_rmap_block(&root->fs_info->mapping_tree, | ||
199 | cache->key.objectid, bytenr, 0, | ||
200 | &logical, &nr, &stripe_len); | ||
201 | BUG_ON(ret); | ||
202 | while (nr--) { | ||
203 | btrfs_remove_free_space(cache, logical[nr], | ||
204 | stripe_len); | ||
205 | } | ||
206 | kfree(logical); | ||
207 | } | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int cache_block_group(struct btrfs_root *root, | ||
212 | struct btrfs_block_group_cache *block_group) | ||
213 | { | 249 | { |
250 | struct btrfs_block_group_cache *block_group = data; | ||
251 | struct btrfs_fs_info *fs_info = block_group->fs_info; | ||
252 | u64 last = 0; | ||
214 | struct btrfs_path *path; | 253 | struct btrfs_path *path; |
215 | int ret = 0; | 254 | int ret = 0; |
216 | struct btrfs_key key; | 255 | struct btrfs_key key; |
217 | struct extent_buffer *leaf; | 256 | struct extent_buffer *leaf; |
218 | int slot; | 257 | int slot; |
219 | u64 last; | 258 | u64 total_found = 0; |
220 | 259 | ||
221 | if (!block_group) | 260 | BUG_ON(!fs_info); |
222 | return 0; | ||
223 | |||
224 | root = root->fs_info->extent_root; | ||
225 | |||
226 | if (block_group->cached) | ||
227 | return 0; | ||
228 | 261 | ||
229 | path = btrfs_alloc_path(); | 262 | path = btrfs_alloc_path(); |
230 | if (!path) | 263 | if (!path) |
231 | return -ENOMEM; | 264 | return -ENOMEM; |
232 | 265 | ||
233 | path->reada = 2; | 266 | atomic_inc(&block_group->space_info->caching_threads); |
267 | last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); | ||
234 | /* | 268 | /* |
235 | * we get into deadlocks with paths held by callers of this function. | 269 | * We don't want to deadlock with somebody trying to allocate a new |
236 | * since the alloc_mutex is protecting things right now, just | 270 | * extent for the extent root while also trying to search the extent |
237 | * skip the locking here | 271 | * root to add free space. So we skip locking and search the commit |
272 | * root, since its read-only | ||
238 | */ | 273 | */ |
239 | path->skip_locking = 1; | 274 | path->skip_locking = 1; |
240 | last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); | 275 | path->search_commit_root = 1; |
276 | path->reada = 2; | ||
277 | |||
241 | key.objectid = last; | 278 | key.objectid = last; |
242 | key.offset = 0; | 279 | key.offset = 0; |
243 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); | 280 | btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY); |
244 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 281 | again: |
282 | /* need to make sure the commit_root doesn't disappear */ | ||
283 | down_read(&fs_info->extent_commit_sem); | ||
284 | |||
285 | ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); | ||
245 | if (ret < 0) | 286 | if (ret < 0) |
246 | goto err; | 287 | goto err; |
247 | 288 | ||
248 | while (1) { | 289 | while (1) { |
290 | smp_mb(); | ||
291 | if (block_group->fs_info->closing > 1) { | ||
292 | last = (u64)-1; | ||
293 | break; | ||
294 | } | ||
295 | |||
249 | leaf = path->nodes[0]; | 296 | leaf = path->nodes[0]; |
250 | slot = path->slots[0]; | 297 | slot = path->slots[0]; |
251 | if (slot >= btrfs_header_nritems(leaf)) { | 298 | if (slot >= btrfs_header_nritems(leaf)) { |
252 | ret = btrfs_next_leaf(root, path); | 299 | ret = btrfs_next_leaf(fs_info->extent_root, path); |
253 | if (ret < 0) | 300 | if (ret < 0) |
254 | goto err; | 301 | goto err; |
255 | if (ret == 0) | 302 | else if (ret) |
256 | continue; | ||
257 | else | ||
258 | break; | 303 | break; |
304 | |||
305 | if (need_resched() || | ||
306 | btrfs_transaction_in_commit(fs_info)) { | ||
307 | leaf = path->nodes[0]; | ||
308 | |||
309 | /* this shouldn't happen, but if the | ||
310 | * leaf is empty just move on. | ||
311 | */ | ||
312 | if (btrfs_header_nritems(leaf) == 0) | ||
313 | break; | ||
314 | /* | ||
315 | * we need to copy the key out so that | ||
316 | * we are sure the next search advances | ||
317 | * us forward in the btree. | ||
318 | */ | ||
319 | btrfs_item_key_to_cpu(leaf, &key, 0); | ||
320 | btrfs_release_path(fs_info->extent_root, path); | ||
321 | up_read(&fs_info->extent_commit_sem); | ||
322 | schedule_timeout(1); | ||
323 | goto again; | ||
324 | } | ||
325 | |||
326 | continue; | ||
259 | } | 327 | } |
260 | btrfs_item_key_to_cpu(leaf, &key, slot); | 328 | btrfs_item_key_to_cpu(leaf, &key, slot); |
261 | if (key.objectid < block_group->key.objectid) | 329 | if (key.objectid < block_group->key.objectid) |
@@ -266,24 +334,59 @@ static int cache_block_group(struct btrfs_root *root, | |||
266 | break; | 334 | break; |
267 | 335 | ||
268 | if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) { | 336 | if (btrfs_key_type(&key) == BTRFS_EXTENT_ITEM_KEY) { |
269 | add_new_free_space(block_group, root->fs_info, last, | 337 | total_found += add_new_free_space(block_group, |
270 | key.objectid); | 338 | fs_info, last, |
271 | 339 | key.objectid); | |
272 | last = key.objectid + key.offset; | 340 | last = key.objectid + key.offset; |
273 | } | 341 | } |
342 | |||
343 | if (total_found > (1024 * 1024 * 2)) { | ||
344 | total_found = 0; | ||
345 | wake_up(&block_group->caching_q); | ||
346 | } | ||
274 | next: | 347 | next: |
275 | path->slots[0]++; | 348 | path->slots[0]++; |
276 | } | 349 | } |
350 | ret = 0; | ||
277 | 351 | ||
278 | add_new_free_space(block_group, root->fs_info, last, | 352 | total_found += add_new_free_space(block_group, fs_info, last, |
279 | block_group->key.objectid + | 353 | block_group->key.objectid + |
280 | block_group->key.offset); | 354 | block_group->key.offset); |
355 | |||
356 | spin_lock(&block_group->lock); | ||
357 | block_group->cached = BTRFS_CACHE_FINISHED; | ||
358 | spin_unlock(&block_group->lock); | ||
281 | 359 | ||
282 | block_group->cached = 1; | ||
283 | remove_sb_from_cache(root, block_group); | ||
284 | ret = 0; | ||
285 | err: | 360 | err: |
286 | btrfs_free_path(path); | 361 | btrfs_free_path(path); |
362 | up_read(&fs_info->extent_commit_sem); | ||
363 | atomic_dec(&block_group->space_info->caching_threads); | ||
364 | wake_up(&block_group->caching_q); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int cache_block_group(struct btrfs_block_group_cache *cache) | ||
370 | { | ||
371 | struct task_struct *tsk; | ||
372 | int ret = 0; | ||
373 | |||
374 | spin_lock(&cache->lock); | ||
375 | if (cache->cached != BTRFS_CACHE_NO) { | ||
376 | spin_unlock(&cache->lock); | ||
377 | return ret; | ||
378 | } | ||
379 | cache->cached = BTRFS_CACHE_STARTED; | ||
380 | spin_unlock(&cache->lock); | ||
381 | |||
382 | tsk = kthread_run(caching_kthread, cache, "btrfs-cache-%llu\n", | ||
383 | cache->key.objectid); | ||
384 | if (IS_ERR(tsk)) { | ||
385 | ret = PTR_ERR(tsk); | ||
386 | printk(KERN_ERR "error running thread %d\n", ret); | ||
387 | BUG(); | ||
388 | } | ||
389 | |||
287 | return ret; | 390 | return ret; |
288 | } | 391 | } |
289 | 392 | ||
@@ -990,15 +1093,13 @@ static inline int extent_ref_type(u64 parent, u64 owner) | |||
990 | return type; | 1093 | return type; |
991 | } | 1094 | } |
992 | 1095 | ||
993 | static int find_next_key(struct btrfs_path *path, struct btrfs_key *key) | 1096 | static int find_next_key(struct btrfs_path *path, int level, |
1097 | struct btrfs_key *key) | ||
994 | 1098 | ||
995 | { | 1099 | { |
996 | int level; | 1100 | for (; level < BTRFS_MAX_LEVEL; level++) { |
997 | BUG_ON(!path->keep_locks); | ||
998 | for (level = 0; level < BTRFS_MAX_LEVEL; level++) { | ||
999 | if (!path->nodes[level]) | 1101 | if (!path->nodes[level]) |
1000 | break; | 1102 | break; |
1001 | btrfs_assert_tree_locked(path->nodes[level]); | ||
1002 | if (path->slots[level] + 1 >= | 1103 | if (path->slots[level] + 1 >= |
1003 | btrfs_header_nritems(path->nodes[level])) | 1104 | btrfs_header_nritems(path->nodes[level])) |
1004 | continue; | 1105 | continue; |
@@ -1158,7 +1259,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, | |||
1158 | * For simplicity, we just do not add new inline back | 1259 | * For simplicity, we just do not add new inline back |
1159 | * ref if there is any kind of item for this block | 1260 | * ref if there is any kind of item for this block |
1160 | */ | 1261 | */ |
1161 | if (find_next_key(path, &key) == 0 && key.objectid == bytenr && | 1262 | if (find_next_key(path, 0, &key) == 0 && |
1263 | key.objectid == bytenr && | ||
1162 | key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) { | 1264 | key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) { |
1163 | err = -EAGAIN; | 1265 | err = -EAGAIN; |
1164 | goto out; | 1266 | goto out; |
@@ -2388,13 +2490,29 @@ fail: | |||
2388 | 2490 | ||
2389 | } | 2491 | } |
2390 | 2492 | ||
2493 | static struct btrfs_block_group_cache * | ||
2494 | next_block_group(struct btrfs_root *root, | ||
2495 | struct btrfs_block_group_cache *cache) | ||
2496 | { | ||
2497 | struct rb_node *node; | ||
2498 | spin_lock(&root->fs_info->block_group_cache_lock); | ||
2499 | node = rb_next(&cache->cache_node); | ||
2500 | btrfs_put_block_group(cache); | ||
2501 | if (node) { | ||
2502 | cache = rb_entry(node, struct btrfs_block_group_cache, | ||
2503 | cache_node); | ||
2504 | atomic_inc(&cache->count); | ||
2505 | } else | ||
2506 | cache = NULL; | ||
2507 | spin_unlock(&root->fs_info->block_group_cache_lock); | ||
2508 | return cache; | ||
2509 | } | ||
2510 | |||
2391 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | 2511 | int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, |
2392 | struct btrfs_root *root) | 2512 | struct btrfs_root *root) |
2393 | { | 2513 | { |
2394 | struct btrfs_block_group_cache *cache, *entry; | 2514 | struct btrfs_block_group_cache *cache; |
2395 | struct rb_node *n; | ||
2396 | int err = 0; | 2515 | int err = 0; |
2397 | int werr = 0; | ||
2398 | struct btrfs_path *path; | 2516 | struct btrfs_path *path; |
2399 | u64 last = 0; | 2517 | u64 last = 0; |
2400 | 2518 | ||
@@ -2403,39 +2521,35 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
2403 | return -ENOMEM; | 2521 | return -ENOMEM; |
2404 | 2522 | ||
2405 | while (1) { | 2523 | while (1) { |
2406 | cache = NULL; | 2524 | if (last == 0) { |
2407 | spin_lock(&root->fs_info->block_group_cache_lock); | 2525 | err = btrfs_run_delayed_refs(trans, root, |
2408 | for (n = rb_first(&root->fs_info->block_group_cache_tree); | 2526 | (unsigned long)-1); |
2409 | n; n = rb_next(n)) { | 2527 | BUG_ON(err); |
2410 | entry = rb_entry(n, struct btrfs_block_group_cache, | ||
2411 | cache_node); | ||
2412 | if (entry->dirty) { | ||
2413 | cache = entry; | ||
2414 | break; | ||
2415 | } | ||
2416 | } | 2528 | } |
2417 | spin_unlock(&root->fs_info->block_group_cache_lock); | ||
2418 | 2529 | ||
2419 | if (!cache) | 2530 | cache = btrfs_lookup_first_block_group(root->fs_info, last); |
2420 | break; | 2531 | while (cache) { |
2532 | if (cache->dirty) | ||
2533 | break; | ||
2534 | cache = next_block_group(root, cache); | ||
2535 | } | ||
2536 | if (!cache) { | ||
2537 | if (last == 0) | ||
2538 | break; | ||
2539 | last = 0; | ||
2540 | continue; | ||
2541 | } | ||
2421 | 2542 | ||
2422 | cache->dirty = 0; | 2543 | cache->dirty = 0; |
2423 | last += cache->key.offset; | 2544 | last = cache->key.objectid + cache->key.offset; |
2424 | 2545 | ||
2425 | err = write_one_cache_group(trans, root, | 2546 | err = write_one_cache_group(trans, root, path, cache); |
2426 | path, cache); | 2547 | BUG_ON(err); |
2427 | /* | 2548 | btrfs_put_block_group(cache); |
2428 | * if we fail to write the cache group, we want | ||
2429 | * to keep it marked dirty in hopes that a later | ||
2430 | * write will work | ||
2431 | */ | ||
2432 | if (err) { | ||
2433 | werr = err; | ||
2434 | continue; | ||
2435 | } | ||
2436 | } | 2549 | } |
2550 | |||
2437 | btrfs_free_path(path); | 2551 | btrfs_free_path(path); |
2438 | return werr; | 2552 | return 0; |
2439 | } | 2553 | } |
2440 | 2554 | ||
2441 | int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr) | 2555 | int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr) |
@@ -2485,6 +2599,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
2485 | found->force_alloc = 0; | 2599 | found->force_alloc = 0; |
2486 | *space_info = found; | 2600 | *space_info = found; |
2487 | list_add_rcu(&found->list, &info->space_info); | 2601 | list_add_rcu(&found->list, &info->space_info); |
2602 | atomic_set(&found->caching_threads, 0); | ||
2488 | return 0; | 2603 | return 0; |
2489 | } | 2604 | } |
2490 | 2605 | ||
@@ -2697,7 +2812,7 @@ again: | |||
2697 | 2812 | ||
2698 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" | 2813 | printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes" |
2699 | ", %llu bytes_used, %llu bytes_reserved, " | 2814 | ", %llu bytes_used, %llu bytes_reserved, " |
2700 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use" | 2815 | "%llu bytes_pinned, %llu bytes_readonly, %llu may use " |
2701 | "%llu total\n", (unsigned long long)bytes, | 2816 | "%llu total\n", (unsigned long long)bytes, |
2702 | (unsigned long long)data_sinfo->bytes_delalloc, | 2817 | (unsigned long long)data_sinfo->bytes_delalloc, |
2703 | (unsigned long long)data_sinfo->bytes_used, | 2818 | (unsigned long long)data_sinfo->bytes_used, |
@@ -2948,13 +3063,9 @@ int btrfs_update_pinned_extents(struct btrfs_root *root, | |||
2948 | struct btrfs_block_group_cache *cache; | 3063 | struct btrfs_block_group_cache *cache; |
2949 | struct btrfs_fs_info *fs_info = root->fs_info; | 3064 | struct btrfs_fs_info *fs_info = root->fs_info; |
2950 | 3065 | ||
2951 | if (pin) { | 3066 | if (pin) |
2952 | set_extent_dirty(&fs_info->pinned_extents, | 3067 | set_extent_dirty(&fs_info->pinned_extents, |
2953 | bytenr, bytenr + num - 1, GFP_NOFS); | 3068 | bytenr, bytenr + num - 1, GFP_NOFS); |
2954 | } else { | ||
2955 | clear_extent_dirty(&fs_info->pinned_extents, | ||
2956 | bytenr, bytenr + num - 1, GFP_NOFS); | ||
2957 | } | ||
2958 | 3069 | ||
2959 | while (num > 0) { | 3070 | while (num > 0) { |
2960 | cache = btrfs_lookup_block_group(fs_info, bytenr); | 3071 | cache = btrfs_lookup_block_group(fs_info, bytenr); |
@@ -2970,14 +3081,34 @@ int btrfs_update_pinned_extents(struct btrfs_root *root, | |||
2970 | spin_unlock(&cache->space_info->lock); | 3081 | spin_unlock(&cache->space_info->lock); |
2971 | fs_info->total_pinned += len; | 3082 | fs_info->total_pinned += len; |
2972 | } else { | 3083 | } else { |
3084 | int unpin = 0; | ||
3085 | |||
3086 | /* | ||
3087 | * in order to not race with the block group caching, we | ||
3088 | * only want to unpin the extent if we are cached. If | ||
3089 | * we aren't cached, we want to start async caching this | ||
3090 | * block group so we can free the extent the next time | ||
3091 | * around. | ||
3092 | */ | ||
2973 | spin_lock(&cache->space_info->lock); | 3093 | spin_lock(&cache->space_info->lock); |
2974 | spin_lock(&cache->lock); | 3094 | spin_lock(&cache->lock); |
2975 | cache->pinned -= len; | 3095 | unpin = (cache->cached == BTRFS_CACHE_FINISHED); |
2976 | cache->space_info->bytes_pinned -= len; | 3096 | if (likely(unpin)) { |
3097 | cache->pinned -= len; | ||
3098 | cache->space_info->bytes_pinned -= len; | ||
3099 | fs_info->total_pinned -= len; | ||
3100 | } | ||
2977 | spin_unlock(&cache->lock); | 3101 | spin_unlock(&cache->lock); |
2978 | spin_unlock(&cache->space_info->lock); | 3102 | spin_unlock(&cache->space_info->lock); |
2979 | fs_info->total_pinned -= len; | 3103 | |
2980 | if (cache->cached) | 3104 | if (likely(unpin)) |
3105 | clear_extent_dirty(&fs_info->pinned_extents, | ||
3106 | bytenr, bytenr + len -1, | ||
3107 | GFP_NOFS); | ||
3108 | else | ||
3109 | cache_block_group(cache); | ||
3110 | |||
3111 | if (unpin) | ||
2981 | btrfs_add_free_space(cache, bytenr, len); | 3112 | btrfs_add_free_space(cache, bytenr, len); |
2982 | } | 3113 | } |
2983 | btrfs_put_block_group(cache); | 3114 | btrfs_put_block_group(cache); |
@@ -3031,6 +3162,7 @@ int btrfs_copy_pinned(struct btrfs_root *root, struct extent_io_tree *copy) | |||
3031 | &start, &end, EXTENT_DIRTY); | 3162 | &start, &end, EXTENT_DIRTY); |
3032 | if (ret) | 3163 | if (ret) |
3033 | break; | 3164 | break; |
3165 | |||
3034 | set_extent_dirty(copy, start, end, GFP_NOFS); | 3166 | set_extent_dirty(copy, start, end, GFP_NOFS); |
3035 | last = end + 1; | 3167 | last = end + 1; |
3036 | } | 3168 | } |
@@ -3059,6 +3191,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, | |||
3059 | 3191 | ||
3060 | cond_resched(); | 3192 | cond_resched(); |
3061 | } | 3193 | } |
3194 | |||
3062 | return ret; | 3195 | return ret; |
3063 | } | 3196 | } |
3064 | 3197 | ||
@@ -3437,6 +3570,45 @@ static u64 stripe_align(struct btrfs_root *root, u64 val) | |||
3437 | } | 3570 | } |
3438 | 3571 | ||
3439 | /* | 3572 | /* |
3573 | * when we wait for progress in the block group caching, its because | ||
3574 | * our allocation attempt failed at least once. So, we must sleep | ||
3575 | * and let some progress happen before we try again. | ||
3576 | * | ||
3577 | * This function will sleep at least once waiting for new free space to | ||
3578 | * show up, and then it will check the block group free space numbers | ||
3579 | * for our min num_bytes. Another option is to have it go ahead | ||
3580 | * and look in the rbtree for a free extent of a given size, but this | ||
3581 | * is a good start. | ||
3582 | */ | ||
3583 | static noinline int | ||
3584 | wait_block_group_cache_progress(struct btrfs_block_group_cache *cache, | ||
3585 | u64 num_bytes) | ||
3586 | { | ||
3587 | DEFINE_WAIT(wait); | ||
3588 | |||
3589 | prepare_to_wait(&cache->caching_q, &wait, TASK_UNINTERRUPTIBLE); | ||
3590 | |||
3591 | if (block_group_cache_done(cache)) { | ||
3592 | finish_wait(&cache->caching_q, &wait); | ||
3593 | return 0; | ||
3594 | } | ||
3595 | schedule(); | ||
3596 | finish_wait(&cache->caching_q, &wait); | ||
3597 | |||
3598 | wait_event(cache->caching_q, block_group_cache_done(cache) || | ||
3599 | (cache->free_space >= num_bytes)); | ||
3600 | return 0; | ||
3601 | } | ||
3602 | |||
3603 | enum btrfs_loop_type { | ||
3604 | LOOP_CACHED_ONLY = 0, | ||
3605 | LOOP_CACHING_NOWAIT = 1, | ||
3606 | LOOP_CACHING_WAIT = 2, | ||
3607 | LOOP_ALLOC_CHUNK = 3, | ||
3608 | LOOP_NO_EMPTY_SIZE = 4, | ||
3609 | }; | ||
3610 | |||
3611 | /* | ||
3440 | * walks the btree of allocated extents and find a hole of a given size. | 3612 | * walks the btree of allocated extents and find a hole of a given size. |
3441 | * The key ins is changed to record the hole: | 3613 | * The key ins is changed to record the hole: |
3442 | * ins->objectid == block start | 3614 | * ins->objectid == block start |
@@ -3461,6 +3633,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, | |||
3461 | struct btrfs_space_info *space_info; | 3633 | struct btrfs_space_info *space_info; |
3462 | int last_ptr_loop = 0; | 3634 | int last_ptr_loop = 0; |
3463 | int loop = 0; | 3635 | int loop = 0; |
3636 | bool found_uncached_bg = false; | ||
3464 | 3637 | ||
3465 | WARN_ON(num_bytes < root->sectorsize); | 3638 | WARN_ON(num_bytes < root->sectorsize); |
3466 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 3639 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
@@ -3492,15 +3665,18 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans, | |||
3492 | search_start = max(search_start, first_logical_byte(root, 0)); | 3665 | search_start = max(search_start, first_logical_byte(root, 0)); |
3493 | search_start = max(search_start, hint_byte); | 3666 | search_start = max(search_start, hint_byte); |
3494 | 3667 | ||
3495 | if (!last_ptr) { | 3668 | if (!last_ptr) |
3496 | empty_cluster = 0; | 3669 | empty_cluster = 0; |
3497 | loop = 1; | ||
3498 | } | ||
3499 | 3670 | ||
3500 | if (search_start == hint_byte) { | 3671 | if (search_start == hint_byte) { |
3501 | block_group = btrfs_lookup_block_group(root->fs_info, | 3672 | block_group = btrfs_lookup_block_group(root->fs_info, |
3502 | search_start); | 3673 | search_start); |
3503 | if (block_group && block_group_bits(block_group, data)) { | 3674 | /* |
3675 | * we don't want to use the block group if it doesn't match our | ||
3676 | * allocation bits, or if its not cached. | ||
3677 | */ | ||
3678 | if (block_group && block_group_bits(block_group, data) && | ||
3679 | block_group_cache_done(block_group)) { | ||
3504 | down_read(&space_info->groups_sem); | 3680 | down_read(&space_info->groups_sem); |
3505 | if (list_empty(&block_group->list) || | 3681 | if (list_empty(&block_group->list) || |
3506 | block_group->ro) { | 3682 | block_group->ro) { |
@@ -3523,21 +3699,35 @@ search: | |||
3523 | down_read(&space_info->groups_sem); | 3699 | down_read(&space_info->groups_sem); |
3524 | list_for_each_entry(block_group, &space_info->block_groups, list) { | 3700 | list_for_each_entry(block_group, &space_info->block_groups, list) { |
3525 | u64 offset; | 3701 | u64 offset; |
3702 | int cached; | ||
3526 | 3703 | ||
3527 | atomic_inc(&block_group->count); | 3704 | atomic_inc(&block_group->count); |
3528 | search_start = block_group->key.objectid; | 3705 | search_start = block_group->key.objectid; |
3529 | 3706 | ||
3530 | have_block_group: | 3707 | have_block_group: |
3531 | if (unlikely(!block_group->cached)) { | 3708 | if (unlikely(block_group->cached == BTRFS_CACHE_NO)) { |
3532 | mutex_lock(&block_group->cache_mutex); | 3709 | /* |
3533 | ret = cache_block_group(root, block_group); | 3710 | * we want to start caching kthreads, but not too many |
3534 | mutex_unlock(&block_group->cache_mutex); | 3711 | * right off the bat so we don't overwhelm the system, |
3535 | if (ret) { | 3712 | * so only start them if there are less than 2 and we're |
3536 | btrfs_put_block_group(block_group); | 3713 | * in the initial allocation phase. |
3537 | break; | 3714 | */ |
3715 | if (loop > LOOP_CACHING_NOWAIT || | ||
3716 | atomic_read(&space_info->caching_threads) < 2) { | ||
3717 | ret = cache_block_group(block_group); | ||
3718 | BUG_ON(ret); | ||
3538 | } | 3719 | } |
3539 | } | 3720 | } |
3540 | 3721 | ||
3722 | cached = block_group_cache_done(block_group); | ||
3723 | if (unlikely(!cached)) { | ||
3724 | found_uncached_bg = true; | ||
3725 | |||
3726 | /* if we only want cached bgs, loop */ | ||
3727 | if (loop == LOOP_CACHED_ONLY) | ||
3728 | goto loop; | ||
3729 | } | ||
3730 | |||
3541 | if (unlikely(block_group->ro)) | 3731 | if (unlikely(block_group->ro)) |
3542 | goto loop; | 3732 | goto loop; |
3543 | 3733 | ||
@@ -3616,14 +3806,21 @@ refill_cluster: | |||
3616 | spin_unlock(&last_ptr->refill_lock); | 3806 | spin_unlock(&last_ptr->refill_lock); |
3617 | goto checks; | 3807 | goto checks; |
3618 | } | 3808 | } |
3809 | } else if (!cached && loop > LOOP_CACHING_NOWAIT) { | ||
3810 | spin_unlock(&last_ptr->refill_lock); | ||
3811 | |||
3812 | wait_block_group_cache_progress(block_group, | ||
3813 | num_bytes + empty_cluster + empty_size); | ||
3814 | goto have_block_group; | ||
3619 | } | 3815 | } |
3816 | |||
3620 | /* | 3817 | /* |
3621 | * at this point we either didn't find a cluster | 3818 | * at this point we either didn't find a cluster |
3622 | * or we weren't able to allocate a block from our | 3819 | * or we weren't able to allocate a block from our |
3623 | * cluster. Free the cluster we've been trying | 3820 | * cluster. Free the cluster we've been trying |
3624 | * to use, and go to the next block group | 3821 | * to use, and go to the next block group |
3625 | */ | 3822 | */ |
3626 | if (loop < 2) { | 3823 | if (loop < LOOP_NO_EMPTY_SIZE) { |
3627 | btrfs_return_cluster_to_free_space(NULL, | 3824 | btrfs_return_cluster_to_free_space(NULL, |
3628 | last_ptr); | 3825 | last_ptr); |
3629 | spin_unlock(&last_ptr->refill_lock); | 3826 | spin_unlock(&last_ptr->refill_lock); |
@@ -3634,11 +3831,17 @@ refill_cluster: | |||
3634 | 3831 | ||
3635 | offset = btrfs_find_space_for_alloc(block_group, search_start, | 3832 | offset = btrfs_find_space_for_alloc(block_group, search_start, |
3636 | num_bytes, empty_size); | 3833 | num_bytes, empty_size); |
3637 | if (!offset) | 3834 | if (!offset && (cached || (!cached && |
3835 | loop == LOOP_CACHING_NOWAIT))) { | ||
3638 | goto loop; | 3836 | goto loop; |
3837 | } else if (!offset && (!cached && | ||
3838 | loop > LOOP_CACHING_NOWAIT)) { | ||
3839 | wait_block_group_cache_progress(block_group, | ||
3840 | num_bytes + empty_size); | ||
3841 | goto have_block_group; | ||
3842 | } | ||
3639 | checks: | 3843 | checks: |
3640 | search_start = stripe_align(root, offset); | 3844 | search_start = stripe_align(root, offset); |
3641 | |||
3642 | /* move on to the next group */ | 3845 | /* move on to the next group */ |
3643 | if (search_start + num_bytes >= search_end) { | 3846 | if (search_start + num_bytes >= search_end) { |
3644 | btrfs_add_free_space(block_group, offset, num_bytes); | 3847 | btrfs_add_free_space(block_group, offset, num_bytes); |
@@ -3684,13 +3887,26 @@ loop: | |||
3684 | } | 3887 | } |
3685 | up_read(&space_info->groups_sem); | 3888 | up_read(&space_info->groups_sem); |
3686 | 3889 | ||
3687 | /* loop == 0, try to find a clustered alloc in every block group | 3890 | /* LOOP_CACHED_ONLY, only search fully cached block groups |
3688 | * loop == 1, try again after forcing a chunk allocation | 3891 | * LOOP_CACHING_NOWAIT, search partially cached block groups, but |
3689 | * loop == 2, set empty_size and empty_cluster to 0 and try again | 3892 | * dont wait foR them to finish caching |
3893 | * LOOP_CACHING_WAIT, search everything, and wait if our bg is caching | ||
3894 | * LOOP_ALLOC_CHUNK, force a chunk allocation and try again | ||
3895 | * LOOP_NO_EMPTY_SIZE, set empty_size and empty_cluster to 0 and try | ||
3896 | * again | ||
3690 | */ | 3897 | */ |
3691 | if (!ins->objectid && loop < 3 && | 3898 | if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE && |
3692 | (empty_size || empty_cluster || allowed_chunk_alloc)) { | 3899 | (found_uncached_bg || empty_size || empty_cluster || |
3693 | if (loop >= 2) { | 3900 | allowed_chunk_alloc)) { |
3901 | if (found_uncached_bg) { | ||
3902 | found_uncached_bg = false; | ||
3903 | if (loop < LOOP_CACHING_WAIT) { | ||
3904 | loop++; | ||
3905 | goto search; | ||
3906 | } | ||
3907 | } | ||
3908 | |||
3909 | if (loop == LOOP_ALLOC_CHUNK) { | ||
3694 | empty_size = 0; | 3910 | empty_size = 0; |
3695 | empty_cluster = 0; | 3911 | empty_cluster = 0; |
3696 | } | 3912 | } |
@@ -3703,7 +3919,7 @@ loop: | |||
3703 | space_info->force_alloc = 1; | 3919 | space_info->force_alloc = 1; |
3704 | } | 3920 | } |
3705 | 3921 | ||
3706 | if (loop < 3) { | 3922 | if (loop < LOOP_NO_EMPTY_SIZE) { |
3707 | loop++; | 3923 | loop++; |
3708 | goto search; | 3924 | goto search; |
3709 | } | 3925 | } |
@@ -3799,7 +4015,7 @@ again: | |||
3799 | num_bytes, data, 1); | 4015 | num_bytes, data, 1); |
3800 | goto again; | 4016 | goto again; |
3801 | } | 4017 | } |
3802 | if (ret) { | 4018 | if (ret == -ENOSPC) { |
3803 | struct btrfs_space_info *sinfo; | 4019 | struct btrfs_space_info *sinfo; |
3804 | 4020 | ||
3805 | sinfo = __find_space_info(root->fs_info, data); | 4021 | sinfo = __find_space_info(root->fs_info, data); |
@@ -3807,7 +4023,6 @@ again: | |||
3807 | "wanted %llu\n", (unsigned long long)data, | 4023 | "wanted %llu\n", (unsigned long long)data, |
3808 | (unsigned long long)num_bytes); | 4024 | (unsigned long long)num_bytes); |
3809 | dump_space_info(sinfo, num_bytes); | 4025 | dump_space_info(sinfo, num_bytes); |
3810 | BUG(); | ||
3811 | } | 4026 | } |
3812 | 4027 | ||
3813 | return ret; | 4028 | return ret; |
@@ -3845,7 +4060,9 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, | |||
3845 | ret = __btrfs_reserve_extent(trans, root, num_bytes, min_alloc_size, | 4060 | ret = __btrfs_reserve_extent(trans, root, num_bytes, min_alloc_size, |
3846 | empty_size, hint_byte, search_end, ins, | 4061 | empty_size, hint_byte, search_end, ins, |
3847 | data); | 4062 | data); |
3848 | update_reserved_extents(root, ins->objectid, ins->offset, 1); | 4063 | if (!ret) |
4064 | update_reserved_extents(root, ins->objectid, ins->offset, 1); | ||
4065 | |||
3849 | return ret; | 4066 | return ret; |
3850 | } | 4067 | } |
3851 | 4068 | ||
@@ -4007,9 +4224,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
4007 | struct btrfs_block_group_cache *block_group; | 4224 | struct btrfs_block_group_cache *block_group; |
4008 | 4225 | ||
4009 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); | 4226 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); |
4010 | mutex_lock(&block_group->cache_mutex); | 4227 | cache_block_group(block_group); |
4011 | cache_block_group(root, block_group); | 4228 | wait_event(block_group->caching_q, |
4012 | mutex_unlock(&block_group->cache_mutex); | 4229 | block_group_cache_done(block_group)); |
4013 | 4230 | ||
4014 | ret = btrfs_remove_free_space(block_group, ins->objectid, | 4231 | ret = btrfs_remove_free_space(block_group, ins->objectid, |
4015 | ins->offset); | 4232 | ins->offset); |
@@ -4040,7 +4257,8 @@ static int alloc_tree_block(struct btrfs_trans_handle *trans, | |||
4040 | ret = __btrfs_reserve_extent(trans, root, num_bytes, num_bytes, | 4257 | ret = __btrfs_reserve_extent(trans, root, num_bytes, num_bytes, |
4041 | empty_size, hint_byte, search_end, | 4258 | empty_size, hint_byte, search_end, |
4042 | ins, 0); | 4259 | ins, 0); |
4043 | BUG_ON(ret); | 4260 | if (ret) |
4261 | return ret; | ||
4044 | 4262 | ||
4045 | if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { | 4263 | if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { |
4046 | if (parent == 0) | 4264 | if (parent == 0) |
@@ -4128,6 +4346,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
4128 | return buf; | 4346 | return buf; |
4129 | } | 4347 | } |
4130 | 4348 | ||
4349 | #if 0 | ||
4131 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | 4350 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, |
4132 | struct btrfs_root *root, struct extent_buffer *leaf) | 4351 | struct btrfs_root *root, struct extent_buffer *leaf) |
4133 | { | 4352 | { |
@@ -4171,8 +4390,6 @@ int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | |||
4171 | return 0; | 4390 | return 0; |
4172 | } | 4391 | } |
4173 | 4392 | ||
4174 | #if 0 | ||
4175 | |||
4176 | static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans, | 4393 | static noinline int cache_drop_leaf_ref(struct btrfs_trans_handle *trans, |
4177 | struct btrfs_root *root, | 4394 | struct btrfs_root *root, |
4178 | struct btrfs_leaf_ref *ref) | 4395 | struct btrfs_leaf_ref *ref) |
@@ -4553,262 +4770,471 @@ out: | |||
4553 | } | 4770 | } |
4554 | #endif | 4771 | #endif |
4555 | 4772 | ||
4773 | struct walk_control { | ||
4774 | u64 refs[BTRFS_MAX_LEVEL]; | ||
4775 | u64 flags[BTRFS_MAX_LEVEL]; | ||
4776 | struct btrfs_key update_progress; | ||
4777 | int stage; | ||
4778 | int level; | ||
4779 | int shared_level; | ||
4780 | int update_ref; | ||
4781 | int keep_locks; | ||
4782 | }; | ||
4783 | |||
4784 | #define DROP_REFERENCE 1 | ||
4785 | #define UPDATE_BACKREF 2 | ||
4786 | |||
4556 | /* | 4787 | /* |
4557 | * helper function for drop_subtree, this function is similar to | 4788 | * hepler to process tree block while walking down the tree. |
4558 | * walk_down_tree. The main difference is that it checks reference | 4789 | * |
4559 | * counts while tree blocks are locked. | 4790 | * when wc->stage == DROP_REFERENCE, this function checks |
4791 | * reference count of the block. if the block is shared and | ||
4792 | * we need update back refs for the subtree rooted at the | ||
4793 | * block, this function changes wc->stage to UPDATE_BACKREF | ||
4794 | * | ||
4795 | * when wc->stage == UPDATE_BACKREF, this function updates | ||
4796 | * back refs for pointers in the block. | ||
4797 | * | ||
4798 | * NOTE: return value 1 means we should stop walking down. | ||
4560 | */ | 4799 | */ |
4561 | static noinline int walk_down_tree(struct btrfs_trans_handle *trans, | 4800 | static noinline int walk_down_proc(struct btrfs_trans_handle *trans, |
4562 | struct btrfs_root *root, | 4801 | struct btrfs_root *root, |
4563 | struct btrfs_path *path, int *level) | 4802 | struct btrfs_path *path, |
4803 | struct walk_control *wc) | ||
4564 | { | 4804 | { |
4565 | struct extent_buffer *next; | 4805 | int level = wc->level; |
4566 | struct extent_buffer *cur; | 4806 | struct extent_buffer *eb = path->nodes[level]; |
4567 | struct extent_buffer *parent; | 4807 | struct btrfs_key key; |
4568 | u64 bytenr; | 4808 | u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF; |
4569 | u64 ptr_gen; | ||
4570 | u64 refs; | ||
4571 | u64 flags; | ||
4572 | u32 blocksize; | ||
4573 | int ret; | 4809 | int ret; |
4574 | 4810 | ||
4575 | cur = path->nodes[*level]; | 4811 | if (wc->stage == UPDATE_BACKREF && |
4576 | ret = btrfs_lookup_extent_info(trans, root, cur->start, cur->len, | 4812 | btrfs_header_owner(eb) != root->root_key.objectid) |
4577 | &refs, &flags); | 4813 | return 1; |
4578 | BUG_ON(ret); | ||
4579 | if (refs > 1) | ||
4580 | goto out; | ||
4581 | 4814 | ||
4582 | BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); | 4815 | /* |
4816 | * when reference count of tree block is 1, it won't increase | ||
4817 | * again. once full backref flag is set, we never clear it. | ||
4818 | */ | ||
4819 | if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) || | ||
4820 | (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) { | ||
4821 | BUG_ON(!path->locks[level]); | ||
4822 | ret = btrfs_lookup_extent_info(trans, root, | ||
4823 | eb->start, eb->len, | ||
4824 | &wc->refs[level], | ||
4825 | &wc->flags[level]); | ||
4826 | BUG_ON(ret); | ||
4827 | BUG_ON(wc->refs[level] == 0); | ||
4828 | } | ||
4583 | 4829 | ||
4584 | while (*level >= 0) { | 4830 | if (wc->stage == DROP_REFERENCE && |
4585 | cur = path->nodes[*level]; | 4831 | wc->update_ref && wc->refs[level] > 1) { |
4586 | if (*level == 0) { | 4832 | BUG_ON(eb == root->node); |
4587 | ret = btrfs_drop_leaf_ref(trans, root, cur); | 4833 | BUG_ON(path->slots[level] > 0); |
4588 | BUG_ON(ret); | 4834 | if (level == 0) |
4589 | clean_tree_block(trans, root, cur); | 4835 | btrfs_item_key_to_cpu(eb, &key, path->slots[level]); |
4590 | break; | 4836 | else |
4591 | } | 4837 | btrfs_node_key_to_cpu(eb, &key, path->slots[level]); |
4592 | if (path->slots[*level] >= btrfs_header_nritems(cur)) { | 4838 | if (btrfs_header_owner(eb) == root->root_key.objectid && |
4593 | clean_tree_block(trans, root, cur); | 4839 | btrfs_comp_cpu_keys(&key, &wc->update_progress) >= 0) { |
4594 | break; | 4840 | wc->stage = UPDATE_BACKREF; |
4841 | wc->shared_level = level; | ||
4595 | } | 4842 | } |
4843 | } | ||
4596 | 4844 | ||
4597 | bytenr = btrfs_node_blockptr(cur, path->slots[*level]); | 4845 | if (wc->stage == DROP_REFERENCE) { |
4598 | blocksize = btrfs_level_size(root, *level - 1); | 4846 | if (wc->refs[level] > 1) |
4599 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); | 4847 | return 1; |
4600 | 4848 | ||
4601 | next = read_tree_block(root, bytenr, blocksize, ptr_gen); | 4849 | if (path->locks[level] && !wc->keep_locks) { |
4602 | btrfs_tree_lock(next); | 4850 | btrfs_tree_unlock(eb); |
4603 | btrfs_set_lock_blocking(next); | 4851 | path->locks[level] = 0; |
4852 | } | ||
4853 | return 0; | ||
4854 | } | ||
4604 | 4855 | ||
4605 | ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize, | 4856 | /* wc->stage == UPDATE_BACKREF */ |
4606 | &refs, &flags); | 4857 | if (!(wc->flags[level] & flag)) { |
4858 | BUG_ON(!path->locks[level]); | ||
4859 | ret = btrfs_inc_ref(trans, root, eb, 1); | ||
4607 | BUG_ON(ret); | 4860 | BUG_ON(ret); |
4608 | if (refs > 1) { | 4861 | ret = btrfs_dec_ref(trans, root, eb, 0); |
4609 | parent = path->nodes[*level]; | 4862 | BUG_ON(ret); |
4610 | ret = btrfs_free_extent(trans, root, bytenr, | 4863 | ret = btrfs_set_disk_extent_flags(trans, root, eb->start, |
4611 | blocksize, parent->start, | 4864 | eb->len, flag, 0); |
4612 | btrfs_header_owner(parent), | 4865 | BUG_ON(ret); |
4613 | *level - 1, 0); | 4866 | wc->flags[level] |= flag; |
4867 | } | ||
4868 | |||
4869 | /* | ||
4870 | * the block is shared by multiple trees, so it's not good to | ||
4871 | * keep the tree lock | ||
4872 | */ | ||
4873 | if (path->locks[level] && level > 0) { | ||
4874 | btrfs_tree_unlock(eb); | ||
4875 | path->locks[level] = 0; | ||
4876 | } | ||
4877 | return 0; | ||
4878 | } | ||
4879 | |||
4880 | /* | ||
4881 | * hepler to process tree block while walking up the tree. | ||
4882 | * | ||
4883 | * when wc->stage == DROP_REFERENCE, this function drops | ||
4884 | * reference count on the block. | ||
4885 | * | ||
4886 | * when wc->stage == UPDATE_BACKREF, this function changes | ||
4887 | * wc->stage back to DROP_REFERENCE if we changed wc->stage | ||
4888 | * to UPDATE_BACKREF previously while processing the block. | ||
4889 | * | ||
4890 | * NOTE: return value 1 means we should stop walking up. | ||
4891 | */ | ||
4892 | static noinline int walk_up_proc(struct btrfs_trans_handle *trans, | ||
4893 | struct btrfs_root *root, | ||
4894 | struct btrfs_path *path, | ||
4895 | struct walk_control *wc) | ||
4896 | { | ||
4897 | int ret = 0; | ||
4898 | int level = wc->level; | ||
4899 | struct extent_buffer *eb = path->nodes[level]; | ||
4900 | u64 parent = 0; | ||
4901 | |||
4902 | if (wc->stage == UPDATE_BACKREF) { | ||
4903 | BUG_ON(wc->shared_level < level); | ||
4904 | if (level < wc->shared_level) | ||
4905 | goto out; | ||
4906 | |||
4907 | BUG_ON(wc->refs[level] <= 1); | ||
4908 | ret = find_next_key(path, level + 1, &wc->update_progress); | ||
4909 | if (ret > 0) | ||
4910 | wc->update_ref = 0; | ||
4911 | |||
4912 | wc->stage = DROP_REFERENCE; | ||
4913 | wc->shared_level = -1; | ||
4914 | path->slots[level] = 0; | ||
4915 | |||
4916 | /* | ||
4917 | * check reference count again if the block isn't locked. | ||
4918 | * we should start walking down the tree again if reference | ||
4919 | * count is one. | ||
4920 | */ | ||
4921 | if (!path->locks[level]) { | ||
4922 | BUG_ON(level == 0); | ||
4923 | btrfs_tree_lock(eb); | ||
4924 | btrfs_set_lock_blocking(eb); | ||
4925 | path->locks[level] = 1; | ||
4926 | |||
4927 | ret = btrfs_lookup_extent_info(trans, root, | ||
4928 | eb->start, eb->len, | ||
4929 | &wc->refs[level], | ||
4930 | &wc->flags[level]); | ||
4614 | BUG_ON(ret); | 4931 | BUG_ON(ret); |
4615 | path->slots[*level]++; | 4932 | BUG_ON(wc->refs[level] == 0); |
4616 | btrfs_tree_unlock(next); | 4933 | if (wc->refs[level] == 1) { |
4617 | free_extent_buffer(next); | 4934 | btrfs_tree_unlock(eb); |
4618 | continue; | 4935 | path->locks[level] = 0; |
4936 | return 1; | ||
4937 | } | ||
4938 | } else { | ||
4939 | BUG_ON(level != 0); | ||
4619 | } | 4940 | } |
4941 | } | ||
4620 | 4942 | ||
4621 | BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); | 4943 | /* wc->stage == DROP_REFERENCE */ |
4944 | BUG_ON(wc->refs[level] > 1 && !path->locks[level]); | ||
4622 | 4945 | ||
4623 | *level = btrfs_header_level(next); | 4946 | if (wc->refs[level] == 1) { |
4624 | path->nodes[*level] = next; | 4947 | if (level == 0) { |
4625 | path->slots[*level] = 0; | 4948 | if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) |
4626 | path->locks[*level] = 1; | 4949 | ret = btrfs_dec_ref(trans, root, eb, 1); |
4627 | cond_resched(); | 4950 | else |
4951 | ret = btrfs_dec_ref(trans, root, eb, 0); | ||
4952 | BUG_ON(ret); | ||
4953 | } | ||
4954 | /* make block locked assertion in clean_tree_block happy */ | ||
4955 | if (!path->locks[level] && | ||
4956 | btrfs_header_generation(eb) == trans->transid) { | ||
4957 | btrfs_tree_lock(eb); | ||
4958 | btrfs_set_lock_blocking(eb); | ||
4959 | path->locks[level] = 1; | ||
4960 | } | ||
4961 | clean_tree_block(trans, root, eb); | ||
4628 | } | 4962 | } |
4629 | out: | ||
4630 | if (path->nodes[*level] == root->node) | ||
4631 | parent = path->nodes[*level]; | ||
4632 | else | ||
4633 | parent = path->nodes[*level + 1]; | ||
4634 | bytenr = path->nodes[*level]->start; | ||
4635 | blocksize = path->nodes[*level]->len; | ||
4636 | 4963 | ||
4637 | ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent->start, | 4964 | if (eb == root->node) { |
4638 | btrfs_header_owner(parent), *level, 0); | 4965 | if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) |
4966 | parent = eb->start; | ||
4967 | else | ||
4968 | BUG_ON(root->root_key.objectid != | ||
4969 | btrfs_header_owner(eb)); | ||
4970 | } else { | ||
4971 | if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF) | ||
4972 | parent = path->nodes[level + 1]->start; | ||
4973 | else | ||
4974 | BUG_ON(root->root_key.objectid != | ||
4975 | btrfs_header_owner(path->nodes[level + 1])); | ||
4976 | } | ||
4977 | |||
4978 | ret = btrfs_free_extent(trans, root, eb->start, eb->len, parent, | ||
4979 | root->root_key.objectid, level, 0); | ||
4639 | BUG_ON(ret); | 4980 | BUG_ON(ret); |
4981 | out: | ||
4982 | wc->refs[level] = 0; | ||
4983 | wc->flags[level] = 0; | ||
4984 | return ret; | ||
4985 | } | ||
4986 | |||
4987 | static noinline int walk_down_tree(struct btrfs_trans_handle *trans, | ||
4988 | struct btrfs_root *root, | ||
4989 | struct btrfs_path *path, | ||
4990 | struct walk_control *wc) | ||
4991 | { | ||
4992 | struct extent_buffer *next; | ||
4993 | struct extent_buffer *cur; | ||
4994 | u64 bytenr; | ||
4995 | u64 ptr_gen; | ||
4996 | u32 blocksize; | ||
4997 | int level = wc->level; | ||
4998 | int ret; | ||
4999 | |||
5000 | while (level >= 0) { | ||
5001 | cur = path->nodes[level]; | ||
5002 | BUG_ON(path->slots[level] >= btrfs_header_nritems(cur)); | ||
5003 | |||
5004 | ret = walk_down_proc(trans, root, path, wc); | ||
5005 | if (ret > 0) | ||
5006 | break; | ||
5007 | |||
5008 | if (level == 0) | ||
5009 | break; | ||
5010 | |||
5011 | bytenr = btrfs_node_blockptr(cur, path->slots[level]); | ||
5012 | blocksize = btrfs_level_size(root, level - 1); | ||
5013 | ptr_gen = btrfs_node_ptr_generation(cur, path->slots[level]); | ||
5014 | |||
5015 | next = read_tree_block(root, bytenr, blocksize, ptr_gen); | ||
5016 | btrfs_tree_lock(next); | ||
5017 | btrfs_set_lock_blocking(next); | ||
4640 | 5018 | ||
4641 | if (path->locks[*level]) { | 5019 | level--; |
4642 | btrfs_tree_unlock(path->nodes[*level]); | 5020 | BUG_ON(level != btrfs_header_level(next)); |
4643 | path->locks[*level] = 0; | 5021 | path->nodes[level] = next; |
5022 | path->slots[level] = 0; | ||
5023 | path->locks[level] = 1; | ||
5024 | wc->level = level; | ||
4644 | } | 5025 | } |
4645 | free_extent_buffer(path->nodes[*level]); | ||
4646 | path->nodes[*level] = NULL; | ||
4647 | *level += 1; | ||
4648 | cond_resched(); | ||
4649 | return 0; | 5026 | return 0; |
4650 | } | 5027 | } |
4651 | 5028 | ||
4652 | /* | ||
4653 | * helper for dropping snapshots. This walks back up the tree in the path | ||
4654 | * to find the first node higher up where we haven't yet gone through | ||
4655 | * all the slots | ||
4656 | */ | ||
4657 | static noinline int walk_up_tree(struct btrfs_trans_handle *trans, | 5029 | static noinline int walk_up_tree(struct btrfs_trans_handle *trans, |
4658 | struct btrfs_root *root, | 5030 | struct btrfs_root *root, |
4659 | struct btrfs_path *path, | 5031 | struct btrfs_path *path, |
4660 | int *level, int max_level) | 5032 | struct walk_control *wc, int max_level) |
4661 | { | 5033 | { |
4662 | struct btrfs_root_item *root_item = &root->root_item; | 5034 | int level = wc->level; |
4663 | int i; | ||
4664 | int slot; | ||
4665 | int ret; | 5035 | int ret; |
4666 | 5036 | ||
4667 | for (i = *level; i < max_level && path->nodes[i]; i++) { | 5037 | path->slots[level] = btrfs_header_nritems(path->nodes[level]); |
4668 | slot = path->slots[i]; | 5038 | while (level < max_level && path->nodes[level]) { |
4669 | if (slot + 1 < btrfs_header_nritems(path->nodes[i])) { | 5039 | wc->level = level; |
4670 | /* | 5040 | if (path->slots[level] + 1 < |
4671 | * there is more work to do in this level. | 5041 | btrfs_header_nritems(path->nodes[level])) { |
4672 | * Update the drop_progress marker to reflect | 5042 | path->slots[level]++; |
4673 | * the work we've done so far, and then bump | ||
4674 | * the slot number | ||
4675 | */ | ||
4676 | path->slots[i]++; | ||
4677 | WARN_ON(*level == 0); | ||
4678 | if (max_level == BTRFS_MAX_LEVEL) { | ||
4679 | btrfs_node_key(path->nodes[i], | ||
4680 | &root_item->drop_progress, | ||
4681 | path->slots[i]); | ||
4682 | root_item->drop_level = i; | ||
4683 | } | ||
4684 | *level = i; | ||
4685 | return 0; | 5043 | return 0; |
4686 | } else { | 5044 | } else { |
4687 | struct extent_buffer *parent; | 5045 | ret = walk_up_proc(trans, root, path, wc); |
4688 | 5046 | if (ret > 0) | |
4689 | /* | 5047 | return 0; |
4690 | * this whole node is done, free our reference | ||
4691 | * on it and go up one level | ||
4692 | */ | ||
4693 | if (path->nodes[*level] == root->node) | ||
4694 | parent = path->nodes[*level]; | ||
4695 | else | ||
4696 | parent = path->nodes[*level + 1]; | ||
4697 | 5048 | ||
4698 | clean_tree_block(trans, root, path->nodes[i]); | 5049 | if (path->locks[level]) { |
4699 | ret = btrfs_free_extent(trans, root, | 5050 | btrfs_tree_unlock(path->nodes[level]); |
4700 | path->nodes[i]->start, | 5051 | path->locks[level] = 0; |
4701 | path->nodes[i]->len, | ||
4702 | parent->start, | ||
4703 | btrfs_header_owner(parent), | ||
4704 | *level, 0); | ||
4705 | BUG_ON(ret); | ||
4706 | if (path->locks[*level]) { | ||
4707 | btrfs_tree_unlock(path->nodes[i]); | ||
4708 | path->locks[i] = 0; | ||
4709 | } | 5052 | } |
4710 | free_extent_buffer(path->nodes[i]); | 5053 | free_extent_buffer(path->nodes[level]); |
4711 | path->nodes[i] = NULL; | 5054 | path->nodes[level] = NULL; |
4712 | *level = i + 1; | 5055 | level++; |
4713 | } | 5056 | } |
4714 | } | 5057 | } |
4715 | return 1; | 5058 | return 1; |
4716 | } | 5059 | } |
4717 | 5060 | ||
4718 | /* | 5061 | /* |
4719 | * drop the reference count on the tree rooted at 'snap'. This traverses | 5062 | * drop a subvolume tree. |
4720 | * the tree freeing any blocks that have a ref count of zero after being | 5063 | * |
4721 | * decremented. | 5064 | * this function traverses the tree freeing any blocks that only |
5065 | * referenced by the tree. | ||
5066 | * | ||
5067 | * when a shared tree block is found. this function decreases its | ||
5068 | * reference count by one. if update_ref is true, this function | ||
5069 | * also make sure backrefs for the shared block and all lower level | ||
5070 | * blocks are properly updated. | ||
4722 | */ | 5071 | */ |
4723 | int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | 5072 | int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref) |
4724 | *root) | ||
4725 | { | 5073 | { |
4726 | int ret = 0; | ||
4727 | int wret; | ||
4728 | int level; | ||
4729 | struct btrfs_path *path; | 5074 | struct btrfs_path *path; |
4730 | int update_count; | 5075 | struct btrfs_trans_handle *trans; |
5076 | struct btrfs_root *tree_root = root->fs_info->tree_root; | ||
4731 | struct btrfs_root_item *root_item = &root->root_item; | 5077 | struct btrfs_root_item *root_item = &root->root_item; |
5078 | struct walk_control *wc; | ||
5079 | struct btrfs_key key; | ||
5080 | int err = 0; | ||
5081 | int ret; | ||
5082 | int level; | ||
4732 | 5083 | ||
4733 | path = btrfs_alloc_path(); | 5084 | path = btrfs_alloc_path(); |
4734 | BUG_ON(!path); | 5085 | BUG_ON(!path); |
4735 | 5086 | ||
4736 | level = btrfs_header_level(root->node); | 5087 | wc = kzalloc(sizeof(*wc), GFP_NOFS); |
5088 | BUG_ON(!wc); | ||
5089 | |||
5090 | trans = btrfs_start_transaction(tree_root, 1); | ||
5091 | |||
4737 | if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { | 5092 | if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { |
5093 | level = btrfs_header_level(root->node); | ||
4738 | path->nodes[level] = btrfs_lock_root_node(root); | 5094 | path->nodes[level] = btrfs_lock_root_node(root); |
4739 | btrfs_set_lock_blocking(path->nodes[level]); | 5095 | btrfs_set_lock_blocking(path->nodes[level]); |
4740 | path->slots[level] = 0; | 5096 | path->slots[level] = 0; |
4741 | path->locks[level] = 1; | 5097 | path->locks[level] = 1; |
5098 | memset(&wc->update_progress, 0, | ||
5099 | sizeof(wc->update_progress)); | ||
4742 | } else { | 5100 | } else { |
4743 | struct btrfs_key key; | ||
4744 | struct btrfs_disk_key found_key; | ||
4745 | struct extent_buffer *node; | ||
4746 | |||
4747 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); | 5101 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); |
5102 | memcpy(&wc->update_progress, &key, | ||
5103 | sizeof(wc->update_progress)); | ||
5104 | |||
4748 | level = root_item->drop_level; | 5105 | level = root_item->drop_level; |
5106 | BUG_ON(level == 0); | ||
4749 | path->lowest_level = level; | 5107 | path->lowest_level = level; |
4750 | wret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 5108 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
4751 | if (wret < 0) { | 5109 | path->lowest_level = 0; |
4752 | ret = wret; | 5110 | if (ret < 0) { |
5111 | err = ret; | ||
4753 | goto out; | 5112 | goto out; |
4754 | } | 5113 | } |
4755 | node = path->nodes[level]; | 5114 | btrfs_node_key_to_cpu(path->nodes[level], &key, |
4756 | btrfs_node_key(node, &found_key, path->slots[level]); | 5115 | path->slots[level]); |
4757 | WARN_ON(memcmp(&found_key, &root_item->drop_progress, | 5116 | WARN_ON(memcmp(&key, &wc->update_progress, sizeof(key))); |
4758 | sizeof(found_key))); | 5117 | |
4759 | /* | 5118 | /* |
4760 | * unlock our path, this is safe because only this | 5119 | * unlock our path, this is safe because only this |
4761 | * function is allowed to delete this snapshot | 5120 | * function is allowed to delete this snapshot |
4762 | */ | 5121 | */ |
4763 | btrfs_unlock_up_safe(path, 0); | 5122 | btrfs_unlock_up_safe(path, 0); |
5123 | |||
5124 | level = btrfs_header_level(root->node); | ||
5125 | while (1) { | ||
5126 | btrfs_tree_lock(path->nodes[level]); | ||
5127 | btrfs_set_lock_blocking(path->nodes[level]); | ||
5128 | |||
5129 | ret = btrfs_lookup_extent_info(trans, root, | ||
5130 | path->nodes[level]->start, | ||
5131 | path->nodes[level]->len, | ||
5132 | &wc->refs[level], | ||
5133 | &wc->flags[level]); | ||
5134 | BUG_ON(ret); | ||
5135 | BUG_ON(wc->refs[level] == 0); | ||
5136 | |||
5137 | if (level == root_item->drop_level) | ||
5138 | break; | ||
5139 | |||
5140 | btrfs_tree_unlock(path->nodes[level]); | ||
5141 | WARN_ON(wc->refs[level] != 1); | ||
5142 | level--; | ||
5143 | } | ||
4764 | } | 5144 | } |
5145 | |||
5146 | wc->level = level; | ||
5147 | wc->shared_level = -1; | ||
5148 | wc->stage = DROP_REFERENCE; | ||
5149 | wc->update_ref = update_ref; | ||
5150 | wc->keep_locks = 0; | ||
5151 | |||
4765 | while (1) { | 5152 | while (1) { |
4766 | unsigned long update; | 5153 | ret = walk_down_tree(trans, root, path, wc); |
4767 | wret = walk_down_tree(trans, root, path, &level); | 5154 | if (ret < 0) { |
4768 | if (wret > 0) | 5155 | err = ret; |
4769 | break; | 5156 | break; |
4770 | if (wret < 0) | 5157 | } |
4771 | ret = wret; | ||
4772 | 5158 | ||
4773 | wret = walk_up_tree(trans, root, path, &level, | 5159 | ret = walk_up_tree(trans, root, path, wc, BTRFS_MAX_LEVEL); |
4774 | BTRFS_MAX_LEVEL); | 5160 | if (ret < 0) { |
4775 | if (wret > 0) | 5161 | err = ret; |
4776 | break; | 5162 | break; |
4777 | if (wret < 0) | 5163 | } |
4778 | ret = wret; | 5164 | |
4779 | if (trans->transaction->in_commit || | 5165 | if (ret > 0) { |
4780 | trans->transaction->delayed_refs.flushing) { | 5166 | BUG_ON(wc->stage != DROP_REFERENCE); |
4781 | ret = -EAGAIN; | ||
4782 | break; | 5167 | break; |
4783 | } | 5168 | } |
4784 | for (update_count = 0; update_count < 16; update_count++) { | 5169 | |
5170 | if (wc->stage == DROP_REFERENCE) { | ||
5171 | level = wc->level; | ||
5172 | btrfs_node_key(path->nodes[level], | ||
5173 | &root_item->drop_progress, | ||
5174 | path->slots[level]); | ||
5175 | root_item->drop_level = level; | ||
5176 | } | ||
5177 | |||
5178 | BUG_ON(wc->level == 0); | ||
5179 | if (trans->transaction->in_commit || | ||
5180 | trans->transaction->delayed_refs.flushing) { | ||
5181 | ret = btrfs_update_root(trans, tree_root, | ||
5182 | &root->root_key, | ||
5183 | root_item); | ||
5184 | BUG_ON(ret); | ||
5185 | |||
5186 | btrfs_end_transaction(trans, tree_root); | ||
5187 | trans = btrfs_start_transaction(tree_root, 1); | ||
5188 | } else { | ||
5189 | unsigned long update; | ||
4785 | update = trans->delayed_ref_updates; | 5190 | update = trans->delayed_ref_updates; |
4786 | trans->delayed_ref_updates = 0; | 5191 | trans->delayed_ref_updates = 0; |
4787 | if (update) | 5192 | if (update) |
4788 | btrfs_run_delayed_refs(trans, root, update); | 5193 | btrfs_run_delayed_refs(trans, tree_root, |
4789 | else | 5194 | update); |
4790 | break; | ||
4791 | } | 5195 | } |
4792 | } | 5196 | } |
5197 | btrfs_release_path(root, path); | ||
5198 | BUG_ON(err); | ||
5199 | |||
5200 | ret = btrfs_del_root(trans, tree_root, &root->root_key); | ||
5201 | BUG_ON(ret); | ||
5202 | |||
5203 | free_extent_buffer(root->node); | ||
5204 | free_extent_buffer(root->commit_root); | ||
5205 | kfree(root); | ||
4793 | out: | 5206 | out: |
5207 | btrfs_end_transaction(trans, tree_root); | ||
5208 | kfree(wc); | ||
4794 | btrfs_free_path(path); | 5209 | btrfs_free_path(path); |
4795 | return ret; | 5210 | return err; |
4796 | } | 5211 | } |
4797 | 5212 | ||
5213 | /* | ||
5214 | * drop subtree rooted at tree block 'node'. | ||
5215 | * | ||
5216 | * NOTE: this function will unlock and release tree block 'node' | ||
5217 | */ | ||
4798 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | 5218 | int btrfs_drop_subtree(struct btrfs_trans_handle *trans, |
4799 | struct btrfs_root *root, | 5219 | struct btrfs_root *root, |
4800 | struct extent_buffer *node, | 5220 | struct extent_buffer *node, |
4801 | struct extent_buffer *parent) | 5221 | struct extent_buffer *parent) |
4802 | { | 5222 | { |
4803 | struct btrfs_path *path; | 5223 | struct btrfs_path *path; |
5224 | struct walk_control *wc; | ||
4804 | int level; | 5225 | int level; |
4805 | int parent_level; | 5226 | int parent_level; |
4806 | int ret = 0; | 5227 | int ret = 0; |
4807 | int wret; | 5228 | int wret; |
4808 | 5229 | ||
5230 | BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); | ||
5231 | |||
4809 | path = btrfs_alloc_path(); | 5232 | path = btrfs_alloc_path(); |
4810 | BUG_ON(!path); | 5233 | BUG_ON(!path); |
4811 | 5234 | ||
5235 | wc = kzalloc(sizeof(*wc), GFP_NOFS); | ||
5236 | BUG_ON(!wc); | ||
5237 | |||
4812 | btrfs_assert_tree_locked(parent); | 5238 | btrfs_assert_tree_locked(parent); |
4813 | parent_level = btrfs_header_level(parent); | 5239 | parent_level = btrfs_header_level(parent); |
4814 | extent_buffer_get(parent); | 5240 | extent_buffer_get(parent); |
@@ -4817,24 +5243,33 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans, | |||
4817 | 5243 | ||
4818 | btrfs_assert_tree_locked(node); | 5244 | btrfs_assert_tree_locked(node); |
4819 | level = btrfs_header_level(node); | 5245 | level = btrfs_header_level(node); |
4820 | extent_buffer_get(node); | ||
4821 | path->nodes[level] = node; | 5246 | path->nodes[level] = node; |
4822 | path->slots[level] = 0; | 5247 | path->slots[level] = 0; |
5248 | path->locks[level] = 1; | ||
5249 | |||
5250 | wc->refs[parent_level] = 1; | ||
5251 | wc->flags[parent_level] = BTRFS_BLOCK_FLAG_FULL_BACKREF; | ||
5252 | wc->level = level; | ||
5253 | wc->shared_level = -1; | ||
5254 | wc->stage = DROP_REFERENCE; | ||
5255 | wc->update_ref = 0; | ||
5256 | wc->keep_locks = 1; | ||
4823 | 5257 | ||
4824 | while (1) { | 5258 | while (1) { |
4825 | wret = walk_down_tree(trans, root, path, &level); | 5259 | wret = walk_down_tree(trans, root, path, wc); |
4826 | if (wret < 0) | 5260 | if (wret < 0) { |
4827 | ret = wret; | 5261 | ret = wret; |
4828 | if (wret != 0) | ||
4829 | break; | 5262 | break; |
5263 | } | ||
4830 | 5264 | ||
4831 | wret = walk_up_tree(trans, root, path, &level, parent_level); | 5265 | wret = walk_up_tree(trans, root, path, wc, parent_level); |
4832 | if (wret < 0) | 5266 | if (wret < 0) |
4833 | ret = wret; | 5267 | ret = wret; |
4834 | if (wret != 0) | 5268 | if (wret != 0) |
4835 | break; | 5269 | break; |
4836 | } | 5270 | } |
4837 | 5271 | ||
5272 | kfree(wc); | ||
4838 | btrfs_free_path(path); | 5273 | btrfs_free_path(path); |
4839 | return ret; | 5274 | return ret; |
4840 | } | 5275 | } |
@@ -6739,11 +7174,16 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
6739 | &info->block_group_cache_tree); | 7174 | &info->block_group_cache_tree); |
6740 | spin_unlock(&info->block_group_cache_lock); | 7175 | spin_unlock(&info->block_group_cache_lock); |
6741 | 7176 | ||
6742 | btrfs_remove_free_space_cache(block_group); | ||
6743 | down_write(&block_group->space_info->groups_sem); | 7177 | down_write(&block_group->space_info->groups_sem); |
6744 | list_del(&block_group->list); | 7178 | list_del(&block_group->list); |
6745 | up_write(&block_group->space_info->groups_sem); | 7179 | up_write(&block_group->space_info->groups_sem); |
6746 | 7180 | ||
7181 | if (block_group->cached == BTRFS_CACHE_STARTED) | ||
7182 | wait_event(block_group->caching_q, | ||
7183 | block_group_cache_done(block_group)); | ||
7184 | |||
7185 | btrfs_remove_free_space_cache(block_group); | ||
7186 | |||
6747 | WARN_ON(atomic_read(&block_group->count) != 1); | 7187 | WARN_ON(atomic_read(&block_group->count) != 1); |
6748 | kfree(block_group); | 7188 | kfree(block_group); |
6749 | 7189 | ||
@@ -6809,9 +7249,19 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
6809 | atomic_set(&cache->count, 1); | 7249 | atomic_set(&cache->count, 1); |
6810 | spin_lock_init(&cache->lock); | 7250 | spin_lock_init(&cache->lock); |
6811 | spin_lock_init(&cache->tree_lock); | 7251 | spin_lock_init(&cache->tree_lock); |
6812 | mutex_init(&cache->cache_mutex); | 7252 | cache->fs_info = info; |
7253 | init_waitqueue_head(&cache->caching_q); | ||
6813 | INIT_LIST_HEAD(&cache->list); | 7254 | INIT_LIST_HEAD(&cache->list); |
6814 | INIT_LIST_HEAD(&cache->cluster_list); | 7255 | INIT_LIST_HEAD(&cache->cluster_list); |
7256 | |||
7257 | /* | ||
7258 | * we only want to have 32k of ram per block group for keeping | ||
7259 | * track of free space, and if we pass 1/2 of that we want to | ||
7260 | * start converting things over to using bitmaps | ||
7261 | */ | ||
7262 | cache->extents_thresh = ((1024 * 32) / 2) / | ||
7263 | sizeof(struct btrfs_free_space); | ||
7264 | |||
6815 | read_extent_buffer(leaf, &cache->item, | 7265 | read_extent_buffer(leaf, &cache->item, |
6816 | btrfs_item_ptr_offset(leaf, path->slots[0]), | 7266 | btrfs_item_ptr_offset(leaf, path->slots[0]), |
6817 | sizeof(cache->item)); | 7267 | sizeof(cache->item)); |
@@ -6820,6 +7270,26 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
6820 | key.objectid = found_key.objectid + found_key.offset; | 7270 | key.objectid = found_key.objectid + found_key.offset; |
6821 | btrfs_release_path(root, path); | 7271 | btrfs_release_path(root, path); |
6822 | cache->flags = btrfs_block_group_flags(&cache->item); | 7272 | cache->flags = btrfs_block_group_flags(&cache->item); |
7273 | cache->sectorsize = root->sectorsize; | ||
7274 | |||
7275 | remove_sb_from_cache(root, cache); | ||
7276 | |||
7277 | /* | ||
7278 | * check for two cases, either we are full, and therefore | ||
7279 | * don't need to bother with the caching work since we won't | ||
7280 | * find any space, or we are empty, and we can just add all | ||
7281 | * the space in and be done with it. This saves us _alot_ of | ||
7282 | * time, particularly in the full case. | ||
7283 | */ | ||
7284 | if (found_key.offset == btrfs_block_group_used(&cache->item)) { | ||
7285 | cache->cached = BTRFS_CACHE_FINISHED; | ||
7286 | } else if (btrfs_block_group_used(&cache->item) == 0) { | ||
7287 | cache->cached = BTRFS_CACHE_FINISHED; | ||
7288 | add_new_free_space(cache, root->fs_info, | ||
7289 | found_key.objectid, | ||
7290 | found_key.objectid + | ||
7291 | found_key.offset); | ||
7292 | } | ||
6823 | 7293 | ||
6824 | ret = update_space_info(info, cache->flags, found_key.offset, | 7294 | ret = update_space_info(info, cache->flags, found_key.offset, |
6825 | btrfs_block_group_used(&cache->item), | 7295 | btrfs_block_group_used(&cache->item), |
@@ -6863,10 +7333,19 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
6863 | cache->key.objectid = chunk_offset; | 7333 | cache->key.objectid = chunk_offset; |
6864 | cache->key.offset = size; | 7334 | cache->key.offset = size; |
6865 | cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; | 7335 | cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; |
7336 | cache->sectorsize = root->sectorsize; | ||
7337 | |||
7338 | /* | ||
7339 | * we only want to have 32k of ram per block group for keeping track | ||
7340 | * of free space, and if we pass 1/2 of that we want to start | ||
7341 | * converting things over to using bitmaps | ||
7342 | */ | ||
7343 | cache->extents_thresh = ((1024 * 32) / 2) / | ||
7344 | sizeof(struct btrfs_free_space); | ||
6866 | atomic_set(&cache->count, 1); | 7345 | atomic_set(&cache->count, 1); |
6867 | spin_lock_init(&cache->lock); | 7346 | spin_lock_init(&cache->lock); |
6868 | spin_lock_init(&cache->tree_lock); | 7347 | spin_lock_init(&cache->tree_lock); |
6869 | mutex_init(&cache->cache_mutex); | 7348 | init_waitqueue_head(&cache->caching_q); |
6870 | INIT_LIST_HEAD(&cache->list); | 7349 | INIT_LIST_HEAD(&cache->list); |
6871 | INIT_LIST_HEAD(&cache->cluster_list); | 7350 | INIT_LIST_HEAD(&cache->cluster_list); |
6872 | 7351 | ||
@@ -6875,6 +7354,12 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
6875 | cache->flags = type; | 7354 | cache->flags = type; |
6876 | btrfs_set_block_group_flags(&cache->item, type); | 7355 | btrfs_set_block_group_flags(&cache->item, type); |
6877 | 7356 | ||
7357 | cache->cached = BTRFS_CACHE_FINISHED; | ||
7358 | remove_sb_from_cache(root, cache); | ||
7359 | |||
7360 | add_new_free_space(cache, root->fs_info, chunk_offset, | ||
7361 | chunk_offset + size); | ||
7362 | |||
6878 | ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, | 7363 | ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, |
6879 | &cache->space_info); | 7364 | &cache->space_info); |
6880 | BUG_ON(ret); | 7365 | BUG_ON(ret); |
@@ -6933,7 +7418,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
6933 | rb_erase(&block_group->cache_node, | 7418 | rb_erase(&block_group->cache_node, |
6934 | &root->fs_info->block_group_cache_tree); | 7419 | &root->fs_info->block_group_cache_tree); |
6935 | spin_unlock(&root->fs_info->block_group_cache_lock); | 7420 | spin_unlock(&root->fs_info->block_group_cache_lock); |
6936 | btrfs_remove_free_space_cache(block_group); | 7421 | |
6937 | down_write(&block_group->space_info->groups_sem); | 7422 | down_write(&block_group->space_info->groups_sem); |
6938 | /* | 7423 | /* |
6939 | * we must use list_del_init so people can check to see if they | 7424 | * we must use list_del_init so people can check to see if they |
@@ -6942,11 +7427,18 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, | |||
6942 | list_del_init(&block_group->list); | 7427 | list_del_init(&block_group->list); |
6943 | up_write(&block_group->space_info->groups_sem); | 7428 | up_write(&block_group->space_info->groups_sem); |
6944 | 7429 | ||
7430 | if (block_group->cached == BTRFS_CACHE_STARTED) | ||
7431 | wait_event(block_group->caching_q, | ||
7432 | block_group_cache_done(block_group)); | ||
7433 | |||
7434 | btrfs_remove_free_space_cache(block_group); | ||
7435 | |||
6945 | spin_lock(&block_group->space_info->lock); | 7436 | spin_lock(&block_group->space_info->lock); |
6946 | block_group->space_info->total_bytes -= block_group->key.offset; | 7437 | block_group->space_info->total_bytes -= block_group->key.offset; |
6947 | block_group->space_info->bytes_readonly -= block_group->key.offset; | 7438 | block_group->space_info->bytes_readonly -= block_group->key.offset; |
6948 | spin_unlock(&block_group->space_info->lock); | 7439 | spin_unlock(&block_group->space_info->lock); |
6949 | block_group->space_info->full = 0; | 7440 | |
7441 | btrfs_clear_space_info_full(root->fs_info); | ||
6950 | 7442 | ||
6951 | btrfs_put_block_group(block_group); | 7443 | btrfs_put_block_group(block_group); |
6952 | btrfs_put_block_group(block_group); | 7444 | btrfs_put_block_group(block_group); |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 126477eaecf5..4b833972273a 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/string.h> | 24 | #include <linux/string.h> |
25 | #include <linux/smp_lock.h> | ||
26 | #include <linux/backing-dev.h> | 25 | #include <linux/backing-dev.h> |
27 | #include <linux/mpage.h> | 26 | #include <linux/mpage.h> |
28 | #include <linux/swap.h> | 27 | #include <linux/swap.h> |
@@ -151,7 +150,10 @@ static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
151 | } | 150 | } |
152 | if (end_pos > isize) { | 151 | if (end_pos > isize) { |
153 | i_size_write(inode, end_pos); | 152 | i_size_write(inode, end_pos); |
154 | btrfs_update_inode(trans, root, inode); | 153 | /* we've only changed i_size in ram, and we haven't updated |
154 | * the disk i_size. There is no need to log the inode | ||
155 | * at this time. | ||
156 | */ | ||
155 | } | 157 | } |
156 | err = btrfs_end_transaction(trans, root); | 158 | err = btrfs_end_transaction(trans, root); |
157 | out_unlock: | 159 | out_unlock: |
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 4538e48581a5..5edcee3a617f 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -16,45 +16,46 @@ | |||
16 | * Boston, MA 021110-1307, USA. | 16 | * Boston, MA 021110-1307, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/pagemap.h> | ||
19 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/math64.h> | ||
20 | #include "ctree.h" | 22 | #include "ctree.h" |
21 | #include "free-space-cache.h" | 23 | #include "free-space-cache.h" |
22 | #include "transaction.h" | 24 | #include "transaction.h" |
23 | 25 | ||
24 | struct btrfs_free_space { | 26 | #define BITS_PER_BITMAP (PAGE_CACHE_SIZE * 8) |
25 | struct rb_node bytes_index; | 27 | #define MAX_CACHE_BYTES_PER_GIG (32 * 1024) |
26 | struct rb_node offset_index; | ||
27 | u64 offset; | ||
28 | u64 bytes; | ||
29 | }; | ||
30 | 28 | ||
31 | static int tree_insert_offset(struct rb_root *root, u64 offset, | 29 | static inline unsigned long offset_to_bit(u64 bitmap_start, u64 sectorsize, |
32 | struct rb_node *node) | 30 | u64 offset) |
33 | { | 31 | { |
34 | struct rb_node **p = &root->rb_node; | 32 | BUG_ON(offset < bitmap_start); |
35 | struct rb_node *parent = NULL; | 33 | offset -= bitmap_start; |
36 | struct btrfs_free_space *info; | 34 | return (unsigned long)(div64_u64(offset, sectorsize)); |
35 | } | ||
37 | 36 | ||
38 | while (*p) { | 37 | static inline unsigned long bytes_to_bits(u64 bytes, u64 sectorsize) |
39 | parent = *p; | 38 | { |
40 | info = rb_entry(parent, struct btrfs_free_space, offset_index); | 39 | return (unsigned long)(div64_u64(bytes, sectorsize)); |
40 | } | ||
41 | 41 | ||
42 | if (offset < info->offset) | 42 | static inline u64 offset_to_bitmap(struct btrfs_block_group_cache *block_group, |
43 | p = &(*p)->rb_left; | 43 | u64 offset) |
44 | else if (offset > info->offset) | 44 | { |
45 | p = &(*p)->rb_right; | 45 | u64 bitmap_start; |
46 | else | 46 | u64 bytes_per_bitmap; |
47 | return -EEXIST; | ||
48 | } | ||
49 | 47 | ||
50 | rb_link_node(node, parent, p); | 48 | bytes_per_bitmap = BITS_PER_BITMAP * block_group->sectorsize; |
51 | rb_insert_color(node, root); | 49 | bitmap_start = offset - block_group->key.objectid; |
50 | bitmap_start = div64_u64(bitmap_start, bytes_per_bitmap); | ||
51 | bitmap_start *= bytes_per_bitmap; | ||
52 | bitmap_start += block_group->key.objectid; | ||
52 | 53 | ||
53 | return 0; | 54 | return bitmap_start; |
54 | } | 55 | } |
55 | 56 | ||
56 | static int tree_insert_bytes(struct rb_root *root, u64 bytes, | 57 | static int tree_insert_offset(struct rb_root *root, u64 offset, |
57 | struct rb_node *node) | 58 | struct rb_node *node, int bitmap) |
58 | { | 59 | { |
59 | struct rb_node **p = &root->rb_node; | 60 | struct rb_node **p = &root->rb_node; |
60 | struct rb_node *parent = NULL; | 61 | struct rb_node *parent = NULL; |
@@ -62,12 +63,34 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes, | |||
62 | 63 | ||
63 | while (*p) { | 64 | while (*p) { |
64 | parent = *p; | 65 | parent = *p; |
65 | info = rb_entry(parent, struct btrfs_free_space, bytes_index); | 66 | info = rb_entry(parent, struct btrfs_free_space, offset_index); |
66 | 67 | ||
67 | if (bytes < info->bytes) | 68 | if (offset < info->offset) { |
68 | p = &(*p)->rb_left; | 69 | p = &(*p)->rb_left; |
69 | else | 70 | } else if (offset > info->offset) { |
70 | p = &(*p)->rb_right; | 71 | p = &(*p)->rb_right; |
72 | } else { | ||
73 | /* | ||
74 | * we could have a bitmap entry and an extent entry | ||
75 | * share the same offset. If this is the case, we want | ||
76 | * the extent entry to always be found first if we do a | ||
77 | * linear search through the tree, since we want to have | ||
78 | * the quickest allocation time, and allocating from an | ||
79 | * extent is faster than allocating from a bitmap. So | ||
80 | * if we're inserting a bitmap and we find an entry at | ||
81 | * this offset, we want to go right, or after this entry | ||
82 | * logically. If we are inserting an extent and we've | ||
83 | * found a bitmap, we want to go left, or before | ||
84 | * logically. | ||
85 | */ | ||
86 | if (bitmap) { | ||
87 | WARN_ON(info->bitmap); | ||
88 | p = &(*p)->rb_right; | ||
89 | } else { | ||
90 | WARN_ON(!info->bitmap); | ||
91 | p = &(*p)->rb_left; | ||
92 | } | ||
93 | } | ||
71 | } | 94 | } |
72 | 95 | ||
73 | rb_link_node(node, parent, p); | 96 | rb_link_node(node, parent, p); |
@@ -79,110 +102,143 @@ static int tree_insert_bytes(struct rb_root *root, u64 bytes, | |||
79 | /* | 102 | /* |
80 | * searches the tree for the given offset. | 103 | * searches the tree for the given offset. |
81 | * | 104 | * |
82 | * fuzzy == 1: this is used for allocations where we are given a hint of where | 105 | * fuzzy - If this is set, then we are trying to make an allocation, and we just |
83 | * to look for free space. Because the hint may not be completely on an offset | 106 | * want a section that has at least bytes size and comes at or after the given |
84 | * mark, or the hint may no longer point to free space we need to fudge our | 107 | * offset. |
85 | * results a bit. So we look for free space starting at or after offset with at | ||
86 | * least bytes size. We prefer to find as close to the given offset as we can. | ||
87 | * Also if the offset is within a free space range, then we will return the free | ||
88 | * space that contains the given offset, which means we can return a free space | ||
89 | * chunk with an offset before the provided offset. | ||
90 | * | ||
91 | * fuzzy == 0: this is just a normal tree search. Give us the free space that | ||
92 | * starts at the given offset which is at least bytes size, and if its not there | ||
93 | * return NULL. | ||
94 | */ | 108 | */ |
95 | static struct btrfs_free_space *tree_search_offset(struct rb_root *root, | 109 | static struct btrfs_free_space * |
96 | u64 offset, u64 bytes, | 110 | tree_search_offset(struct btrfs_block_group_cache *block_group, |
97 | int fuzzy) | 111 | u64 offset, int bitmap_only, int fuzzy) |
98 | { | 112 | { |
99 | struct rb_node *n = root->rb_node; | 113 | struct rb_node *n = block_group->free_space_offset.rb_node; |
100 | struct btrfs_free_space *entry, *ret = NULL; | 114 | struct btrfs_free_space *entry, *prev = NULL; |
115 | |||
116 | /* find entry that is closest to the 'offset' */ | ||
117 | while (1) { | ||
118 | if (!n) { | ||
119 | entry = NULL; | ||
120 | break; | ||
121 | } | ||
101 | 122 | ||
102 | while (n) { | ||
103 | entry = rb_entry(n, struct btrfs_free_space, offset_index); | 123 | entry = rb_entry(n, struct btrfs_free_space, offset_index); |
124 | prev = entry; | ||
104 | 125 | ||
105 | if (offset < entry->offset) { | 126 | if (offset < entry->offset) |
106 | if (fuzzy && | ||
107 | (!ret || entry->offset < ret->offset) && | ||
108 | (bytes <= entry->bytes)) | ||
109 | ret = entry; | ||
110 | n = n->rb_left; | 127 | n = n->rb_left; |
111 | } else if (offset > entry->offset) { | 128 | else if (offset > entry->offset) |
112 | if (fuzzy && | ||
113 | (entry->offset + entry->bytes - 1) >= offset && | ||
114 | bytes <= entry->bytes) { | ||
115 | ret = entry; | ||
116 | break; | ||
117 | } | ||
118 | n = n->rb_right; | 129 | n = n->rb_right; |
119 | } else { | 130 | else |
120 | if (bytes > entry->bytes) { | ||
121 | n = n->rb_right; | ||
122 | continue; | ||
123 | } | ||
124 | ret = entry; | ||
125 | break; | 131 | break; |
126 | } | ||
127 | } | 132 | } |
128 | 133 | ||
129 | return ret; | 134 | if (bitmap_only) { |
130 | } | 135 | if (!entry) |
136 | return NULL; | ||
137 | if (entry->bitmap) | ||
138 | return entry; | ||
131 | 139 | ||
132 | /* | 140 | /* |
133 | * return a chunk at least bytes size, as close to offset that we can get. | 141 | * bitmap entry and extent entry may share same offset, |
134 | */ | 142 | * in that case, bitmap entry comes after extent entry. |
135 | static struct btrfs_free_space *tree_search_bytes(struct rb_root *root, | 143 | */ |
136 | u64 offset, u64 bytes) | 144 | n = rb_next(n); |
137 | { | 145 | if (!n) |
138 | struct rb_node *n = root->rb_node; | 146 | return NULL; |
139 | struct btrfs_free_space *entry, *ret = NULL; | 147 | entry = rb_entry(n, struct btrfs_free_space, offset_index); |
140 | 148 | if (entry->offset != offset) | |
141 | while (n) { | 149 | return NULL; |
142 | entry = rb_entry(n, struct btrfs_free_space, bytes_index); | ||
143 | 150 | ||
144 | if (bytes < entry->bytes) { | 151 | WARN_ON(!entry->bitmap); |
152 | return entry; | ||
153 | } else if (entry) { | ||
154 | if (entry->bitmap) { | ||
145 | /* | 155 | /* |
146 | * We prefer to get a hole size as close to the size we | 156 | * if previous extent entry covers the offset, |
147 | * are asking for so we don't take small slivers out of | 157 | * we should return it instead of the bitmap entry |
148 | * huge holes, but we also want to get as close to the | ||
149 | * offset as possible so we don't have a whole lot of | ||
150 | * fragmentation. | ||
151 | */ | 158 | */ |
152 | if (offset <= entry->offset) { | 159 | n = &entry->offset_index; |
153 | if (!ret) | 160 | while (1) { |
154 | ret = entry; | 161 | n = rb_prev(n); |
155 | else if (entry->bytes < ret->bytes) | 162 | if (!n) |
156 | ret = entry; | 163 | break; |
157 | else if (entry->offset < ret->offset) | 164 | prev = rb_entry(n, struct btrfs_free_space, |
158 | ret = entry; | 165 | offset_index); |
166 | if (!prev->bitmap) { | ||
167 | if (prev->offset + prev->bytes > offset) | ||
168 | entry = prev; | ||
169 | break; | ||
170 | } | ||
159 | } | 171 | } |
160 | n = n->rb_left; | 172 | } |
161 | } else if (bytes > entry->bytes) { | 173 | return entry; |
162 | n = n->rb_right; | 174 | } |
175 | |||
176 | if (!prev) | ||
177 | return NULL; | ||
178 | |||
179 | /* find last entry before the 'offset' */ | ||
180 | entry = prev; | ||
181 | if (entry->offset > offset) { | ||
182 | n = rb_prev(&entry->offset_index); | ||
183 | if (n) { | ||
184 | entry = rb_entry(n, struct btrfs_free_space, | ||
185 | offset_index); | ||
186 | BUG_ON(entry->offset > offset); | ||
163 | } else { | 187 | } else { |
164 | /* | 188 | if (fuzzy) |
165 | * Ok we may have multiple chunks of the wanted size, | 189 | return entry; |
166 | * so we don't want to take the first one we find, we | 190 | else |
167 | * want to take the one closest to our given offset, so | 191 | return NULL; |
168 | * keep searching just in case theres a better match. | ||
169 | */ | ||
170 | n = n->rb_right; | ||
171 | if (offset > entry->offset) | ||
172 | continue; | ||
173 | else if (!ret || entry->offset < ret->offset) | ||
174 | ret = entry; | ||
175 | } | 192 | } |
176 | } | 193 | } |
177 | 194 | ||
178 | return ret; | 195 | if (entry->bitmap) { |
196 | n = &entry->offset_index; | ||
197 | while (1) { | ||
198 | n = rb_prev(n); | ||
199 | if (!n) | ||
200 | break; | ||
201 | prev = rb_entry(n, struct btrfs_free_space, | ||
202 | offset_index); | ||
203 | if (!prev->bitmap) { | ||
204 | if (prev->offset + prev->bytes > offset) | ||
205 | return prev; | ||
206 | break; | ||
207 | } | ||
208 | } | ||
209 | if (entry->offset + BITS_PER_BITMAP * | ||
210 | block_group->sectorsize > offset) | ||
211 | return entry; | ||
212 | } else if (entry->offset + entry->bytes > offset) | ||
213 | return entry; | ||
214 | |||
215 | if (!fuzzy) | ||
216 | return NULL; | ||
217 | |||
218 | while (1) { | ||
219 | if (entry->bitmap) { | ||
220 | if (entry->offset + BITS_PER_BITMAP * | ||
221 | block_group->sectorsize > offset) | ||
222 | break; | ||
223 | } else { | ||
224 | if (entry->offset + entry->bytes > offset) | ||
225 | break; | ||
226 | } | ||
227 | |||
228 | n = rb_next(&entry->offset_index); | ||
229 | if (!n) | ||
230 | return NULL; | ||
231 | entry = rb_entry(n, struct btrfs_free_space, offset_index); | ||
232 | } | ||
233 | return entry; | ||
179 | } | 234 | } |
180 | 235 | ||
181 | static void unlink_free_space(struct btrfs_block_group_cache *block_group, | 236 | static void unlink_free_space(struct btrfs_block_group_cache *block_group, |
182 | struct btrfs_free_space *info) | 237 | struct btrfs_free_space *info) |
183 | { | 238 | { |
184 | rb_erase(&info->offset_index, &block_group->free_space_offset); | 239 | rb_erase(&info->offset_index, &block_group->free_space_offset); |
185 | rb_erase(&info->bytes_index, &block_group->free_space_bytes); | 240 | block_group->free_extents--; |
241 | block_group->free_space -= info->bytes; | ||
186 | } | 242 | } |
187 | 243 | ||
188 | static int link_free_space(struct btrfs_block_group_cache *block_group, | 244 | static int link_free_space(struct btrfs_block_group_cache *block_group, |
@@ -190,17 +246,353 @@ static int link_free_space(struct btrfs_block_group_cache *block_group, | |||
190 | { | 246 | { |
191 | int ret = 0; | 247 | int ret = 0; |
192 | 248 | ||
193 | 249 | BUG_ON(!info->bitmap && !info->bytes); | |
194 | BUG_ON(!info->bytes); | ||
195 | ret = tree_insert_offset(&block_group->free_space_offset, info->offset, | 250 | ret = tree_insert_offset(&block_group->free_space_offset, info->offset, |
196 | &info->offset_index); | 251 | &info->offset_index, (info->bitmap != NULL)); |
197 | if (ret) | 252 | if (ret) |
198 | return ret; | 253 | return ret; |
199 | 254 | ||
200 | ret = tree_insert_bytes(&block_group->free_space_bytes, info->bytes, | 255 | block_group->free_space += info->bytes; |
201 | &info->bytes_index); | 256 | block_group->free_extents++; |
202 | if (ret) | 257 | return ret; |
203 | return ret; | 258 | } |
259 | |||
260 | static void recalculate_thresholds(struct btrfs_block_group_cache *block_group) | ||
261 | { | ||
262 | u64 max_bytes, possible_bytes; | ||
263 | |||
264 | /* | ||
265 | * The goal is to keep the total amount of memory used per 1gb of space | ||
266 | * at or below 32k, so we need to adjust how much memory we allow to be | ||
267 | * used by extent based free space tracking | ||
268 | */ | ||
269 | max_bytes = MAX_CACHE_BYTES_PER_GIG * | ||
270 | (div64_u64(block_group->key.offset, 1024 * 1024 * 1024)); | ||
271 | |||
272 | possible_bytes = (block_group->total_bitmaps * PAGE_CACHE_SIZE) + | ||
273 | (sizeof(struct btrfs_free_space) * | ||
274 | block_group->extents_thresh); | ||
275 | |||
276 | if (possible_bytes > max_bytes) { | ||
277 | int extent_bytes = max_bytes - | ||
278 | (block_group->total_bitmaps * PAGE_CACHE_SIZE); | ||
279 | |||
280 | if (extent_bytes <= 0) { | ||
281 | block_group->extents_thresh = 0; | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | block_group->extents_thresh = extent_bytes / | ||
286 | (sizeof(struct btrfs_free_space)); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group, | ||
291 | struct btrfs_free_space *info, u64 offset, | ||
292 | u64 bytes) | ||
293 | { | ||
294 | unsigned long start, end; | ||
295 | unsigned long i; | ||
296 | |||
297 | start = offset_to_bit(info->offset, block_group->sectorsize, offset); | ||
298 | end = start + bytes_to_bits(bytes, block_group->sectorsize); | ||
299 | BUG_ON(end > BITS_PER_BITMAP); | ||
300 | |||
301 | for (i = start; i < end; i++) | ||
302 | clear_bit(i, info->bitmap); | ||
303 | |||
304 | info->bytes -= bytes; | ||
305 | block_group->free_space -= bytes; | ||
306 | } | ||
307 | |||
308 | static void bitmap_set_bits(struct btrfs_block_group_cache *block_group, | ||
309 | struct btrfs_free_space *info, u64 offset, | ||
310 | u64 bytes) | ||
311 | { | ||
312 | unsigned long start, end; | ||
313 | unsigned long i; | ||
314 | |||
315 | start = offset_to_bit(info->offset, block_group->sectorsize, offset); | ||
316 | end = start + bytes_to_bits(bytes, block_group->sectorsize); | ||
317 | BUG_ON(end > BITS_PER_BITMAP); | ||
318 | |||
319 | for (i = start; i < end; i++) | ||
320 | set_bit(i, info->bitmap); | ||
321 | |||
322 | info->bytes += bytes; | ||
323 | block_group->free_space += bytes; | ||
324 | } | ||
325 | |||
326 | static int search_bitmap(struct btrfs_block_group_cache *block_group, | ||
327 | struct btrfs_free_space *bitmap_info, u64 *offset, | ||
328 | u64 *bytes) | ||
329 | { | ||
330 | unsigned long found_bits = 0; | ||
331 | unsigned long bits, i; | ||
332 | unsigned long next_zero; | ||
333 | |||
334 | i = offset_to_bit(bitmap_info->offset, block_group->sectorsize, | ||
335 | max_t(u64, *offset, bitmap_info->offset)); | ||
336 | bits = bytes_to_bits(*bytes, block_group->sectorsize); | ||
337 | |||
338 | for (i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i); | ||
339 | i < BITS_PER_BITMAP; | ||
340 | i = find_next_bit(bitmap_info->bitmap, BITS_PER_BITMAP, i + 1)) { | ||
341 | next_zero = find_next_zero_bit(bitmap_info->bitmap, | ||
342 | BITS_PER_BITMAP, i); | ||
343 | if ((next_zero - i) >= bits) { | ||
344 | found_bits = next_zero - i; | ||
345 | break; | ||
346 | } | ||
347 | i = next_zero; | ||
348 | } | ||
349 | |||
350 | if (found_bits) { | ||
351 | *offset = (u64)(i * block_group->sectorsize) + | ||
352 | bitmap_info->offset; | ||
353 | *bytes = (u64)(found_bits) * block_group->sectorsize; | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | return -1; | ||
358 | } | ||
359 | |||
360 | static struct btrfs_free_space *find_free_space(struct btrfs_block_group_cache | ||
361 | *block_group, u64 *offset, | ||
362 | u64 *bytes, int debug) | ||
363 | { | ||
364 | struct btrfs_free_space *entry; | ||
365 | struct rb_node *node; | ||
366 | int ret; | ||
367 | |||
368 | if (!block_group->free_space_offset.rb_node) | ||
369 | return NULL; | ||
370 | |||
371 | entry = tree_search_offset(block_group, | ||
372 | offset_to_bitmap(block_group, *offset), | ||
373 | 0, 1); | ||
374 | if (!entry) | ||
375 | return NULL; | ||
376 | |||
377 | for (node = &entry->offset_index; node; node = rb_next(node)) { | ||
378 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | ||
379 | if (entry->bytes < *bytes) | ||
380 | continue; | ||
381 | |||
382 | if (entry->bitmap) { | ||
383 | ret = search_bitmap(block_group, entry, offset, bytes); | ||
384 | if (!ret) | ||
385 | return entry; | ||
386 | continue; | ||
387 | } | ||
388 | |||
389 | *offset = entry->offset; | ||
390 | *bytes = entry->bytes; | ||
391 | return entry; | ||
392 | } | ||
393 | |||
394 | return NULL; | ||
395 | } | ||
396 | |||
397 | static void add_new_bitmap(struct btrfs_block_group_cache *block_group, | ||
398 | struct btrfs_free_space *info, u64 offset) | ||
399 | { | ||
400 | u64 bytes_per_bg = BITS_PER_BITMAP * block_group->sectorsize; | ||
401 | int max_bitmaps = (int)div64_u64(block_group->key.offset + | ||
402 | bytes_per_bg - 1, bytes_per_bg); | ||
403 | BUG_ON(block_group->total_bitmaps >= max_bitmaps); | ||
404 | |||
405 | info->offset = offset_to_bitmap(block_group, offset); | ||
406 | link_free_space(block_group, info); | ||
407 | block_group->total_bitmaps++; | ||
408 | |||
409 | recalculate_thresholds(block_group); | ||
410 | } | ||
411 | |||
412 | static noinline int remove_from_bitmap(struct btrfs_block_group_cache *block_group, | ||
413 | struct btrfs_free_space *bitmap_info, | ||
414 | u64 *offset, u64 *bytes) | ||
415 | { | ||
416 | u64 end; | ||
417 | u64 search_start, search_bytes; | ||
418 | int ret; | ||
419 | |||
420 | again: | ||
421 | end = bitmap_info->offset + | ||
422 | (u64)(BITS_PER_BITMAP * block_group->sectorsize) - 1; | ||
423 | |||
424 | /* | ||
425 | * XXX - this can go away after a few releases. | ||
426 | * | ||
427 | * since the only user of btrfs_remove_free_space is the tree logging | ||
428 | * stuff, and the only way to test that is under crash conditions, we | ||
429 | * want to have this debug stuff here just in case somethings not | ||
430 | * working. Search the bitmap for the space we are trying to use to | ||
431 | * make sure its actually there. If its not there then we need to stop | ||
432 | * because something has gone wrong. | ||
433 | */ | ||
434 | search_start = *offset; | ||
435 | search_bytes = *bytes; | ||
436 | ret = search_bitmap(block_group, bitmap_info, &search_start, | ||
437 | &search_bytes); | ||
438 | BUG_ON(ret < 0 || search_start != *offset); | ||
439 | |||
440 | if (*offset > bitmap_info->offset && *offset + *bytes > end) { | ||
441 | bitmap_clear_bits(block_group, bitmap_info, *offset, | ||
442 | end - *offset + 1); | ||
443 | *bytes -= end - *offset + 1; | ||
444 | *offset = end + 1; | ||
445 | } else if (*offset >= bitmap_info->offset && *offset + *bytes <= end) { | ||
446 | bitmap_clear_bits(block_group, bitmap_info, *offset, *bytes); | ||
447 | *bytes = 0; | ||
448 | } | ||
449 | |||
450 | if (*bytes) { | ||
451 | struct rb_node *next = rb_next(&bitmap_info->offset_index); | ||
452 | if (!bitmap_info->bytes) { | ||
453 | unlink_free_space(block_group, bitmap_info); | ||
454 | kfree(bitmap_info->bitmap); | ||
455 | kfree(bitmap_info); | ||
456 | block_group->total_bitmaps--; | ||
457 | recalculate_thresholds(block_group); | ||
458 | } | ||
459 | |||
460 | /* | ||
461 | * no entry after this bitmap, but we still have bytes to | ||
462 | * remove, so something has gone wrong. | ||
463 | */ | ||
464 | if (!next) | ||
465 | return -EINVAL; | ||
466 | |||
467 | bitmap_info = rb_entry(next, struct btrfs_free_space, | ||
468 | offset_index); | ||
469 | |||
470 | /* | ||
471 | * if the next entry isn't a bitmap we need to return to let the | ||
472 | * extent stuff do its work. | ||
473 | */ | ||
474 | if (!bitmap_info->bitmap) | ||
475 | return -EAGAIN; | ||
476 | |||
477 | /* | ||
478 | * Ok the next item is a bitmap, but it may not actually hold | ||
479 | * the information for the rest of this free space stuff, so | ||
480 | * look for it, and if we don't find it return so we can try | ||
481 | * everything over again. | ||
482 | */ | ||
483 | search_start = *offset; | ||
484 | search_bytes = *bytes; | ||
485 | ret = search_bitmap(block_group, bitmap_info, &search_start, | ||
486 | &search_bytes); | ||
487 | if (ret < 0 || search_start != *offset) | ||
488 | return -EAGAIN; | ||
489 | |||
490 | goto again; | ||
491 | } else if (!bitmap_info->bytes) { | ||
492 | unlink_free_space(block_group, bitmap_info); | ||
493 | kfree(bitmap_info->bitmap); | ||
494 | kfree(bitmap_info); | ||
495 | block_group->total_bitmaps--; | ||
496 | recalculate_thresholds(block_group); | ||
497 | } | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int insert_into_bitmap(struct btrfs_block_group_cache *block_group, | ||
503 | struct btrfs_free_space *info) | ||
504 | { | ||
505 | struct btrfs_free_space *bitmap_info; | ||
506 | int added = 0; | ||
507 | u64 bytes, offset, end; | ||
508 | int ret; | ||
509 | |||
510 | /* | ||
511 | * If we are below the extents threshold then we can add this as an | ||
512 | * extent, and don't have to deal with the bitmap | ||
513 | */ | ||
514 | if (block_group->free_extents < block_group->extents_thresh && | ||
515 | info->bytes > block_group->sectorsize * 4) | ||
516 | return 0; | ||
517 | |||
518 | /* | ||
519 | * some block groups are so tiny they can't be enveloped by a bitmap, so | ||
520 | * don't even bother to create a bitmap for this | ||
521 | */ | ||
522 | if (BITS_PER_BITMAP * block_group->sectorsize > | ||
523 | block_group->key.offset) | ||
524 | return 0; | ||
525 | |||
526 | bytes = info->bytes; | ||
527 | offset = info->offset; | ||
528 | |||
529 | again: | ||
530 | bitmap_info = tree_search_offset(block_group, | ||
531 | offset_to_bitmap(block_group, offset), | ||
532 | 1, 0); | ||
533 | if (!bitmap_info) { | ||
534 | BUG_ON(added); | ||
535 | goto new_bitmap; | ||
536 | } | ||
537 | |||
538 | end = bitmap_info->offset + | ||
539 | (u64)(BITS_PER_BITMAP * block_group->sectorsize); | ||
540 | |||
541 | if (offset >= bitmap_info->offset && offset + bytes > end) { | ||
542 | bitmap_set_bits(block_group, bitmap_info, offset, | ||
543 | end - offset); | ||
544 | bytes -= end - offset; | ||
545 | offset = end; | ||
546 | added = 0; | ||
547 | } else if (offset >= bitmap_info->offset && offset + bytes <= end) { | ||
548 | bitmap_set_bits(block_group, bitmap_info, offset, bytes); | ||
549 | bytes = 0; | ||
550 | } else { | ||
551 | BUG(); | ||
552 | } | ||
553 | |||
554 | if (!bytes) { | ||
555 | ret = 1; | ||
556 | goto out; | ||
557 | } else | ||
558 | goto again; | ||
559 | |||
560 | new_bitmap: | ||
561 | if (info && info->bitmap) { | ||
562 | add_new_bitmap(block_group, info, offset); | ||
563 | added = 1; | ||
564 | info = NULL; | ||
565 | goto again; | ||
566 | } else { | ||
567 | spin_unlock(&block_group->tree_lock); | ||
568 | |||
569 | /* no pre-allocated info, allocate a new one */ | ||
570 | if (!info) { | ||
571 | info = kzalloc(sizeof(struct btrfs_free_space), | ||
572 | GFP_NOFS); | ||
573 | if (!info) { | ||
574 | spin_lock(&block_group->tree_lock); | ||
575 | ret = -ENOMEM; | ||
576 | goto out; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | /* allocate the bitmap */ | ||
581 | info->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS); | ||
582 | spin_lock(&block_group->tree_lock); | ||
583 | if (!info->bitmap) { | ||
584 | ret = -ENOMEM; | ||
585 | goto out; | ||
586 | } | ||
587 | goto again; | ||
588 | } | ||
589 | |||
590 | out: | ||
591 | if (info) { | ||
592 | if (info->bitmap) | ||
593 | kfree(info->bitmap); | ||
594 | kfree(info); | ||
595 | } | ||
204 | 596 | ||
205 | return ret; | 597 | return ret; |
206 | } | 598 | } |
@@ -208,8 +600,8 @@ static int link_free_space(struct btrfs_block_group_cache *block_group, | |||
208 | int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | 600 | int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, |
209 | u64 offset, u64 bytes) | 601 | u64 offset, u64 bytes) |
210 | { | 602 | { |
211 | struct btrfs_free_space *right_info; | 603 | struct btrfs_free_space *right_info = NULL; |
212 | struct btrfs_free_space *left_info; | 604 | struct btrfs_free_space *left_info = NULL; |
213 | struct btrfs_free_space *info = NULL; | 605 | struct btrfs_free_space *info = NULL; |
214 | int ret = 0; | 606 | int ret = 0; |
215 | 607 | ||
@@ -227,18 +619,38 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | |||
227 | * are adding, if there is remove that struct and add a new one to | 619 | * are adding, if there is remove that struct and add a new one to |
228 | * cover the entire range | 620 | * cover the entire range |
229 | */ | 621 | */ |
230 | right_info = tree_search_offset(&block_group->free_space_offset, | 622 | right_info = tree_search_offset(block_group, offset + bytes, 0, 0); |
231 | offset+bytes, 0, 0); | 623 | if (right_info && rb_prev(&right_info->offset_index)) |
232 | left_info = tree_search_offset(&block_group->free_space_offset, | 624 | left_info = rb_entry(rb_prev(&right_info->offset_index), |
233 | offset-1, 0, 1); | 625 | struct btrfs_free_space, offset_index); |
626 | else | ||
627 | left_info = tree_search_offset(block_group, offset - 1, 0, 0); | ||
628 | |||
629 | /* | ||
630 | * If there was no extent directly to the left or right of this new | ||
631 | * extent then we know we're going to have to allocate a new extent, so | ||
632 | * before we do that see if we need to drop this into a bitmap | ||
633 | */ | ||
634 | if ((!left_info || left_info->bitmap) && | ||
635 | (!right_info || right_info->bitmap)) { | ||
636 | ret = insert_into_bitmap(block_group, info); | ||
637 | |||
638 | if (ret < 0) { | ||
639 | goto out; | ||
640 | } else if (ret) { | ||
641 | ret = 0; | ||
642 | goto out; | ||
643 | } | ||
644 | } | ||
234 | 645 | ||
235 | if (right_info) { | 646 | if (right_info && !right_info->bitmap) { |
236 | unlink_free_space(block_group, right_info); | 647 | unlink_free_space(block_group, right_info); |
237 | info->bytes += right_info->bytes; | 648 | info->bytes += right_info->bytes; |
238 | kfree(right_info); | 649 | kfree(right_info); |
239 | } | 650 | } |
240 | 651 | ||
241 | if (left_info && left_info->offset + left_info->bytes == offset) { | 652 | if (left_info && !left_info->bitmap && |
653 | left_info->offset + left_info->bytes == offset) { | ||
242 | unlink_free_space(block_group, left_info); | 654 | unlink_free_space(block_group, left_info); |
243 | info->offset = left_info->offset; | 655 | info->offset = left_info->offset; |
244 | info->bytes += left_info->bytes; | 656 | info->bytes += left_info->bytes; |
@@ -248,11 +660,11 @@ int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | |||
248 | ret = link_free_space(block_group, info); | 660 | ret = link_free_space(block_group, info); |
249 | if (ret) | 661 | if (ret) |
250 | kfree(info); | 662 | kfree(info); |
251 | 663 | out: | |
252 | spin_unlock(&block_group->tree_lock); | 664 | spin_unlock(&block_group->tree_lock); |
253 | 665 | ||
254 | if (ret) { | 666 | if (ret) { |
255 | printk(KERN_ERR "btrfs: unable to add free space :%d\n", ret); | 667 | printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret); |
256 | BUG_ON(ret == -EEXIST); | 668 | BUG_ON(ret == -EEXIST); |
257 | } | 669 | } |
258 | 670 | ||
@@ -263,40 +675,74 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | |||
263 | u64 offset, u64 bytes) | 675 | u64 offset, u64 bytes) |
264 | { | 676 | { |
265 | struct btrfs_free_space *info; | 677 | struct btrfs_free_space *info; |
678 | struct btrfs_free_space *next_info = NULL; | ||
266 | int ret = 0; | 679 | int ret = 0; |
267 | 680 | ||
268 | spin_lock(&block_group->tree_lock); | 681 | spin_lock(&block_group->tree_lock); |
269 | 682 | ||
270 | info = tree_search_offset(&block_group->free_space_offset, offset, 0, | 683 | again: |
271 | 1); | 684 | info = tree_search_offset(block_group, offset, 0, 0); |
272 | if (info && info->offset == offset) { | 685 | if (!info) { |
273 | if (info->bytes < bytes) { | 686 | /* |
274 | printk(KERN_ERR "Found free space at %llu, size %llu," | 687 | * oops didn't find an extent that matched the space we wanted |
275 | "trying to use %llu\n", | 688 | * to remove, look for a bitmap instead |
276 | (unsigned long long)info->offset, | 689 | */ |
277 | (unsigned long long)info->bytes, | 690 | info = tree_search_offset(block_group, |
278 | (unsigned long long)bytes); | 691 | offset_to_bitmap(block_group, offset), |
692 | 1, 0); | ||
693 | if (!info) { | ||
694 | WARN_ON(1); | ||
695 | goto out_lock; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | if (info->bytes < bytes && rb_next(&info->offset_index)) { | ||
700 | u64 end; | ||
701 | next_info = rb_entry(rb_next(&info->offset_index), | ||
702 | struct btrfs_free_space, | ||
703 | offset_index); | ||
704 | |||
705 | if (next_info->bitmap) | ||
706 | end = next_info->offset + BITS_PER_BITMAP * | ||
707 | block_group->sectorsize - 1; | ||
708 | else | ||
709 | end = next_info->offset + next_info->bytes; | ||
710 | |||
711 | if (next_info->bytes < bytes || | ||
712 | next_info->offset > offset || offset > end) { | ||
713 | printk(KERN_CRIT "Found free space at %llu, size %llu," | ||
714 | " trying to use %llu\n", | ||
715 | (unsigned long long)info->offset, | ||
716 | (unsigned long long)info->bytes, | ||
717 | (unsigned long long)bytes); | ||
279 | WARN_ON(1); | 718 | WARN_ON(1); |
280 | ret = -EINVAL; | 719 | ret = -EINVAL; |
281 | spin_unlock(&block_group->tree_lock); | 720 | goto out_lock; |
282 | goto out; | ||
283 | } | 721 | } |
284 | unlink_free_space(block_group, info); | ||
285 | 722 | ||
286 | if (info->bytes == bytes) { | 723 | info = next_info; |
287 | kfree(info); | 724 | } |
288 | spin_unlock(&block_group->tree_lock); | 725 | |
289 | goto out; | 726 | if (info->bytes == bytes) { |
727 | unlink_free_space(block_group, info); | ||
728 | if (info->bitmap) { | ||
729 | kfree(info->bitmap); | ||
730 | block_group->total_bitmaps--; | ||
290 | } | 731 | } |
732 | kfree(info); | ||
733 | goto out_lock; | ||
734 | } | ||
291 | 735 | ||
736 | if (!info->bitmap && info->offset == offset) { | ||
737 | unlink_free_space(block_group, info); | ||
292 | info->offset += bytes; | 738 | info->offset += bytes; |
293 | info->bytes -= bytes; | 739 | info->bytes -= bytes; |
740 | link_free_space(block_group, info); | ||
741 | goto out_lock; | ||
742 | } | ||
294 | 743 | ||
295 | ret = link_free_space(block_group, info); | 744 | if (!info->bitmap && info->offset <= offset && |
296 | spin_unlock(&block_group->tree_lock); | 745 | info->offset + info->bytes >= offset + bytes) { |
297 | BUG_ON(ret); | ||
298 | } else if (info && info->offset < offset && | ||
299 | info->offset + info->bytes >= offset + bytes) { | ||
300 | u64 old_start = info->offset; | 746 | u64 old_start = info->offset; |
301 | /* | 747 | /* |
302 | * we're freeing space in the middle of the info, | 748 | * we're freeing space in the middle of the info, |
@@ -312,7 +758,9 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | |||
312 | info->offset = offset + bytes; | 758 | info->offset = offset + bytes; |
313 | info->bytes = old_end - info->offset; | 759 | info->bytes = old_end - info->offset; |
314 | ret = link_free_space(block_group, info); | 760 | ret = link_free_space(block_group, info); |
315 | BUG_ON(ret); | 761 | WARN_ON(ret); |
762 | if (ret) | ||
763 | goto out_lock; | ||
316 | } else { | 764 | } else { |
317 | /* the hole we're creating ends at the end | 765 | /* the hole we're creating ends at the end |
318 | * of the info struct, just free the info | 766 | * of the info struct, just free the info |
@@ -320,32 +768,22 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | |||
320 | kfree(info); | 768 | kfree(info); |
321 | } | 769 | } |
322 | spin_unlock(&block_group->tree_lock); | 770 | spin_unlock(&block_group->tree_lock); |
323 | /* step two, insert a new info struct to cover anything | 771 | |
324 | * before the hole | 772 | /* step two, insert a new info struct to cover |
773 | * anything before the hole | ||
325 | */ | 774 | */ |
326 | ret = btrfs_add_free_space(block_group, old_start, | 775 | ret = btrfs_add_free_space(block_group, old_start, |
327 | offset - old_start); | 776 | offset - old_start); |
328 | BUG_ON(ret); | 777 | WARN_ON(ret); |
329 | } else { | 778 | goto out; |
330 | spin_unlock(&block_group->tree_lock); | ||
331 | if (!info) { | ||
332 | printk(KERN_ERR "couldn't find space %llu to free\n", | ||
333 | (unsigned long long)offset); | ||
334 | printk(KERN_ERR "cached is %d, offset %llu bytes %llu\n", | ||
335 | block_group->cached, | ||
336 | (unsigned long long)block_group->key.objectid, | ||
337 | (unsigned long long)block_group->key.offset); | ||
338 | btrfs_dump_free_space(block_group, bytes); | ||
339 | } else if (info) { | ||
340 | printk(KERN_ERR "hmm, found offset=%llu bytes=%llu, " | ||
341 | "but wanted offset=%llu bytes=%llu\n", | ||
342 | (unsigned long long)info->offset, | ||
343 | (unsigned long long)info->bytes, | ||
344 | (unsigned long long)offset, | ||
345 | (unsigned long long)bytes); | ||
346 | } | ||
347 | WARN_ON(1); | ||
348 | } | 779 | } |
780 | |||
781 | ret = remove_from_bitmap(block_group, info, &offset, &bytes); | ||
782 | if (ret == -EAGAIN) | ||
783 | goto again; | ||
784 | BUG_ON(ret); | ||
785 | out_lock: | ||
786 | spin_unlock(&block_group->tree_lock); | ||
349 | out: | 787 | out: |
350 | return ret; | 788 | return ret; |
351 | } | 789 | } |
@@ -361,10 +799,13 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, | |||
361 | info = rb_entry(n, struct btrfs_free_space, offset_index); | 799 | info = rb_entry(n, struct btrfs_free_space, offset_index); |
362 | if (info->bytes >= bytes) | 800 | if (info->bytes >= bytes) |
363 | count++; | 801 | count++; |
364 | printk(KERN_ERR "entry offset %llu, bytes %llu\n", | 802 | printk(KERN_CRIT "entry offset %llu, bytes %llu, bitmap %s\n", |
365 | (unsigned long long)info->offset, | 803 | (unsigned long long)info->offset, |
366 | (unsigned long long)info->bytes); | 804 | (unsigned long long)info->bytes, |
805 | (info->bitmap) ? "yes" : "no"); | ||
367 | } | 806 | } |
807 | printk(KERN_INFO "block group has cluster?: %s\n", | ||
808 | list_empty(&block_group->cluster_list) ? "no" : "yes"); | ||
368 | printk(KERN_INFO "%d blocks of free space at or bigger than bytes is" | 809 | printk(KERN_INFO "%d blocks of free space at or bigger than bytes is" |
369 | "\n", count); | 810 | "\n", count); |
370 | } | 811 | } |
@@ -397,26 +838,35 @@ __btrfs_return_cluster_to_free_space( | |||
397 | { | 838 | { |
398 | struct btrfs_free_space *entry; | 839 | struct btrfs_free_space *entry; |
399 | struct rb_node *node; | 840 | struct rb_node *node; |
841 | bool bitmap; | ||
400 | 842 | ||
401 | spin_lock(&cluster->lock); | 843 | spin_lock(&cluster->lock); |
402 | if (cluster->block_group != block_group) | 844 | if (cluster->block_group != block_group) |
403 | goto out; | 845 | goto out; |
404 | 846 | ||
847 | bitmap = cluster->points_to_bitmap; | ||
848 | cluster->block_group = NULL; | ||
405 | cluster->window_start = 0; | 849 | cluster->window_start = 0; |
850 | list_del_init(&cluster->block_group_list); | ||
851 | cluster->points_to_bitmap = false; | ||
852 | |||
853 | if (bitmap) | ||
854 | goto out; | ||
855 | |||
406 | node = rb_first(&cluster->root); | 856 | node = rb_first(&cluster->root); |
407 | while(node) { | 857 | while (node) { |
408 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | 858 | entry = rb_entry(node, struct btrfs_free_space, offset_index); |
409 | node = rb_next(&entry->offset_index); | 859 | node = rb_next(&entry->offset_index); |
410 | rb_erase(&entry->offset_index, &cluster->root); | 860 | rb_erase(&entry->offset_index, &cluster->root); |
411 | link_free_space(block_group, entry); | 861 | BUG_ON(entry->bitmap); |
862 | tree_insert_offset(&block_group->free_space_offset, | ||
863 | entry->offset, &entry->offset_index, 0); | ||
412 | } | 864 | } |
413 | list_del_init(&cluster->block_group_list); | ||
414 | |||
415 | btrfs_put_block_group(cluster->block_group); | ||
416 | cluster->block_group = NULL; | ||
417 | cluster->root.rb_node = NULL; | 865 | cluster->root.rb_node = NULL; |
866 | |||
418 | out: | 867 | out: |
419 | spin_unlock(&cluster->lock); | 868 | spin_unlock(&cluster->lock); |
869 | btrfs_put_block_group(block_group); | ||
420 | return 0; | 870 | return 0; |
421 | } | 871 | } |
422 | 872 | ||
@@ -425,20 +875,28 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group) | |||
425 | struct btrfs_free_space *info; | 875 | struct btrfs_free_space *info; |
426 | struct rb_node *node; | 876 | struct rb_node *node; |
427 | struct btrfs_free_cluster *cluster; | 877 | struct btrfs_free_cluster *cluster; |
428 | struct btrfs_free_cluster *safe; | 878 | struct list_head *head; |
429 | 879 | ||
430 | spin_lock(&block_group->tree_lock); | 880 | spin_lock(&block_group->tree_lock); |
431 | 881 | while ((head = block_group->cluster_list.next) != | |
432 | list_for_each_entry_safe(cluster, safe, &block_group->cluster_list, | 882 | &block_group->cluster_list) { |
433 | block_group_list) { | 883 | cluster = list_entry(head, struct btrfs_free_cluster, |
884 | block_group_list); | ||
434 | 885 | ||
435 | WARN_ON(cluster->block_group != block_group); | 886 | WARN_ON(cluster->block_group != block_group); |
436 | __btrfs_return_cluster_to_free_space(block_group, cluster); | 887 | __btrfs_return_cluster_to_free_space(block_group, cluster); |
888 | if (need_resched()) { | ||
889 | spin_unlock(&block_group->tree_lock); | ||
890 | cond_resched(); | ||
891 | spin_lock(&block_group->tree_lock); | ||
892 | } | ||
437 | } | 893 | } |
438 | 894 | ||
439 | while ((node = rb_last(&block_group->free_space_bytes)) != NULL) { | 895 | while ((node = rb_last(&block_group->free_space_offset)) != NULL) { |
440 | info = rb_entry(node, struct btrfs_free_space, bytes_index); | 896 | info = rb_entry(node, struct btrfs_free_space, offset_index); |
441 | unlink_free_space(block_group, info); | 897 | unlink_free_space(block_group, info); |
898 | if (info->bitmap) | ||
899 | kfree(info->bitmap); | ||
442 | kfree(info); | 900 | kfree(info); |
443 | if (need_resched()) { | 901 | if (need_resched()) { |
444 | spin_unlock(&block_group->tree_lock); | 902 | spin_unlock(&block_group->tree_lock); |
@@ -446,6 +904,7 @@ void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group) | |||
446 | spin_lock(&block_group->tree_lock); | 904 | spin_lock(&block_group->tree_lock); |
447 | } | 905 | } |
448 | } | 906 | } |
907 | |||
449 | spin_unlock(&block_group->tree_lock); | 908 | spin_unlock(&block_group->tree_lock); |
450 | } | 909 | } |
451 | 910 | ||
@@ -453,25 +912,35 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, | |||
453 | u64 offset, u64 bytes, u64 empty_size) | 912 | u64 offset, u64 bytes, u64 empty_size) |
454 | { | 913 | { |
455 | struct btrfs_free_space *entry = NULL; | 914 | struct btrfs_free_space *entry = NULL; |
915 | u64 bytes_search = bytes + empty_size; | ||
456 | u64 ret = 0; | 916 | u64 ret = 0; |
457 | 917 | ||
458 | spin_lock(&block_group->tree_lock); | 918 | spin_lock(&block_group->tree_lock); |
459 | entry = tree_search_offset(&block_group->free_space_offset, offset, | 919 | entry = find_free_space(block_group, &offset, &bytes_search, 0); |
460 | bytes + empty_size, 1); | ||
461 | if (!entry) | 920 | if (!entry) |
462 | entry = tree_search_bytes(&block_group->free_space_bytes, | 921 | goto out; |
463 | offset, bytes + empty_size); | 922 | |
464 | if (entry) { | 923 | ret = offset; |
924 | if (entry->bitmap) { | ||
925 | bitmap_clear_bits(block_group, entry, offset, bytes); | ||
926 | if (!entry->bytes) { | ||
927 | unlink_free_space(block_group, entry); | ||
928 | kfree(entry->bitmap); | ||
929 | kfree(entry); | ||
930 | block_group->total_bitmaps--; | ||
931 | recalculate_thresholds(block_group); | ||
932 | } | ||
933 | } else { | ||
465 | unlink_free_space(block_group, entry); | 934 | unlink_free_space(block_group, entry); |
466 | ret = entry->offset; | ||
467 | entry->offset += bytes; | 935 | entry->offset += bytes; |
468 | entry->bytes -= bytes; | 936 | entry->bytes -= bytes; |
469 | |||
470 | if (!entry->bytes) | 937 | if (!entry->bytes) |
471 | kfree(entry); | 938 | kfree(entry); |
472 | else | 939 | else |
473 | link_free_space(block_group, entry); | 940 | link_free_space(block_group, entry); |
474 | } | 941 | } |
942 | |||
943 | out: | ||
475 | spin_unlock(&block_group->tree_lock); | 944 | spin_unlock(&block_group->tree_lock); |
476 | 945 | ||
477 | return ret; | 946 | return ret; |
@@ -517,6 +986,54 @@ int btrfs_return_cluster_to_free_space( | |||
517 | return ret; | 986 | return ret; |
518 | } | 987 | } |
519 | 988 | ||
989 | static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, | ||
990 | struct btrfs_free_cluster *cluster, | ||
991 | u64 bytes, u64 min_start) | ||
992 | { | ||
993 | struct btrfs_free_space *entry; | ||
994 | int err; | ||
995 | u64 search_start = cluster->window_start; | ||
996 | u64 search_bytes = bytes; | ||
997 | u64 ret = 0; | ||
998 | |||
999 | spin_lock(&block_group->tree_lock); | ||
1000 | spin_lock(&cluster->lock); | ||
1001 | |||
1002 | if (!cluster->points_to_bitmap) | ||
1003 | goto out; | ||
1004 | |||
1005 | if (cluster->block_group != block_group) | ||
1006 | goto out; | ||
1007 | |||
1008 | /* | ||
1009 | * search_start is the beginning of the bitmap, but at some point it may | ||
1010 | * be a good idea to point to the actual start of the free area in the | ||
1011 | * bitmap, so do the offset_to_bitmap trick anyway, and set bitmap_only | ||
1012 | * to 1 to make sure we get the bitmap entry | ||
1013 | */ | ||
1014 | entry = tree_search_offset(block_group, | ||
1015 | offset_to_bitmap(block_group, search_start), | ||
1016 | 1, 0); | ||
1017 | if (!entry || !entry->bitmap) | ||
1018 | goto out; | ||
1019 | |||
1020 | search_start = min_start; | ||
1021 | search_bytes = bytes; | ||
1022 | |||
1023 | err = search_bitmap(block_group, entry, &search_start, | ||
1024 | &search_bytes); | ||
1025 | if (err) | ||
1026 | goto out; | ||
1027 | |||
1028 | ret = search_start; | ||
1029 | bitmap_clear_bits(block_group, entry, ret, bytes); | ||
1030 | out: | ||
1031 | spin_unlock(&cluster->lock); | ||
1032 | spin_unlock(&block_group->tree_lock); | ||
1033 | |||
1034 | return ret; | ||
1035 | } | ||
1036 | |||
520 | /* | 1037 | /* |
521 | * given a cluster, try to allocate 'bytes' from it, returns 0 | 1038 | * given a cluster, try to allocate 'bytes' from it, returns 0 |
522 | * if it couldn't find anything suitably large, or a logical disk offset | 1039 | * if it couldn't find anything suitably large, or a logical disk offset |
@@ -530,6 +1047,10 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, | |||
530 | struct rb_node *node; | 1047 | struct rb_node *node; |
531 | u64 ret = 0; | 1048 | u64 ret = 0; |
532 | 1049 | ||
1050 | if (cluster->points_to_bitmap) | ||
1051 | return btrfs_alloc_from_bitmap(block_group, cluster, bytes, | ||
1052 | min_start); | ||
1053 | |||
533 | spin_lock(&cluster->lock); | 1054 | spin_lock(&cluster->lock); |
534 | if (bytes > cluster->max_size) | 1055 | if (bytes > cluster->max_size) |
535 | goto out; | 1056 | goto out; |
@@ -567,9 +1088,73 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, | |||
567 | } | 1088 | } |
568 | out: | 1089 | out: |
569 | spin_unlock(&cluster->lock); | 1090 | spin_unlock(&cluster->lock); |
1091 | |||
570 | return ret; | 1092 | return ret; |
571 | } | 1093 | } |
572 | 1094 | ||
1095 | static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group, | ||
1096 | struct btrfs_free_space *entry, | ||
1097 | struct btrfs_free_cluster *cluster, | ||
1098 | u64 offset, u64 bytes, u64 min_bytes) | ||
1099 | { | ||
1100 | unsigned long next_zero; | ||
1101 | unsigned long i; | ||
1102 | unsigned long search_bits; | ||
1103 | unsigned long total_bits; | ||
1104 | unsigned long found_bits; | ||
1105 | unsigned long start = 0; | ||
1106 | unsigned long total_found = 0; | ||
1107 | bool found = false; | ||
1108 | |||
1109 | i = offset_to_bit(entry->offset, block_group->sectorsize, | ||
1110 | max_t(u64, offset, entry->offset)); | ||
1111 | search_bits = bytes_to_bits(min_bytes, block_group->sectorsize); | ||
1112 | total_bits = bytes_to_bits(bytes, block_group->sectorsize); | ||
1113 | |||
1114 | again: | ||
1115 | found_bits = 0; | ||
1116 | for (i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i); | ||
1117 | i < BITS_PER_BITMAP; | ||
1118 | i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, i + 1)) { | ||
1119 | next_zero = find_next_zero_bit(entry->bitmap, | ||
1120 | BITS_PER_BITMAP, i); | ||
1121 | if (next_zero - i >= search_bits) { | ||
1122 | found_bits = next_zero - i; | ||
1123 | break; | ||
1124 | } | ||
1125 | i = next_zero; | ||
1126 | } | ||
1127 | |||
1128 | if (!found_bits) | ||
1129 | return -1; | ||
1130 | |||
1131 | if (!found) { | ||
1132 | start = i; | ||
1133 | found = true; | ||
1134 | } | ||
1135 | |||
1136 | total_found += found_bits; | ||
1137 | |||
1138 | if (cluster->max_size < found_bits * block_group->sectorsize) | ||
1139 | cluster->max_size = found_bits * block_group->sectorsize; | ||
1140 | |||
1141 | if (total_found < total_bits) { | ||
1142 | i = find_next_bit(entry->bitmap, BITS_PER_BITMAP, next_zero); | ||
1143 | if (i - start > total_bits * 2) { | ||
1144 | total_found = 0; | ||
1145 | cluster->max_size = 0; | ||
1146 | found = false; | ||
1147 | } | ||
1148 | goto again; | ||
1149 | } | ||
1150 | |||
1151 | cluster->window_start = start * block_group->sectorsize + | ||
1152 | entry->offset; | ||
1153 | cluster->points_to_bitmap = true; | ||
1154 | |||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
573 | /* | 1158 | /* |
574 | * here we try to find a cluster of blocks in a block group. The goal | 1159 | * here we try to find a cluster of blocks in a block group. The goal |
575 | * is to find at least bytes free and up to empty_size + bytes free. | 1160 | * is to find at least bytes free and up to empty_size + bytes free. |
@@ -587,12 +1172,12 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, | |||
587 | struct btrfs_free_space *entry = NULL; | 1172 | struct btrfs_free_space *entry = NULL; |
588 | struct rb_node *node; | 1173 | struct rb_node *node; |
589 | struct btrfs_free_space *next; | 1174 | struct btrfs_free_space *next; |
590 | struct btrfs_free_space *last; | 1175 | struct btrfs_free_space *last = NULL; |
591 | u64 min_bytes; | 1176 | u64 min_bytes; |
592 | u64 window_start; | 1177 | u64 window_start; |
593 | u64 window_free; | 1178 | u64 window_free; |
594 | u64 max_extent = 0; | 1179 | u64 max_extent = 0; |
595 | int total_retries = 0; | 1180 | bool found_bitmap = false; |
596 | int ret; | 1181 | int ret; |
597 | 1182 | ||
598 | /* for metadata, allow allocates with more holes */ | 1183 | /* for metadata, allow allocates with more holes */ |
@@ -620,31 +1205,80 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, | |||
620 | goto out; | 1205 | goto out; |
621 | } | 1206 | } |
622 | again: | 1207 | again: |
623 | min_bytes = min(min_bytes, bytes + empty_size); | 1208 | entry = tree_search_offset(block_group, offset, found_bitmap, 1); |
624 | entry = tree_search_bytes(&block_group->free_space_bytes, | ||
625 | offset, min_bytes); | ||
626 | if (!entry) { | 1209 | if (!entry) { |
627 | ret = -ENOSPC; | 1210 | ret = -ENOSPC; |
628 | goto out; | 1211 | goto out; |
629 | } | 1212 | } |
1213 | |||
1214 | /* | ||
1215 | * If found_bitmap is true, we exhausted our search for extent entries, | ||
1216 | * and we just want to search all of the bitmaps that we can find, and | ||
1217 | * ignore any extent entries we find. | ||
1218 | */ | ||
1219 | while (entry->bitmap || found_bitmap || | ||
1220 | (!entry->bitmap && entry->bytes < min_bytes)) { | ||
1221 | struct rb_node *node = rb_next(&entry->offset_index); | ||
1222 | |||
1223 | if (entry->bitmap && entry->bytes > bytes + empty_size) { | ||
1224 | ret = btrfs_bitmap_cluster(block_group, entry, cluster, | ||
1225 | offset, bytes + empty_size, | ||
1226 | min_bytes); | ||
1227 | if (!ret) | ||
1228 | goto got_it; | ||
1229 | } | ||
1230 | |||
1231 | if (!node) { | ||
1232 | ret = -ENOSPC; | ||
1233 | goto out; | ||
1234 | } | ||
1235 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | ||
1236 | } | ||
1237 | |||
1238 | /* | ||
1239 | * We already searched all the extent entries from the passed in offset | ||
1240 | * to the end and didn't find enough space for the cluster, and we also | ||
1241 | * didn't find any bitmaps that met our criteria, just go ahead and exit | ||
1242 | */ | ||
1243 | if (found_bitmap) { | ||
1244 | ret = -ENOSPC; | ||
1245 | goto out; | ||
1246 | } | ||
1247 | |||
1248 | cluster->points_to_bitmap = false; | ||
630 | window_start = entry->offset; | 1249 | window_start = entry->offset; |
631 | window_free = entry->bytes; | 1250 | window_free = entry->bytes; |
632 | last = entry; | 1251 | last = entry; |
633 | max_extent = entry->bytes; | 1252 | max_extent = entry->bytes; |
634 | 1253 | ||
635 | while(1) { | 1254 | while (1) { |
636 | /* out window is just right, lets fill it */ | 1255 | /* out window is just right, lets fill it */ |
637 | if (window_free >= bytes + empty_size) | 1256 | if (window_free >= bytes + empty_size) |
638 | break; | 1257 | break; |
639 | 1258 | ||
640 | node = rb_next(&last->offset_index); | 1259 | node = rb_next(&last->offset_index); |
641 | if (!node) { | 1260 | if (!node) { |
1261 | if (found_bitmap) | ||
1262 | goto again; | ||
642 | ret = -ENOSPC; | 1263 | ret = -ENOSPC; |
643 | goto out; | 1264 | goto out; |
644 | } | 1265 | } |
645 | next = rb_entry(node, struct btrfs_free_space, offset_index); | 1266 | next = rb_entry(node, struct btrfs_free_space, offset_index); |
646 | 1267 | ||
647 | /* | 1268 | /* |
1269 | * we found a bitmap, so if this search doesn't result in a | ||
1270 | * cluster, we know to go and search again for the bitmaps and | ||
1271 | * start looking for space there | ||
1272 | */ | ||
1273 | if (next->bitmap) { | ||
1274 | if (!found_bitmap) | ||
1275 | offset = next->offset; | ||
1276 | found_bitmap = true; | ||
1277 | last = next; | ||
1278 | continue; | ||
1279 | } | ||
1280 | |||
1281 | /* | ||
648 | * we haven't filled the empty size and the window is | 1282 | * we haven't filled the empty size and the window is |
649 | * very large. reset and try again | 1283 | * very large. reset and try again |
650 | */ | 1284 | */ |
@@ -655,19 +1289,6 @@ again: | |||
655 | window_free = entry->bytes; | 1289 | window_free = entry->bytes; |
656 | last = entry; | 1290 | last = entry; |
657 | max_extent = 0; | 1291 | max_extent = 0; |
658 | total_retries++; | ||
659 | if (total_retries % 64 == 0) { | ||
660 | if (min_bytes >= (bytes + empty_size)) { | ||
661 | ret = -ENOSPC; | ||
662 | goto out; | ||
663 | } | ||
664 | /* | ||
665 | * grow our allocation a bit, we're not having | ||
666 | * much luck | ||
667 | */ | ||
668 | min_bytes *= 2; | ||
669 | goto again; | ||
670 | } | ||
671 | } else { | 1292 | } else { |
672 | last = next; | 1293 | last = next; |
673 | window_free += next->bytes; | 1294 | window_free += next->bytes; |
@@ -685,11 +1306,19 @@ again: | |||
685 | * The cluster includes an rbtree, but only uses the offset index | 1306 | * The cluster includes an rbtree, but only uses the offset index |
686 | * of each free space cache entry. | 1307 | * of each free space cache entry. |
687 | */ | 1308 | */ |
688 | while(1) { | 1309 | while (1) { |
689 | node = rb_next(&entry->offset_index); | 1310 | node = rb_next(&entry->offset_index); |
690 | unlink_free_space(block_group, entry); | 1311 | if (entry->bitmap && node) { |
1312 | entry = rb_entry(node, struct btrfs_free_space, | ||
1313 | offset_index); | ||
1314 | continue; | ||
1315 | } else if (entry->bitmap && !node) { | ||
1316 | break; | ||
1317 | } | ||
1318 | |||
1319 | rb_erase(&entry->offset_index, &block_group->free_space_offset); | ||
691 | ret = tree_insert_offset(&cluster->root, entry->offset, | 1320 | ret = tree_insert_offset(&cluster->root, entry->offset, |
692 | &entry->offset_index); | 1321 | &entry->offset_index, 0); |
693 | BUG_ON(ret); | 1322 | BUG_ON(ret); |
694 | 1323 | ||
695 | if (!node || entry == last) | 1324 | if (!node || entry == last) |
@@ -697,8 +1326,10 @@ again: | |||
697 | 1326 | ||
698 | entry = rb_entry(node, struct btrfs_free_space, offset_index); | 1327 | entry = rb_entry(node, struct btrfs_free_space, offset_index); |
699 | } | 1328 | } |
700 | ret = 0; | 1329 | |
701 | cluster->max_size = max_extent; | 1330 | cluster->max_size = max_extent; |
1331 | got_it: | ||
1332 | ret = 0; | ||
702 | atomic_inc(&block_group->count); | 1333 | atomic_inc(&block_group->count); |
703 | list_add_tail(&cluster->block_group_list, &block_group->cluster_list); | 1334 | list_add_tail(&cluster->block_group_list, &block_group->cluster_list); |
704 | cluster->block_group = block_group; | 1335 | cluster->block_group = block_group; |
@@ -718,6 +1349,7 @@ void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) | |||
718 | spin_lock_init(&cluster->refill_lock); | 1349 | spin_lock_init(&cluster->refill_lock); |
719 | cluster->root.rb_node = NULL; | 1350 | cluster->root.rb_node = NULL; |
720 | cluster->max_size = 0; | 1351 | cluster->max_size = 0; |
1352 | cluster->points_to_bitmap = false; | ||
721 | INIT_LIST_HEAD(&cluster->block_group_list); | 1353 | INIT_LIST_HEAD(&cluster->block_group_list); |
722 | cluster->block_group = NULL; | 1354 | cluster->block_group = NULL; |
723 | } | 1355 | } |
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h index 266fb8764054..890a8e79011b 100644 --- a/fs/btrfs/free-space-cache.h +++ b/fs/btrfs/free-space-cache.h | |||
@@ -19,6 +19,14 @@ | |||
19 | #ifndef __BTRFS_FREE_SPACE_CACHE | 19 | #ifndef __BTRFS_FREE_SPACE_CACHE |
20 | #define __BTRFS_FREE_SPACE_CACHE | 20 | #define __BTRFS_FREE_SPACE_CACHE |
21 | 21 | ||
22 | struct btrfs_free_space { | ||
23 | struct rb_node offset_index; | ||
24 | u64 offset; | ||
25 | u64 bytes; | ||
26 | unsigned long *bitmap; | ||
27 | struct list_head list; | ||
28 | }; | ||
29 | |||
22 | int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, | 30 | int btrfs_add_free_space(struct btrfs_block_group_cache *block_group, |
23 | u64 bytenr, u64 size); | 31 | u64 bytenr, u64 size); |
24 | int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, | 32 | int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8612b3a09811..272b9b2bea86 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/time.h> | 26 | #include <linux/time.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/string.h> | 28 | #include <linux/string.h> |
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/backing-dev.h> | 29 | #include <linux/backing-dev.h> |
31 | #include <linux/mpage.h> | 30 | #include <linux/mpage.h> |
32 | #include <linux/swap.h> | 31 | #include <linux/swap.h> |
@@ -2122,10 +2121,8 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
2122 | * any xattrs or acls | 2121 | * any xattrs or acls |
2123 | */ | 2122 | */ |
2124 | maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino); | 2123 | maybe_acls = acls_after_inode_item(leaf, path->slots[0], inode->i_ino); |
2125 | if (!maybe_acls) { | 2124 | if (!maybe_acls) |
2126 | BTRFS_I(inode)->i_acl = NULL; | 2125 | cache_no_acl(inode); |
2127 | BTRFS_I(inode)->i_default_acl = NULL; | ||
2128 | } | ||
2129 | 2126 | ||
2130 | BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, | 2127 | BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, |
2131 | alloc_group_block, 0); | 2128 | alloc_group_block, 0); |
@@ -2606,8 +2603,8 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | |||
2606 | if (root->ref_cows) | 2603 | if (root->ref_cows) |
2607 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); | 2604 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); |
2608 | path = btrfs_alloc_path(); | 2605 | path = btrfs_alloc_path(); |
2609 | path->reada = -1; | ||
2610 | BUG_ON(!path); | 2606 | BUG_ON(!path); |
2607 | path->reada = -1; | ||
2611 | 2608 | ||
2612 | /* FIXME, add redo link to tree so we don't leak on crash */ | 2609 | /* FIXME, add redo link to tree so we don't leak on crash */ |
2613 | key.objectid = inode->i_ino; | 2610 | key.objectid = inode->i_ino; |
@@ -3141,9 +3138,6 @@ static noinline void init_btrfs_i(struct inode *inode) | |||
3141 | { | 3138 | { |
3142 | struct btrfs_inode *bi = BTRFS_I(inode); | 3139 | struct btrfs_inode *bi = BTRFS_I(inode); |
3143 | 3140 | ||
3144 | bi->i_acl = BTRFS_ACL_NOT_CACHED; | ||
3145 | bi->i_default_acl = BTRFS_ACL_NOT_CACHED; | ||
3146 | |||
3147 | bi->generation = 0; | 3141 | bi->generation = 0; |
3148 | bi->sequence = 0; | 3142 | bi->sequence = 0; |
3149 | bi->last_trans = 0; | 3143 | bi->last_trans = 0; |
@@ -3585,12 +3579,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
3585 | owner = 1; | 3579 | owner = 1; |
3586 | BTRFS_I(inode)->block_group = | 3580 | BTRFS_I(inode)->block_group = |
3587 | btrfs_find_block_group(root, 0, alloc_hint, owner); | 3581 | btrfs_find_block_group(root, 0, alloc_hint, owner); |
3588 | if ((mode & S_IFREG)) { | ||
3589 | if (btrfs_test_opt(root, NODATASUM)) | ||
3590 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | ||
3591 | if (btrfs_test_opt(root, NODATACOW)) | ||
3592 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | ||
3593 | } | ||
3594 | 3582 | ||
3595 | key[0].objectid = objectid; | 3583 | key[0].objectid = objectid; |
3596 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); | 3584 | btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); |
@@ -3645,6 +3633,13 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, | |||
3645 | 3633 | ||
3646 | btrfs_inherit_iflags(inode, dir); | 3634 | btrfs_inherit_iflags(inode, dir); |
3647 | 3635 | ||
3636 | if ((mode & S_IFREG)) { | ||
3637 | if (btrfs_test_opt(root, NODATASUM)) | ||
3638 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; | ||
3639 | if (btrfs_test_opt(root, NODATACOW)) | ||
3640 | BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; | ||
3641 | } | ||
3642 | |||
3648 | insert_inode_hash(inode); | 3643 | insert_inode_hash(inode); |
3649 | inode_tree_add(inode); | 3644 | inode_tree_add(inode); |
3650 | return inode; | 3645 | return inode; |
@@ -4640,8 +4635,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
4640 | ei->last_trans = 0; | 4635 | ei->last_trans = 0; |
4641 | ei->logged_trans = 0; | 4636 | ei->logged_trans = 0; |
4642 | btrfs_ordered_inode_tree_init(&ei->ordered_tree); | 4637 | btrfs_ordered_inode_tree_init(&ei->ordered_tree); |
4643 | ei->i_acl = BTRFS_ACL_NOT_CACHED; | ||
4644 | ei->i_default_acl = BTRFS_ACL_NOT_CACHED; | ||
4645 | INIT_LIST_HEAD(&ei->i_orphan); | 4638 | INIT_LIST_HEAD(&ei->i_orphan); |
4646 | INIT_LIST_HEAD(&ei->ordered_operations); | 4639 | INIT_LIST_HEAD(&ei->ordered_operations); |
4647 | return &ei->vfs_inode; | 4640 | return &ei->vfs_inode; |
@@ -4655,13 +4648,6 @@ void btrfs_destroy_inode(struct inode *inode) | |||
4655 | WARN_ON(!list_empty(&inode->i_dentry)); | 4648 | WARN_ON(!list_empty(&inode->i_dentry)); |
4656 | WARN_ON(inode->i_data.nrpages); | 4649 | WARN_ON(inode->i_data.nrpages); |
4657 | 4650 | ||
4658 | if (BTRFS_I(inode)->i_acl && | ||
4659 | BTRFS_I(inode)->i_acl != BTRFS_ACL_NOT_CACHED) | ||
4660 | posix_acl_release(BTRFS_I(inode)->i_acl); | ||
4661 | if (BTRFS_I(inode)->i_default_acl && | ||
4662 | BTRFS_I(inode)->i_default_acl != BTRFS_ACL_NOT_CACHED) | ||
4663 | posix_acl_release(BTRFS_I(inode)->i_default_acl); | ||
4664 | |||
4665 | /* | 4651 | /* |
4666 | * Make sure we're properly removed from the ordered operation | 4652 | * Make sure we're properly removed from the ordered operation |
4667 | * lists. | 4653 | * lists. |
@@ -4799,8 +4785,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
4799 | * and the replacement file is large. Start IO on it now so | 4785 | * and the replacement file is large. Start IO on it now so |
4800 | * we don't add too much work to the end of the transaction | 4786 | * we don't add too much work to the end of the transaction |
4801 | */ | 4787 | */ |
4802 | if (new_inode && old_inode && S_ISREG(old_inode->i_mode) && | 4788 | if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size && |
4803 | new_inode->i_size && | ||
4804 | old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT) | 4789 | old_inode->i_size > BTRFS_ORDERED_OPERATIONS_FLUSH_LIMIT) |
4805 | filemap_flush(old_inode->i_mapping); | 4790 | filemap_flush(old_inode->i_mapping); |
4806 | 4791 | ||
@@ -5096,6 +5081,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5096 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; | 5081 | u64 mask = BTRFS_I(inode)->root->sectorsize - 1; |
5097 | struct extent_map *em; | 5082 | struct extent_map *em; |
5098 | struct btrfs_trans_handle *trans; | 5083 | struct btrfs_trans_handle *trans; |
5084 | struct btrfs_root *root; | ||
5099 | int ret; | 5085 | int ret; |
5100 | 5086 | ||
5101 | alloc_start = offset & ~mask; | 5087 | alloc_start = offset & ~mask; |
@@ -5114,6 +5100,13 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5114 | goto out; | 5100 | goto out; |
5115 | } | 5101 | } |
5116 | 5102 | ||
5103 | root = BTRFS_I(inode)->root; | ||
5104 | |||
5105 | ret = btrfs_check_data_free_space(root, inode, | ||
5106 | alloc_end - alloc_start); | ||
5107 | if (ret) | ||
5108 | goto out; | ||
5109 | |||
5117 | locked_end = alloc_end - 1; | 5110 | locked_end = alloc_end - 1; |
5118 | while (1) { | 5111 | while (1) { |
5119 | struct btrfs_ordered_extent *ordered; | 5112 | struct btrfs_ordered_extent *ordered; |
@@ -5121,7 +5114,7 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5121 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); | 5114 | trans = btrfs_start_transaction(BTRFS_I(inode)->root, 1); |
5122 | if (!trans) { | 5115 | if (!trans) { |
5123 | ret = -EIO; | 5116 | ret = -EIO; |
5124 | goto out; | 5117 | goto out_free; |
5125 | } | 5118 | } |
5126 | 5119 | ||
5127 | /* the extent lock is ordered inside the running | 5120 | /* the extent lock is ordered inside the running |
@@ -5182,6 +5175,8 @@ static long btrfs_fallocate(struct inode *inode, int mode, | |||
5182 | GFP_NOFS); | 5175 | GFP_NOFS); |
5183 | 5176 | ||
5184 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); | 5177 | btrfs_end_transaction(trans, BTRFS_I(inode)->root); |
5178 | out_free: | ||
5179 | btrfs_free_reserved_data_space(root, inode, alloc_end - alloc_start); | ||
5185 | out: | 5180 | out: |
5186 | mutex_unlock(&inode->i_mutex); | 5181 | mutex_unlock(&inode->i_mutex); |
5187 | return ret; | 5182 | return ret; |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index eff18f5b5362..bd88f25889f7 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/time.h> | 27 | #include <linux/time.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | #include <linux/smp_lock.h> | ||
31 | #include <linux/backing-dev.h> | 30 | #include <linux/backing-dev.h> |
32 | #include <linux/mount.h> | 31 | #include <linux/mount.h> |
33 | #include <linux/mpage.h> | 32 | #include <linux/mpage.h> |
@@ -1028,7 +1027,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1028 | struct btrfs_file_extent_item); | 1027 | struct btrfs_file_extent_item); |
1029 | comp = btrfs_file_extent_compression(leaf, extent); | 1028 | comp = btrfs_file_extent_compression(leaf, extent); |
1030 | type = btrfs_file_extent_type(leaf, extent); | 1029 | type = btrfs_file_extent_type(leaf, extent); |
1031 | if (type == BTRFS_FILE_EXTENT_REG) { | 1030 | if (type == BTRFS_FILE_EXTENT_REG || |
1031 | type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
1032 | disko = btrfs_file_extent_disk_bytenr(leaf, | 1032 | disko = btrfs_file_extent_disk_bytenr(leaf, |
1033 | extent); | 1033 | extent); |
1034 | diskl = btrfs_file_extent_disk_num_bytes(leaf, | 1034 | diskl = btrfs_file_extent_disk_num_bytes(leaf, |
@@ -1051,7 +1051,8 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1051 | new_key.objectid = inode->i_ino; | 1051 | new_key.objectid = inode->i_ino; |
1052 | new_key.offset = key.offset + destoff - off; | 1052 | new_key.offset = key.offset + destoff - off; |
1053 | 1053 | ||
1054 | if (type == BTRFS_FILE_EXTENT_REG) { | 1054 | if (type == BTRFS_FILE_EXTENT_REG || |
1055 | type == BTRFS_FILE_EXTENT_PREALLOC) { | ||
1055 | ret = btrfs_insert_empty_item(trans, root, path, | 1056 | ret = btrfs_insert_empty_item(trans, root, path, |
1056 | &new_key, size); | 1057 | &new_key, size); |
1057 | if (ret) | 1058 | if (ret) |
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c index 6d6523da0a30..0d126be22b63 100644 --- a/fs/btrfs/print-tree.c +++ b/fs/btrfs/print-tree.c | |||
@@ -309,7 +309,7 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c) | |||
309 | } | 309 | } |
310 | printk(KERN_INFO "node %llu level %d total ptrs %d free spc %u\n", | 310 | printk(KERN_INFO "node %llu level %d total ptrs %d free spc %u\n", |
311 | (unsigned long long)btrfs_header_bytenr(c), | 311 | (unsigned long long)btrfs_header_bytenr(c), |
312 | btrfs_header_level(c), nr, | 312 | level, nr, |
313 | (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr); | 313 | (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr); |
314 | for (i = 0; i < nr; i++) { | 314 | for (i = 0; i < nr; i++) { |
315 | btrfs_node_key_to_cpu(c, &key, i); | 315 | btrfs_node_key_to_cpu(c, &key, i); |
@@ -326,10 +326,10 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c) | |||
326 | btrfs_level_size(root, level - 1), | 326 | btrfs_level_size(root, level - 1), |
327 | btrfs_node_ptr_generation(c, i)); | 327 | btrfs_node_ptr_generation(c, i)); |
328 | if (btrfs_is_leaf(next) && | 328 | if (btrfs_is_leaf(next) && |
329 | btrfs_header_level(c) != 1) | 329 | level != 1) |
330 | BUG(); | 330 | BUG(); |
331 | if (btrfs_header_level(next) != | 331 | if (btrfs_header_level(next) != |
332 | btrfs_header_level(c) - 1) | 332 | level - 1) |
333 | BUG(); | 333 | BUG(); |
334 | btrfs_print_tree(root, next); | 334 | btrfs_print_tree(root, next); |
335 | free_extent_buffer(next); | 335 | free_extent_buffer(next); |
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c index b23dc209ae10..c04f7f212602 100644 --- a/fs/btrfs/relocation.c +++ b/fs/btrfs/relocation.c | |||
@@ -670,6 +670,8 @@ again: | |||
670 | err = ret; | 670 | err = ret; |
671 | goto out; | 671 | goto out; |
672 | } | 672 | } |
673 | if (ret > 0 && path2->slots[level] > 0) | ||
674 | path2->slots[level]--; | ||
673 | 675 | ||
674 | eb = path2->nodes[level]; | 676 | eb = path2->nodes[level]; |
675 | WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) != | 677 | WARN_ON(btrfs_node_blockptr(eb, path2->slots[level]) != |
@@ -1609,6 +1611,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, | |||
1609 | BUG_ON(level == 0); | 1611 | BUG_ON(level == 0); |
1610 | path->lowest_level = level; | 1612 | path->lowest_level = level; |
1611 | ret = btrfs_search_slot(NULL, reloc_root, &key, path, 0, 0); | 1613 | ret = btrfs_search_slot(NULL, reloc_root, &key, path, 0, 0); |
1614 | path->lowest_level = 0; | ||
1612 | if (ret < 0) { | 1615 | if (ret < 0) { |
1613 | btrfs_free_path(path); | 1616 | btrfs_free_path(path); |
1614 | return ret; | 1617 | return ret; |
@@ -1788,7 +1791,7 @@ static void merge_func(struct btrfs_work *work) | |||
1788 | btrfs_end_transaction(trans, root); | 1791 | btrfs_end_transaction(trans, root); |
1789 | } | 1792 | } |
1790 | 1793 | ||
1791 | btrfs_drop_dead_root(reloc_root); | 1794 | btrfs_drop_snapshot(reloc_root, 0); |
1792 | 1795 | ||
1793 | if (atomic_dec_and_test(async->num_pending)) | 1796 | if (atomic_dec_and_test(async->num_pending)) |
1794 | complete(async->done); | 1797 | complete(async->done); |
@@ -2075,9 +2078,6 @@ static int do_relocation(struct btrfs_trans_handle *trans, | |||
2075 | 2078 | ||
2076 | ret = btrfs_drop_subtree(trans, root, eb, upper->eb); | 2079 | ret = btrfs_drop_subtree(trans, root, eb, upper->eb); |
2077 | BUG_ON(ret); | 2080 | BUG_ON(ret); |
2078 | |||
2079 | btrfs_tree_unlock(eb); | ||
2080 | free_extent_buffer(eb); | ||
2081 | } | 2081 | } |
2082 | if (!lowest) { | 2082 | if (!lowest) { |
2083 | btrfs_tree_unlock(upper->eb); | 2083 | btrfs_tree_unlock(upper->eb); |
@@ -2553,8 +2553,13 @@ int relocate_inode_pages(struct inode *inode, u64 start, u64 len) | |||
2553 | last_index = (start + len - 1) >> PAGE_CACHE_SHIFT; | 2553 | last_index = (start + len - 1) >> PAGE_CACHE_SHIFT; |
2554 | 2554 | ||
2555 | /* make sure the dirty trick played by the caller work */ | 2555 | /* make sure the dirty trick played by the caller work */ |
2556 | ret = invalidate_inode_pages2_range(inode->i_mapping, | 2556 | while (1) { |
2557 | first_index, last_index); | 2557 | ret = invalidate_inode_pages2_range(inode->i_mapping, |
2558 | first_index, last_index); | ||
2559 | if (ret != -EBUSY) | ||
2560 | break; | ||
2561 | schedule_timeout(HZ/10); | ||
2562 | } | ||
2558 | if (ret) | 2563 | if (ret) |
2559 | goto out_unlock; | 2564 | goto out_unlock; |
2560 | 2565 | ||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 9f179d4832d5..6d6d06cb6dfc 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/seq_file.h> | 27 | #include <linux/seq_file.h> |
28 | #include <linux/string.h> | 28 | #include <linux/string.h> |
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/backing-dev.h> | 29 | #include <linux/backing-dev.h> |
31 | #include <linux/mount.h> | 30 | #include <linux/mount.h> |
32 | #include <linux/mpage.h> | 31 | #include <linux/mpage.h> |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 2e177d7f4bb9..cdbb5022da52 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -40,6 +40,12 @@ static noinline void put_transaction(struct btrfs_transaction *transaction) | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | static noinline void switch_commit_root(struct btrfs_root *root) | ||
44 | { | ||
45 | free_extent_buffer(root->commit_root); | ||
46 | root->commit_root = btrfs_root_node(root); | ||
47 | } | ||
48 | |||
43 | /* | 49 | /* |
44 | * either allocate a new transaction or hop into the existing one | 50 | * either allocate a new transaction or hop into the existing one |
45 | */ | 51 | */ |
@@ -444,9 +450,6 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, | |||
444 | 450 | ||
445 | btrfs_write_dirty_block_groups(trans, root); | 451 | btrfs_write_dirty_block_groups(trans, root); |
446 | 452 | ||
447 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | ||
448 | BUG_ON(ret); | ||
449 | |||
450 | while (1) { | 453 | while (1) { |
451 | old_root_bytenr = btrfs_root_bytenr(&root->root_item); | 454 | old_root_bytenr = btrfs_root_bytenr(&root->root_item); |
452 | if (old_root_bytenr == root->node->start) | 455 | if (old_root_bytenr == root->node->start) |
@@ -457,13 +460,14 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans, | |||
457 | &root->root_key, | 460 | &root->root_key, |
458 | &root->root_item); | 461 | &root->root_item); |
459 | BUG_ON(ret); | 462 | BUG_ON(ret); |
460 | btrfs_write_dirty_block_groups(trans, root); | ||
461 | 463 | ||
462 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | 464 | ret = btrfs_write_dirty_block_groups(trans, root); |
463 | BUG_ON(ret); | 465 | BUG_ON(ret); |
464 | } | 466 | } |
465 | free_extent_buffer(root->commit_root); | 467 | |
466 | root->commit_root = btrfs_root_node(root); | 468 | if (root != root->fs_info->extent_root) |
469 | switch_commit_root(root); | ||
470 | |||
467 | return 0; | 471 | return 0; |
468 | } | 472 | } |
469 | 473 | ||
@@ -495,10 +499,12 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, | |||
495 | root = list_entry(next, struct btrfs_root, dirty_list); | 499 | root = list_entry(next, struct btrfs_root, dirty_list); |
496 | 500 | ||
497 | update_cowonly_root(trans, root); | 501 | update_cowonly_root(trans, root); |
498 | |||
499 | ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); | ||
500 | BUG_ON(ret); | ||
501 | } | 502 | } |
503 | |||
504 | down_write(&fs_info->extent_commit_sem); | ||
505 | switch_commit_root(fs_info->extent_root); | ||
506 | up_write(&fs_info->extent_commit_sem); | ||
507 | |||
502 | return 0; | 508 | return 0; |
503 | } | 509 | } |
504 | 510 | ||
@@ -543,13 +549,12 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | |||
543 | btrfs_free_log(trans, root); | 549 | btrfs_free_log(trans, root); |
544 | btrfs_update_reloc_root(trans, root); | 550 | btrfs_update_reloc_root(trans, root); |
545 | 551 | ||
546 | if (root->commit_root == root->node) | 552 | if (root->commit_root != root->node) { |
547 | continue; | 553 | switch_commit_root(root); |
548 | 554 | btrfs_set_root_node(&root->root_item, | |
549 | free_extent_buffer(root->commit_root); | 555 | root->node); |
550 | root->commit_root = btrfs_root_node(root); | 556 | } |
551 | 557 | ||
552 | btrfs_set_root_node(&root->root_item, root->node); | ||
553 | err = btrfs_update_root(trans, fs_info->tree_root, | 558 | err = btrfs_update_root(trans, fs_info->tree_root, |
554 | &root->root_key, | 559 | &root->root_key, |
555 | &root->root_item); | 560 | &root->root_item); |
@@ -593,6 +598,7 @@ int btrfs_defrag_root(struct btrfs_root *root, int cacheonly) | |||
593 | return 0; | 598 | return 0; |
594 | } | 599 | } |
595 | 600 | ||
601 | #if 0 | ||
596 | /* | 602 | /* |
597 | * when dropping snapshots, we generate a ton of delayed refs, and it makes | 603 | * when dropping snapshots, we generate a ton of delayed refs, and it makes |
598 | * sense not to join the transaction while it is trying to flush the current | 604 | * sense not to join the transaction while it is trying to flush the current |
@@ -681,6 +687,7 @@ int btrfs_drop_dead_root(struct btrfs_root *root) | |||
681 | btrfs_btree_balance_dirty(tree_root, nr); | 687 | btrfs_btree_balance_dirty(tree_root, nr); |
682 | return ret; | 688 | return ret; |
683 | } | 689 | } |
690 | #endif | ||
684 | 691 | ||
685 | /* | 692 | /* |
686 | * new snapshots need to be created at a very specific time in the | 693 | * new snapshots need to be created at a very specific time in the |
@@ -850,6 +857,16 @@ static void update_super_roots(struct btrfs_root *root) | |||
850 | super->root_level = root_item->level; | 857 | super->root_level = root_item->level; |
851 | } | 858 | } |
852 | 859 | ||
860 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | ||
861 | { | ||
862 | int ret = 0; | ||
863 | spin_lock(&info->new_trans_lock); | ||
864 | if (info->running_transaction) | ||
865 | ret = info->running_transaction->in_commit; | ||
866 | spin_unlock(&info->new_trans_lock); | ||
867 | return ret; | ||
868 | } | ||
869 | |||
853 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 870 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
854 | struct btrfs_root *root) | 871 | struct btrfs_root *root) |
855 | { | 872 | { |
@@ -941,9 +958,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
941 | 958 | ||
942 | mutex_unlock(&root->fs_info->trans_mutex); | 959 | mutex_unlock(&root->fs_info->trans_mutex); |
943 | 960 | ||
944 | if (flush_on_commit || snap_pending) { | 961 | if (flush_on_commit) { |
945 | if (flush_on_commit) | 962 | btrfs_start_delalloc_inodes(root); |
946 | btrfs_start_delalloc_inodes(root); | 963 | ret = btrfs_wait_ordered_extents(root, 0); |
964 | BUG_ON(ret); | ||
965 | } else if (snap_pending) { | ||
947 | ret = btrfs_wait_ordered_extents(root, 1); | 966 | ret = btrfs_wait_ordered_extents(root, 1); |
948 | BUG_ON(ret); | 967 | BUG_ON(ret); |
949 | } | 968 | } |
@@ -1007,15 +1026,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1007 | 1026 | ||
1008 | btrfs_set_root_node(&root->fs_info->tree_root->root_item, | 1027 | btrfs_set_root_node(&root->fs_info->tree_root->root_item, |
1009 | root->fs_info->tree_root->node); | 1028 | root->fs_info->tree_root->node); |
1010 | free_extent_buffer(root->fs_info->tree_root->commit_root); | 1029 | switch_commit_root(root->fs_info->tree_root); |
1011 | root->fs_info->tree_root->commit_root = | ||
1012 | btrfs_root_node(root->fs_info->tree_root); | ||
1013 | 1030 | ||
1014 | btrfs_set_root_node(&root->fs_info->chunk_root->root_item, | 1031 | btrfs_set_root_node(&root->fs_info->chunk_root->root_item, |
1015 | root->fs_info->chunk_root->node); | 1032 | root->fs_info->chunk_root->node); |
1016 | free_extent_buffer(root->fs_info->chunk_root->commit_root); | 1033 | switch_commit_root(root->fs_info->chunk_root); |
1017 | root->fs_info->chunk_root->commit_root = | ||
1018 | btrfs_root_node(root->fs_info->chunk_root); | ||
1019 | 1034 | ||
1020 | update_super_roots(root); | 1035 | update_super_roots(root); |
1021 | 1036 | ||
@@ -1055,6 +1070,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1055 | cur_trans->commit_done = 1; | 1070 | cur_trans->commit_done = 1; |
1056 | 1071 | ||
1057 | root->fs_info->last_trans_committed = cur_trans->transid; | 1072 | root->fs_info->last_trans_committed = cur_trans->transid; |
1073 | |||
1058 | wake_up(&cur_trans->commit_wait); | 1074 | wake_up(&cur_trans->commit_wait); |
1059 | 1075 | ||
1060 | put_transaction(cur_trans); | 1076 | put_transaction(cur_trans); |
@@ -1081,7 +1097,7 @@ int btrfs_clean_old_snapshots(struct btrfs_root *root) | |||
1081 | while (!list_empty(&list)) { | 1097 | while (!list_empty(&list)) { |
1082 | root = list_entry(list.next, struct btrfs_root, root_list); | 1098 | root = list_entry(list.next, struct btrfs_root, root_list); |
1083 | list_del_init(&root->root_list); | 1099 | list_del_init(&root->root_list); |
1084 | btrfs_drop_dead_root(root); | 1100 | btrfs_drop_snapshot(root, 0); |
1085 | } | 1101 | } |
1086 | return 0; | 1102 | return 0; |
1087 | } | 1103 | } |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 961c3ee5a2e1..663c67404918 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -107,4 +107,5 @@ int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, | |||
107 | struct btrfs_root *root); | 107 | struct btrfs_root *root); |
108 | int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, | 108 | int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, |
109 | struct extent_io_tree *dirty_pages); | 109 | struct extent_io_tree *dirty_pages); |
110 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info); | ||
110 | #endif | 111 | #endif |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index c13922206d1b..d91b0de7c502 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -797,7 +797,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans, | |||
797 | return -ENOENT; | 797 | return -ENOENT; |
798 | 798 | ||
799 | inode = read_one_inode(root, key->objectid); | 799 | inode = read_one_inode(root, key->objectid); |
800 | BUG_ON(!dir); | 800 | BUG_ON(!inode); |
801 | 801 | ||
802 | ref_ptr = btrfs_item_ptr_offset(eb, slot); | 802 | ref_ptr = btrfs_item_ptr_offset(eb, slot); |
803 | ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); | 803 | ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 3ab80e9cd767..5dbefd11b4af 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -721,7 +721,8 @@ error: | |||
721 | */ | 721 | */ |
722 | static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans, | 722 | static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans, |
723 | struct btrfs_device *device, | 723 | struct btrfs_device *device, |
724 | u64 num_bytes, u64 *start) | 724 | u64 num_bytes, u64 *start, |
725 | u64 *max_avail) | ||
725 | { | 726 | { |
726 | struct btrfs_key key; | 727 | struct btrfs_key key; |
727 | struct btrfs_root *root = device->dev_root; | 728 | struct btrfs_root *root = device->dev_root; |
@@ -758,9 +759,13 @@ static noinline int find_free_dev_extent(struct btrfs_trans_handle *trans, | |||
758 | ret = btrfs_search_slot(trans, root, &key, path, 0, 0); | 759 | ret = btrfs_search_slot(trans, root, &key, path, 0, 0); |
759 | if (ret < 0) | 760 | if (ret < 0) |
760 | goto error; | 761 | goto error; |
761 | ret = btrfs_previous_item(root, path, 0, key.type); | 762 | if (ret > 0) { |
762 | if (ret < 0) | 763 | ret = btrfs_previous_item(root, path, key.objectid, key.type); |
763 | goto error; | 764 | if (ret < 0) |
765 | goto error; | ||
766 | if (ret > 0) | ||
767 | start_found = 1; | ||
768 | } | ||
764 | l = path->nodes[0]; | 769 | l = path->nodes[0]; |
765 | btrfs_item_key_to_cpu(l, &key, path->slots[0]); | 770 | btrfs_item_key_to_cpu(l, &key, path->slots[0]); |
766 | while (1) { | 771 | while (1) { |
@@ -803,6 +808,10 @@ no_more_items: | |||
803 | if (last_byte < search_start) | 808 | if (last_byte < search_start) |
804 | last_byte = search_start; | 809 | last_byte = search_start; |
805 | hole_size = key.offset - last_byte; | 810 | hole_size = key.offset - last_byte; |
811 | |||
812 | if (hole_size > *max_avail) | ||
813 | *max_avail = hole_size; | ||
814 | |||
806 | if (key.offset > last_byte && | 815 | if (key.offset > last_byte && |
807 | hole_size >= num_bytes) { | 816 | hole_size >= num_bytes) { |
808 | *start = last_byte; | 817 | *start = last_byte; |
@@ -1621,6 +1630,7 @@ static int __btrfs_grow_device(struct btrfs_trans_handle *trans, | |||
1621 | device->fs_devices->total_rw_bytes += diff; | 1630 | device->fs_devices->total_rw_bytes += diff; |
1622 | 1631 | ||
1623 | device->total_bytes = new_size; | 1632 | device->total_bytes = new_size; |
1633 | device->disk_total_bytes = new_size; | ||
1624 | btrfs_clear_space_info_full(device->dev_root->fs_info); | 1634 | btrfs_clear_space_info_full(device->dev_root->fs_info); |
1625 | 1635 | ||
1626 | return btrfs_update_device(trans, device); | 1636 | return btrfs_update_device(trans, device); |
@@ -2007,7 +2017,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
2007 | goto done; | 2017 | goto done; |
2008 | if (ret) { | 2018 | if (ret) { |
2009 | ret = 0; | 2019 | ret = 0; |
2010 | goto done; | 2020 | break; |
2011 | } | 2021 | } |
2012 | 2022 | ||
2013 | l = path->nodes[0]; | 2023 | l = path->nodes[0]; |
@@ -2015,7 +2025,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) | |||
2015 | btrfs_item_key_to_cpu(l, &key, path->slots[0]); | 2025 | btrfs_item_key_to_cpu(l, &key, path->slots[0]); |
2016 | 2026 | ||
2017 | if (key.objectid != device->devid) | 2027 | if (key.objectid != device->devid) |
2018 | goto done; | 2028 | break; |
2019 | 2029 | ||
2020 | dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); | 2030 | dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); |
2021 | length = btrfs_dev_extent_length(l, dev_extent); | 2031 | length = btrfs_dev_extent_length(l, dev_extent); |
@@ -2171,6 +2181,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
2171 | max_chunk_size); | 2181 | max_chunk_size); |
2172 | 2182 | ||
2173 | again: | 2183 | again: |
2184 | max_avail = 0; | ||
2174 | if (!map || map->num_stripes != num_stripes) { | 2185 | if (!map || map->num_stripes != num_stripes) { |
2175 | kfree(map); | 2186 | kfree(map); |
2176 | map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); | 2187 | map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); |
@@ -2219,7 +2230,8 @@ again: | |||
2219 | 2230 | ||
2220 | if (device->in_fs_metadata && avail >= min_free) { | 2231 | if (device->in_fs_metadata && avail >= min_free) { |
2221 | ret = find_free_dev_extent(trans, device, | 2232 | ret = find_free_dev_extent(trans, device, |
2222 | min_free, &dev_offset); | 2233 | min_free, &dev_offset, |
2234 | &max_avail); | ||
2223 | if (ret == 0) { | 2235 | if (ret == 0) { |
2224 | list_move_tail(&device->dev_alloc_list, | 2236 | list_move_tail(&device->dev_alloc_list, |
2225 | &private_devs); | 2237 | &private_devs); |
@@ -2795,26 +2807,6 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree, | |||
2795 | } | 2807 | } |
2796 | } | 2808 | } |
2797 | 2809 | ||
2798 | for (i = 0; i > nr; i++) { | ||
2799 | struct btrfs_multi_bio *multi; | ||
2800 | struct btrfs_bio_stripe *stripe; | ||
2801 | int ret; | ||
2802 | |||
2803 | length = 1; | ||
2804 | ret = btrfs_map_block(map_tree, WRITE, buf[i], | ||
2805 | &length, &multi, 0); | ||
2806 | BUG_ON(ret); | ||
2807 | |||
2808 | stripe = multi->stripes; | ||
2809 | for (j = 0; j < multi->num_stripes; j++) { | ||
2810 | if (stripe->physical >= physical && | ||
2811 | physical < stripe->physical + length) | ||
2812 | break; | ||
2813 | } | ||
2814 | BUG_ON(j >= multi->num_stripes); | ||
2815 | kfree(multi); | ||
2816 | } | ||
2817 | |||
2818 | *logical = buf; | 2810 | *logical = buf; |
2819 | *naddrs = nr; | 2811 | *naddrs = nr; |
2820 | *stripe_len = map->stripe_len; | 2812 | *stripe_len = map->stripe_len; |
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index ecfbce836d32..3e2b90eaa239 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c | |||
@@ -208,7 +208,7 @@ int btrfs_zlib_compress_pages(struct address_space *mapping, | |||
208 | *total_in = 0; | 208 | *total_in = 0; |
209 | 209 | ||
210 | workspace = find_zlib_workspace(); | 210 | workspace = find_zlib_workspace(); |
211 | if (!workspace) | 211 | if (IS_ERR(workspace)) |
212 | return -1; | 212 | return -1; |
213 | 213 | ||
214 | if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { | 214 | if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) { |
@@ -366,7 +366,7 @@ int btrfs_zlib_decompress_biovec(struct page **pages_in, | |||
366 | char *kaddr; | 366 | char *kaddr; |
367 | 367 | ||
368 | workspace = find_zlib_workspace(); | 368 | workspace = find_zlib_workspace(); |
369 | if (!workspace) | 369 | if (IS_ERR(workspace)) |
370 | return -ENOMEM; | 370 | return -ENOMEM; |
371 | 371 | ||
372 | data_in = kmap(pages_in[page_in_index]); | 372 | data_in = kmap(pages_in[page_in_index]); |
@@ -547,7 +547,7 @@ int btrfs_zlib_decompress(unsigned char *data_in, | |||
547 | return -ENOMEM; | 547 | return -ENOMEM; |
548 | 548 | ||
549 | workspace = find_zlib_workspace(); | 549 | workspace = find_zlib_workspace(); |
550 | if (!workspace) | 550 | if (IS_ERR(workspace)) |
551 | return -ENOMEM; | 551 | return -ENOMEM; |
552 | 552 | ||
553 | workspace->inf_strm.next_in = data_in; | 553 | workspace->inf_strm.next_in = data_in; |
diff --git a/fs/char_dev.c b/fs/char_dev.c index b7c9d5187a75..a173551e19d7 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/major.h> | 13 | #include <linux/major.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/smp_lock.h> | ||
17 | #include <linux/seq_file.h> | 16 | #include <linux/seq_file.h> |
18 | 17 | ||
19 | #include <linux/kobject.h> | 18 | #include <linux/kobject.h> |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index b48689839428..e85b1e4389e0 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,10 @@ | |||
1 | Version 1.60 | ||
2 | ------------- | ||
3 | Fix memory leak in reconnect. Fix oops in DFS mount error path. | ||
4 | Set s_maxbytes to smaller (the max that vfs can handle) so that | ||
5 | sendfile will now work over cifs mounts again. Add noforcegid | ||
6 | and noforceuid mount parameters. | ||
7 | |||
1 | Version 1.59 | 8 | Version 1.59 |
2 | ------------ | 9 | ------------ |
3 | Client uses server inode numbers (which are persistent) rather than | 10 | Client uses server inode numbers (which are persistent) rather than |
@@ -5,7 +12,11 @@ client generated ones by default (mount option "serverino" turned | |||
5 | on by default if server supports it). Add forceuid and forcegid | 12 | on by default if server supports it). Add forceuid and forcegid |
6 | mount options (so that when negotiating unix extensions specifying | 13 | mount options (so that when negotiating unix extensions specifying |
7 | which uid mounted does not immediately force the server's reported | 14 | which uid mounted does not immediately force the server's reported |
8 | uids to be overridden). | 15 | uids to be overridden). Add support for scope mount parm. Improve |
16 | hard link detection to use same inode for both. Do not set | ||
17 | read-only dos attribute on directories (for chmod) since Windows | ||
18 | explorer special cases this attribute bit for directories for | ||
19 | a different purpose. | ||
9 | 20 | ||
10 | Version 1.58 | 21 | Version 1.58 |
11 | ------------ | 22 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index ad92921dbde4..79c1a93400be 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -262,11 +262,11 @@ A partial list of the supported mount options follows: | |||
262 | mount. | 262 | mount. |
263 | domain Set the SMB/CIFS workgroup name prepended to the | 263 | domain Set the SMB/CIFS workgroup name prepended to the |
264 | username during CIFS session establishment | 264 | username during CIFS session establishment |
265 | forceuid Set the default uid for inodes based on the uid | 265 | forceuid Set the default uid for inodes to the uid |
266 | passed in. For mounts to servers | 266 | passed in on mount. For mounts to servers |
267 | which do support the CIFS Unix extensions, such as a | 267 | which do support the CIFS Unix extensions, such as a |
268 | properly configured Samba server, the server provides | 268 | properly configured Samba server, the server provides |
269 | the uid, gid and mode so this parameter should not be | 269 | the uid, gid and mode so this parameter should not be |
270 | specified unless the server and clients uid and gid | 270 | specified unless the server and clients uid and gid |
271 | numbering differ. If the server and client are in the | 271 | numbering differ. If the server and client are in the |
272 | same domain (e.g. running winbind or nss_ldap) and | 272 | same domain (e.g. running winbind or nss_ldap) and |
@@ -278,11 +278,7 @@ A partial list of the supported mount options follows: | |||
278 | of existing files will be the uid (gid) of the person | 278 | of existing files will be the uid (gid) of the person |
279 | who executed the mount (root, except when mount.cifs | 279 | who executed the mount (root, except when mount.cifs |
280 | is configured setuid for user mounts) unless the "uid=" | 280 | is configured setuid for user mounts) unless the "uid=" |
281 | (gid) mount option is specified. For the uid (gid) of newly | 281 | (gid) mount option is specified. Also note that permission |
282 | created files and directories, ie files created since | ||
283 | the last mount of the server share, the expected uid | ||
284 | (gid) is cached as long as the inode remains in | ||
285 | memory on the client. Also note that permission | ||
286 | checks (authorization checks) on accesses to a file occur | 282 | checks (authorization checks) on accesses to a file occur |
287 | at the server, but there are cases in which an administrator | 283 | at the server, but there are cases in which an administrator |
288 | may want to restrict at the client as well. For those | 284 | may want to restrict at the client as well. For those |
@@ -290,12 +286,15 @@ A partial list of the supported mount options follows: | |||
290 | (such as Windows), permissions can also be checked at the | 286 | (such as Windows), permissions can also be checked at the |
291 | client, and a crude form of client side permission checking | 287 | client, and a crude form of client side permission checking |
292 | can be enabled by specifying file_mode and dir_mode on | 288 | can be enabled by specifying file_mode and dir_mode on |
293 | the client. Note that the mount.cifs helper must be | 289 | the client. (default) |
294 | at version 1.10 or higher to support specifying the uid | 290 | forcegid (similar to above but for the groupid instead of uid) (default) |
295 | (or gid) in non-numeric form. | 291 | noforceuid Fill in file owner information (uid) by requesting it from |
296 | forcegid (similar to above but for the groupid instead of uid) | 292 | the server if possible. With this option, the value given in |
293 | the uid= option (on mount) will only be used if the server | ||
294 | can not support returning uids on inodes. | ||
295 | noforcegid (similar to above but for the group owner, gid, instead of uid) | ||
297 | uid Set the default uid for inodes, and indicate to the | 296 | uid Set the default uid for inodes, and indicate to the |
298 | cifs kernel driver which local user mounted . If the server | 297 | cifs kernel driver which local user mounted. If the server |
299 | supports the unix extensions the default uid is | 298 | supports the unix extensions the default uid is |
300 | not used to fill in the owner fields of inodes (files) | 299 | not used to fill in the owner fields of inodes (files) |
301 | unless the "forceuid" parameter is specified. | 300 | unless the "forceuid" parameter is specified. |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 1b09f1670061..20692fbfdb24 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #define ASN1_OJI 6 /* Object Identifier */ | 49 | #define ASN1_OJI 6 /* Object Identifier */ |
50 | #define ASN1_OJD 7 /* Object Description */ | 50 | #define ASN1_OJD 7 /* Object Description */ |
51 | #define ASN1_EXT 8 /* External */ | 51 | #define ASN1_EXT 8 /* External */ |
52 | #define ASN1_ENUM 10 /* Enumerated */ | ||
52 | #define ASN1_SEQ 16 /* Sequence */ | 53 | #define ASN1_SEQ 16 /* Sequence */ |
53 | #define ASN1_SET 17 /* Set */ | 54 | #define ASN1_SET 17 /* Set */ |
54 | #define ASN1_NUMSTR 18 /* Numerical String */ | 55 | #define ASN1_NUMSTR 18 /* Numerical String */ |
@@ -78,10 +79,12 @@ | |||
78 | #define SPNEGO_OID_LEN 7 | 79 | #define SPNEGO_OID_LEN 7 |
79 | #define NTLMSSP_OID_LEN 10 | 80 | #define NTLMSSP_OID_LEN 10 |
80 | #define KRB5_OID_LEN 7 | 81 | #define KRB5_OID_LEN 7 |
82 | #define KRB5U2U_OID_LEN 8 | ||
81 | #define MSKRB5_OID_LEN 7 | 83 | #define MSKRB5_OID_LEN 7 |
82 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; | 84 | static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; |
83 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; | 85 | static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; |
84 | static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; | 86 | static unsigned long KRB5_OID[7] = { 1, 2, 840, 113554, 1, 2, 2 }; |
87 | static unsigned long KRB5U2U_OID[8] = { 1, 2, 840, 113554, 1, 2, 2, 3 }; | ||
85 | static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 }; | 88 | static unsigned long MSKRB5_OID[7] = { 1, 2, 840, 48018, 1, 2, 2 }; |
86 | 89 | ||
87 | /* | 90 | /* |
@@ -122,6 +125,28 @@ asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) | |||
122 | return 1; | 125 | return 1; |
123 | } | 126 | } |
124 | 127 | ||
128 | #if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */ | ||
129 | static unsigned char | ||
130 | asn1_enum_decode(struct asn1_ctx *ctx, __le32 *val) | ||
131 | { | ||
132 | unsigned char ch; | ||
133 | |||
134 | if (ctx->pointer >= ctx->end) { | ||
135 | ctx->error = ASN1_ERR_DEC_EMPTY; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | ch = *(ctx->pointer)++; /* ch has 0xa, ptr points to lenght octet */ | ||
140 | if ((ch) == ASN1_ENUM) /* if ch value is ENUM, 0xa */ | ||
141 | *val = *(++(ctx->pointer)); /* value has enum value */ | ||
142 | else | ||
143 | return 0; | ||
144 | |||
145 | ctx->pointer++; | ||
146 | return 1; | ||
147 | } | ||
148 | #endif | ||
149 | |||
125 | static unsigned char | 150 | static unsigned char |
126 | asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) | 151 | asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) |
127 | { | 152 | { |
@@ -476,10 +501,9 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
476 | unsigned int cls, con, tag, oidlen, rc; | 501 | unsigned int cls, con, tag, oidlen, rc; |
477 | bool use_ntlmssp = false; | 502 | bool use_ntlmssp = false; |
478 | bool use_kerberos = false; | 503 | bool use_kerberos = false; |
504 | bool use_kerberosu2u = false; | ||
479 | bool use_mskerberos = false; | 505 | bool use_mskerberos = false; |
480 | 506 | ||
481 | *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/ | ||
482 | |||
483 | /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ | 507 | /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ |
484 | 508 | ||
485 | asn1_open(&ctx, security_blob, length); | 509 | asn1_open(&ctx, security_blob, length); |
@@ -515,6 +539,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
515 | return 0; | 539 | return 0; |
516 | } | 540 | } |
517 | 541 | ||
542 | /* SPNEGO */ | ||
518 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 543 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
519 | cFYI(1, ("Error decoding negTokenInit")); | 544 | cFYI(1, ("Error decoding negTokenInit")); |
520 | return 0; | 545 | return 0; |
@@ -526,6 +551,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
526 | return 0; | 551 | return 0; |
527 | } | 552 | } |
528 | 553 | ||
554 | /* negTokenInit */ | ||
529 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 555 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
530 | cFYI(1, ("Error decoding negTokenInit")); | 556 | cFYI(1, ("Error decoding negTokenInit")); |
531 | return 0; | 557 | return 0; |
@@ -537,6 +563,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
537 | return 0; | 563 | return 0; |
538 | } | 564 | } |
539 | 565 | ||
566 | /* sequence */ | ||
540 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 567 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
541 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); | 568 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
542 | return 0; | 569 | return 0; |
@@ -548,6 +575,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
548 | return 0; | 575 | return 0; |
549 | } | 576 | } |
550 | 577 | ||
578 | /* sequence of */ | ||
551 | if (asn1_header_decode | 579 | if (asn1_header_decode |
552 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { | 580 | (&ctx, &sequence_end, &cls, &con, &tag) == 0) { |
553 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); | 581 | cFYI(1, ("Error decoding 2nd part of negTokenInit")); |
@@ -560,6 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
560 | return 0; | 588 | return 0; |
561 | } | 589 | } |
562 | 590 | ||
591 | /* list of security mechanisms */ | ||
563 | while (!asn1_eoc_decode(&ctx, sequence_end)) { | 592 | while (!asn1_eoc_decode(&ctx, sequence_end)) { |
564 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); | 593 | rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); |
565 | if (!rc) { | 594 | if (!rc) { |
@@ -576,11 +605,15 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
576 | 605 | ||
577 | if (compare_oid(oid, oidlen, MSKRB5_OID, | 606 | if (compare_oid(oid, oidlen, MSKRB5_OID, |
578 | MSKRB5_OID_LEN) && | 607 | MSKRB5_OID_LEN) && |
579 | !use_kerberos) | 608 | !use_mskerberos) |
580 | use_mskerberos = true; | 609 | use_mskerberos = true; |
610 | else if (compare_oid(oid, oidlen, KRB5U2U_OID, | ||
611 | KRB5U2U_OID_LEN) && | ||
612 | !use_kerberosu2u) | ||
613 | use_kerberosu2u = true; | ||
581 | else if (compare_oid(oid, oidlen, KRB5_OID, | 614 | else if (compare_oid(oid, oidlen, KRB5_OID, |
582 | KRB5_OID_LEN) && | 615 | KRB5_OID_LEN) && |
583 | !use_mskerberos) | 616 | !use_kerberos) |
584 | use_kerberos = true; | 617 | use_kerberos = true; |
585 | else if (compare_oid(oid, oidlen, NTLMSSP_OID, | 618 | else if (compare_oid(oid, oidlen, NTLMSSP_OID, |
586 | NTLMSSP_OID_LEN)) | 619 | NTLMSSP_OID_LEN)) |
@@ -593,7 +626,12 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
593 | } | 626 | } |
594 | } | 627 | } |
595 | 628 | ||
629 | /* mechlistMIC */ | ||
596 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 630 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
631 | /* Check if we have reached the end of the blob, but with | ||
632 | no mechListMic (e.g. NTLMSSP instead of KRB5) */ | ||
633 | if (ctx.error == ASN1_ERR_DEC_EMPTY) | ||
634 | goto decode_negtoken_exit; | ||
597 | cFYI(1, ("Error decoding last part negTokenInit exit3")); | 635 | cFYI(1, ("Error decoding last part negTokenInit exit3")); |
598 | return 0; | 636 | return 0; |
599 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { | 637 | } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { |
@@ -602,6 +640,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
602 | cls, con, tag, end, *end)); | 640 | cls, con, tag, end, *end)); |
603 | return 0; | 641 | return 0; |
604 | } | 642 | } |
643 | |||
644 | /* sequence */ | ||
605 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 645 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
606 | cFYI(1, ("Error decoding last part negTokenInit exit5")); | 646 | cFYI(1, ("Error decoding last part negTokenInit exit5")); |
607 | return 0; | 647 | return 0; |
@@ -611,6 +651,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
611 | cls, con, tag, end, *end)); | 651 | cls, con, tag, end, *end)); |
612 | } | 652 | } |
613 | 653 | ||
654 | /* sequence of */ | ||
614 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 655 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
615 | cFYI(1, ("Error decoding last part negTokenInit exit 7")); | 656 | cFYI(1, ("Error decoding last part negTokenInit exit 7")); |
616 | return 0; | 657 | return 0; |
@@ -619,6 +660,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
619 | cls, con, tag, end, *end)); | 660 | cls, con, tag, end, *end)); |
620 | return 0; | 661 | return 0; |
621 | } | 662 | } |
663 | |||
664 | /* general string */ | ||
622 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { | 665 | if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { |
623 | cFYI(1, ("Error decoding last part negTokenInit exit9")); | 666 | cFYI(1, ("Error decoding last part negTokenInit exit9")); |
624 | return 0; | 667 | return 0; |
@@ -630,13 +673,13 @@ decode_negTokenInit(unsigned char *security_blob, int length, | |||
630 | } | 673 | } |
631 | cFYI(1, ("Need to call asn1_octets_decode() function for %s", | 674 | cFYI(1, ("Need to call asn1_octets_decode() function for %s", |
632 | ctx.pointer)); /* is this UTF-8 or ASCII? */ | 675 | ctx.pointer)); /* is this UTF-8 or ASCII? */ |
633 | 676 | decode_negtoken_exit: | |
634 | if (use_kerberos) | 677 | if (use_kerberos) |
635 | *secType = Kerberos; | 678 | *secType = Kerberos; |
636 | else if (use_mskerberos) | 679 | else if (use_mskerberos) |
637 | *secType = MSKerberos; | 680 | *secType = MSKerberos; |
638 | else if (use_ntlmssp) | 681 | else if (use_ntlmssp) |
639 | *secType = NTLMSSP; | 682 | *secType = RawNTLMSSP; |
640 | 683 | ||
641 | return 1; | 684 | return 1; |
642 | } | 685 | } |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7f19fefd3d45..42cec2a7c0cf 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -261,6 +261,8 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
261 | atomic_set(&tcon->num_reads, 0); | 261 | atomic_set(&tcon->num_reads, 0); |
262 | atomic_set(&tcon->num_oplock_brks, 0); | 262 | atomic_set(&tcon->num_oplock_brks, 0); |
263 | atomic_set(&tcon->num_opens, 0); | 263 | atomic_set(&tcon->num_opens, 0); |
264 | atomic_set(&tcon->num_posixopens, 0); | ||
265 | atomic_set(&tcon->num_posixmkdirs, 0); | ||
264 | atomic_set(&tcon->num_closes, 0); | 266 | atomic_set(&tcon->num_closes, 0); |
265 | atomic_set(&tcon->num_deletes, 0); | 267 | atomic_set(&tcon->num_deletes, 0); |
266 | atomic_set(&tcon->num_mkdirs, 0); | 268 | atomic_set(&tcon->num_mkdirs, 0); |
@@ -347,11 +349,15 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
347 | atomic_read(&tcon->num_locks), | 349 | atomic_read(&tcon->num_locks), |
348 | atomic_read(&tcon->num_hardlinks), | 350 | atomic_read(&tcon->num_hardlinks), |
349 | atomic_read(&tcon->num_symlinks)); | 351 | atomic_read(&tcon->num_symlinks)); |
350 | seq_printf(m, "\nOpens: %d Closes: %d" | 352 | seq_printf(m, "\nOpens: %d Closes: %d " |
351 | "Deletes: %d", | 353 | "Deletes: %d", |
352 | atomic_read(&tcon->num_opens), | 354 | atomic_read(&tcon->num_opens), |
353 | atomic_read(&tcon->num_closes), | 355 | atomic_read(&tcon->num_closes), |
354 | atomic_read(&tcon->num_deletes)); | 356 | atomic_read(&tcon->num_deletes)); |
357 | seq_printf(m, "\nPosix Opens: %d " | ||
358 | "Posix Mkdirs: %d", | ||
359 | atomic_read(&tcon->num_posixopens), | ||
360 | atomic_read(&tcon->num_posixmkdirs)); | ||
355 | seq_printf(m, "\nMkdirs: %d Rmdirs: %d", | 361 | seq_printf(m, "\nMkdirs: %d Rmdirs: %d", |
356 | atomic_read(&tcon->num_mkdirs), | 362 | atomic_read(&tcon->num_mkdirs), |
357 | atomic_read(&tcon->num_rmdirs)); | 363 | atomic_read(&tcon->num_rmdirs)); |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 3bb11be8b6a8..606912d8f2a8 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -55,7 +55,7 @@ void cifs_dfs_release_automount_timer(void) | |||
55 | * i.e. strips from UNC trailing path that is not part of share | 55 | * i.e. strips from UNC trailing path that is not part of share |
56 | * name and fixup missing '\' in the begining of DFS node refferal | 56 | * name and fixup missing '\' in the begining of DFS node refferal |
57 | * if neccessary. | 57 | * if neccessary. |
58 | * Returns pointer to share name on success or NULL on error. | 58 | * Returns pointer to share name on success or ERR_PTR on error. |
59 | * Caller is responsible for freeing returned string. | 59 | * Caller is responsible for freeing returned string. |
60 | */ | 60 | */ |
61 | static char *cifs_get_share_name(const char *node_name) | 61 | static char *cifs_get_share_name(const char *node_name) |
@@ -68,7 +68,7 @@ static char *cifs_get_share_name(const char *node_name) | |||
68 | UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, | 68 | UNC = kmalloc(len+2 /*for term null and additional \ if it's missed */, |
69 | GFP_KERNEL); | 69 | GFP_KERNEL); |
70 | if (!UNC) | 70 | if (!UNC) |
71 | return NULL; | 71 | return ERR_PTR(-ENOMEM); |
72 | 72 | ||
73 | /* get share name and server name */ | 73 | /* get share name and server name */ |
74 | if (node_name[1] != '\\') { | 74 | if (node_name[1] != '\\') { |
@@ -87,7 +87,7 @@ static char *cifs_get_share_name(const char *node_name) | |||
87 | cERROR(1, ("%s: no server name end in node name: %s", | 87 | cERROR(1, ("%s: no server name end in node name: %s", |
88 | __func__, node_name)); | 88 | __func__, node_name)); |
89 | kfree(UNC); | 89 | kfree(UNC); |
90 | return NULL; | 90 | return ERR_PTR(-EINVAL); |
91 | } | 91 | } |
92 | 92 | ||
93 | /* find sharename end */ | 93 | /* find sharename end */ |
@@ -133,6 +133,12 @@ char *cifs_compose_mount_options(const char *sb_mountdata, | |||
133 | return ERR_PTR(-EINVAL); | 133 | return ERR_PTR(-EINVAL); |
134 | 134 | ||
135 | *devname = cifs_get_share_name(ref->node_name); | 135 | *devname = cifs_get_share_name(ref->node_name); |
136 | if (IS_ERR(*devname)) { | ||
137 | rc = PTR_ERR(*devname); | ||
138 | *devname = NULL; | ||
139 | goto compose_mount_options_err; | ||
140 | } | ||
141 | |||
136 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); | 142 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); |
137 | if (rc != 0) { | 143 | if (rc != 0) { |
138 | cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d", | 144 | cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d", |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 4a4581cb2b5e..051caecf7d67 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -86,6 +86,9 @@ struct key_type cifs_spnego_key_type = { | |||
86 | /* strlen of ";user=" */ | 86 | /* strlen of ";user=" */ |
87 | #define USER_KEY_LEN 6 | 87 | #define USER_KEY_LEN 6 |
88 | 88 | ||
89 | /* strlen of ";pid=0x" */ | ||
90 | #define PID_KEY_LEN 7 | ||
91 | |||
89 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ | 92 | /* get a key struct with a SPNEGO security blob, suitable for session setup */ |
90 | struct key * | 93 | struct key * |
91 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | 94 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) |
@@ -103,7 +106,8 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
103 | IP_KEY_LEN + INET6_ADDRSTRLEN + | 106 | IP_KEY_LEN + INET6_ADDRSTRLEN + |
104 | MAX_MECH_STR_LEN + | 107 | MAX_MECH_STR_LEN + |
105 | UID_KEY_LEN + (sizeof(uid_t) * 2) + | 108 | UID_KEY_LEN + (sizeof(uid_t) * 2) + |
106 | USER_KEY_LEN + strlen(sesInfo->userName) + 1; | 109 | USER_KEY_LEN + strlen(sesInfo->userName) + |
110 | PID_KEY_LEN + (sizeof(pid_t) * 2) + 1; | ||
107 | 111 | ||
108 | spnego_key = ERR_PTR(-ENOMEM); | 112 | spnego_key = ERR_PTR(-ENOMEM); |
109 | description = kzalloc(desc_len, GFP_KERNEL); | 113 | description = kzalloc(desc_len, GFP_KERNEL); |
@@ -141,6 +145,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
141 | dp = description + strlen(description); | 145 | dp = description + strlen(description); |
142 | sprintf(dp, ";user=%s", sesInfo->userName); | 146 | sprintf(dp, ";user=%s", sesInfo->userName); |
143 | 147 | ||
148 | dp = description + strlen(description); | ||
149 | sprintf(dp, ";pid=0x%x", current->pid); | ||
150 | |||
144 | cFYI(1, ("key description = %s", description)); | 151 | cFYI(1, ("key description = %s", description)); |
145 | spnego_key = request_key(&cifs_spnego_key_type, description, ""); | 152 | spnego_key = request_key(&cifs_spnego_key_type, description, ""); |
146 | 153 | ||
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 60e3c4253de0..714a542cbafc 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c | |||
@@ -44,7 +44,7 @@ cifs_ucs2_bytes(const __le16 *from, int maxbytes, | |||
44 | int maxwords = maxbytes / 2; | 44 | int maxwords = maxbytes / 2; |
45 | char tmp[NLS_MAX_CHARSET_SIZE]; | 45 | char tmp[NLS_MAX_CHARSET_SIZE]; |
46 | 46 | ||
47 | for (i = 0; from[i] && i < maxwords; i++) { | 47 | for (i = 0; i < maxwords && from[i]; i++) { |
48 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, | 48 | charlen = codepage->uni2char(le16_to_cpu(from[i]), tmp, |
49 | NLS_MAX_CHARSET_SIZE); | 49 | NLS_MAX_CHARSET_SIZE); |
50 | if (charlen > 0) | 50 | if (charlen > 0) |
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 1403b5d86a73..6941c22398a6 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -327,7 +327,7 @@ static void dump_ace(struct cifs_ace *pace, char *end_of_acl) | |||
327 | 327 | ||
328 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | 328 | static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, |
329 | struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, | 329 | struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, |
330 | struct inode *inode) | 330 | struct cifs_fattr *fattr) |
331 | { | 331 | { |
332 | int i; | 332 | int i; |
333 | int num_aces = 0; | 333 | int num_aces = 0; |
@@ -340,7 +340,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
340 | if (!pdacl) { | 340 | if (!pdacl) { |
341 | /* no DACL in the security descriptor, set | 341 | /* no DACL in the security descriptor, set |
342 | all the permissions for user/group/other */ | 342 | all the permissions for user/group/other */ |
343 | inode->i_mode |= S_IRWXUGO; | 343 | fattr->cf_mode |= S_IRWXUGO; |
344 | return; | 344 | return; |
345 | } | 345 | } |
346 | 346 | ||
@@ -357,7 +357,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
357 | /* reset rwx permissions for user/group/other. | 357 | /* reset rwx permissions for user/group/other. |
358 | Also, if num_aces is 0 i.e. DACL has no ACEs, | 358 | Also, if num_aces is 0 i.e. DACL has no ACEs, |
359 | user/group/other have no permissions */ | 359 | user/group/other have no permissions */ |
360 | inode->i_mode &= ~(S_IRWXUGO); | 360 | fattr->cf_mode &= ~(S_IRWXUGO); |
361 | 361 | ||
362 | acl_base = (char *)pdacl; | 362 | acl_base = (char *)pdacl; |
363 | acl_size = sizeof(struct cifs_acl); | 363 | acl_size = sizeof(struct cifs_acl); |
@@ -379,17 +379,17 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, | |||
379 | if (compare_sids(&(ppace[i]->sid), pownersid)) | 379 | if (compare_sids(&(ppace[i]->sid), pownersid)) |
380 | access_flags_to_mode(ppace[i]->access_req, | 380 | access_flags_to_mode(ppace[i]->access_req, |
381 | ppace[i]->type, | 381 | ppace[i]->type, |
382 | &(inode->i_mode), | 382 | &fattr->cf_mode, |
383 | &user_mask); | 383 | &user_mask); |
384 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) | 384 | if (compare_sids(&(ppace[i]->sid), pgrpsid)) |
385 | access_flags_to_mode(ppace[i]->access_req, | 385 | access_flags_to_mode(ppace[i]->access_req, |
386 | ppace[i]->type, | 386 | ppace[i]->type, |
387 | &(inode->i_mode), | 387 | &fattr->cf_mode, |
388 | &group_mask); | 388 | &group_mask); |
389 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) | 389 | if (compare_sids(&(ppace[i]->sid), &sid_everyone)) |
390 | access_flags_to_mode(ppace[i]->access_req, | 390 | access_flags_to_mode(ppace[i]->access_req, |
391 | ppace[i]->type, | 391 | ppace[i]->type, |
392 | &(inode->i_mode), | 392 | &fattr->cf_mode, |
393 | &other_mask); | 393 | &other_mask); |
394 | 394 | ||
395 | /* memcpy((void *)(&(cifscred->aces[i])), | 395 | /* memcpy((void *)(&(cifscred->aces[i])), |
@@ -464,7 +464,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) | |||
464 | 464 | ||
465 | /* Convert CIFS ACL to POSIX form */ | 465 | /* Convert CIFS ACL to POSIX form */ |
466 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | 466 | static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, |
467 | struct inode *inode) | 467 | struct cifs_fattr *fattr) |
468 | { | 468 | { |
469 | int rc; | 469 | int rc; |
470 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; | 470 | struct cifs_sid *owner_sid_ptr, *group_sid_ptr; |
@@ -472,7 +472,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
472 | char *end_of_acl = ((char *)pntsd) + acl_len; | 472 | char *end_of_acl = ((char *)pntsd) + acl_len; |
473 | __u32 dacloffset; | 473 | __u32 dacloffset; |
474 | 474 | ||
475 | if ((inode == NULL) || (pntsd == NULL)) | 475 | if (pntsd == NULL) |
476 | return -EIO; | 476 | return -EIO; |
477 | 477 | ||
478 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + | 478 | owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + |
@@ -497,7 +497,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
497 | 497 | ||
498 | if (dacloffset) | 498 | if (dacloffset) |
499 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, | 499 | parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, |
500 | group_sid_ptr, inode); | 500 | group_sid_ptr, fattr); |
501 | else | 501 | else |
502 | cFYI(1, ("no ACL")); /* BB grant all or default perms? */ | 502 | cFYI(1, ("no ACL")); /* BB grant all or default perms? */ |
503 | 503 | ||
@@ -508,7 +508,6 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len, | |||
508 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, | 508 | memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, |
509 | sizeof(struct cifs_sid)); */ | 509 | sizeof(struct cifs_sid)); */ |
510 | 510 | ||
511 | |||
512 | return 0; | 511 | return 0; |
513 | } | 512 | } |
514 | 513 | ||
@@ -671,8 +670,9 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, | |||
671 | } | 670 | } |
672 | 671 | ||
673 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ | 672 | /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ |
674 | void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | 673 | void |
675 | const char *path, const __u16 *pfid) | 674 | cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, |
675 | struct inode *inode, const char *path, const __u16 *pfid) | ||
676 | { | 676 | { |
677 | struct cifs_ntsd *pntsd = NULL; | 677 | struct cifs_ntsd *pntsd = NULL; |
678 | u32 acllen = 0; | 678 | u32 acllen = 0; |
@@ -687,7 +687,7 @@ void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | |||
687 | 687 | ||
688 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ | 688 | /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ |
689 | if (pntsd) | 689 | if (pntsd) |
690 | rc = parse_sec_desc(pntsd, acllen, inode); | 690 | rc = parse_sec_desc(pntsd, acllen, fattr); |
691 | if (rc) | 691 | if (rc) |
692 | cFYI(1, ("parse sec desc failed rc = %d", rc)); | 692 | cFYI(1, ("parse sec desc failed rc = %d", rc)); |
693 | 693 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0d92114195ab..84b75253b05a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -308,7 +308,6 @@ cifs_alloc_inode(struct super_block *sb) | |||
308 | if (!cifs_inode) | 308 | if (!cifs_inode) |
309 | return NULL; | 309 | return NULL; |
310 | cifs_inode->cifsAttrs = 0x20; /* default */ | 310 | cifs_inode->cifsAttrs = 0x20; /* default */ |
311 | atomic_set(&cifs_inode->inUse, 0); | ||
312 | cifs_inode->time = 0; | 311 | cifs_inode->time = 0; |
313 | cifs_inode->write_behind_rc = 0; | 312 | cifs_inode->write_behind_rc = 0; |
314 | /* Until the file is open and we have gotten oplock | 313 | /* Until the file is open and we have gotten oplock |
@@ -333,6 +332,27 @@ cifs_destroy_inode(struct inode *inode) | |||
333 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | 332 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); |
334 | } | 333 | } |
335 | 334 | ||
335 | static void | ||
336 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | ||
337 | { | ||
338 | seq_printf(s, ",addr="); | ||
339 | |||
340 | switch (server->addr.sockAddr.sin_family) { | ||
341 | case AF_INET: | ||
342 | seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr); | ||
343 | break; | ||
344 | case AF_INET6: | ||
345 | seq_printf(s, "%pI6", | ||
346 | &server->addr.sockAddr6.sin6_addr.s6_addr); | ||
347 | if (server->addr.sockAddr6.sin6_scope_id) | ||
348 | seq_printf(s, "%%%u", | ||
349 | server->addr.sockAddr6.sin6_scope_id); | ||
350 | break; | ||
351 | default: | ||
352 | seq_printf(s, "(unknown)"); | ||
353 | } | ||
354 | } | ||
355 | |||
336 | /* | 356 | /* |
337 | * cifs_show_options() is for displaying mount options in /proc/mounts. | 357 | * cifs_show_options() is for displaying mount options in /proc/mounts. |
338 | * Not all settable options are displayed but most of the important | 358 | * Not all settable options are displayed but most of the important |
@@ -343,83 +363,68 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
343 | { | 363 | { |
344 | struct cifs_sb_info *cifs_sb; | 364 | struct cifs_sb_info *cifs_sb; |
345 | struct cifsTconInfo *tcon; | 365 | struct cifsTconInfo *tcon; |
346 | struct TCP_Server_Info *server; | ||
347 | 366 | ||
348 | cifs_sb = CIFS_SB(m->mnt_sb); | 367 | cifs_sb = CIFS_SB(m->mnt_sb); |
368 | tcon = cifs_sb->tcon; | ||
349 | 369 | ||
350 | if (cifs_sb) { | 370 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); |
351 | tcon = cifs_sb->tcon; | 371 | if (tcon->ses->userName) |
352 | if (tcon) { | 372 | seq_printf(s, ",username=%s", tcon->ses->userName); |
353 | seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); | 373 | if (tcon->ses->domainName) |
354 | if (tcon->ses) { | 374 | seq_printf(s, ",domain=%s", tcon->ses->domainName); |
355 | if (tcon->ses->userName) | 375 | |
356 | seq_printf(s, ",username=%s", | 376 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); |
357 | tcon->ses->userName); | 377 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
358 | if (tcon->ses->domainName) | 378 | seq_printf(s, ",forceuid"); |
359 | seq_printf(s, ",domain=%s", | 379 | else |
360 | tcon->ses->domainName); | 380 | seq_printf(s, ",noforceuid"); |
361 | server = tcon->ses->server; | 381 | |
362 | if (server) { | 382 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); |
363 | seq_printf(s, ",addr="); | 383 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) |
364 | switch (server->addr.sockAddr6. | 384 | seq_printf(s, ",forcegid"); |
365 | sin6_family) { | 385 | else |
366 | case AF_INET6: | 386 | seq_printf(s, ",noforcegid"); |
367 | seq_printf(s, "%pI6", | 387 | |
368 | &server->addr.sockAddr6.sin6_addr); | 388 | cifs_show_address(s, tcon->ses->server); |
369 | break; | 389 | |
370 | case AF_INET: | 390 | if (!tcon->unix_ext) |
371 | seq_printf(s, "%pI4", | 391 | seq_printf(s, ",file_mode=0%o,dir_mode=0%o", |
372 | &server->addr.sockAddr.sin_addr.s_addr); | ||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | } | ||
377 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || | ||
378 | !(tcon->unix_ext)) | ||
379 | seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); | ||
380 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || | ||
381 | !(tcon->unix_ext)) | ||
382 | seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); | ||
383 | if (!tcon->unix_ext) { | ||
384 | seq_printf(s, ",file_mode=0%o,dir_mode=0%o", | ||
385 | cifs_sb->mnt_file_mode, | 392 | cifs_sb->mnt_file_mode, |
386 | cifs_sb->mnt_dir_mode); | 393 | cifs_sb->mnt_dir_mode); |
387 | } | 394 | if (tcon->seal) |
388 | if (tcon->seal) | 395 | seq_printf(s, ",seal"); |
389 | seq_printf(s, ",seal"); | 396 | if (tcon->nocase) |
390 | if (tcon->nocase) | 397 | seq_printf(s, ",nocase"); |
391 | seq_printf(s, ",nocase"); | 398 | if (tcon->retry) |
392 | if (tcon->retry) | 399 | seq_printf(s, ",hard"); |
393 | seq_printf(s, ",hard"); | 400 | if (cifs_sb->prepath) |
394 | } | 401 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); |
395 | if (cifs_sb->prepath) | 402 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) |
396 | seq_printf(s, ",prepath=%s", cifs_sb->prepath); | 403 | seq_printf(s, ",posixpaths"); |
397 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | 404 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) |
398 | seq_printf(s, ",posixpaths"); | 405 | seq_printf(s, ",setuids"); |
399 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) | 406 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) |
400 | seq_printf(s, ",setuids"); | 407 | seq_printf(s, ",serverino"); |
401 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | 408 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) |
402 | seq_printf(s, ",serverino"); | 409 | seq_printf(s, ",directio"); |
403 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 410 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
404 | seq_printf(s, ",directio"); | 411 | seq_printf(s, ",nouser_xattr"); |
405 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 412 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) |
406 | seq_printf(s, ",nouser_xattr"); | 413 | seq_printf(s, ",mapchars"); |
407 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR) | 414 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
408 | seq_printf(s, ",mapchars"); | 415 | seq_printf(s, ",sfu"); |
409 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 416 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) |
410 | seq_printf(s, ",sfu"); | 417 | seq_printf(s, ",nobrl"); |
411 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 418 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) |
412 | seq_printf(s, ",nobrl"); | 419 | seq_printf(s, ",cifsacl"); |
413 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) | 420 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) |
414 | seq_printf(s, ",cifsacl"); | 421 | seq_printf(s, ",dynperm"); |
415 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) | 422 | if (m->mnt_sb->s_flags & MS_POSIXACL) |
416 | seq_printf(s, ",dynperm"); | 423 | seq_printf(s, ",acl"); |
417 | if (m->mnt_sb->s_flags & MS_POSIXACL) | 424 | |
418 | seq_printf(s, ",acl"); | 425 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); |
419 | 426 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | |
420 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); | 427 | |
421 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | ||
422 | } | ||
423 | return 0; | 428 | return 0; |
424 | } | 429 | } |
425 | 430 | ||
@@ -535,9 +540,14 @@ static void cifs_umount_begin(struct super_block *sb) | |||
535 | if (tcon == NULL) | 540 | if (tcon == NULL) |
536 | return; | 541 | return; |
537 | 542 | ||
538 | lock_kernel(); | ||
539 | read_lock(&cifs_tcp_ses_lock); | 543 | read_lock(&cifs_tcp_ses_lock); |
540 | if (tcon->tc_count == 1) | 544 | if ((tcon->tc_count > 1) || (tcon->tidStatus == CifsExiting)) { |
545 | /* we have other mounts to same share or we have | ||
546 | already tried to force umount this and woken up | ||
547 | all waiting network requests, nothing to do */ | ||
548 | read_unlock(&cifs_tcp_ses_lock); | ||
549 | return; | ||
550 | } else if (tcon->tc_count == 1) | ||
541 | tcon->tidStatus = CifsExiting; | 551 | tcon->tidStatus = CifsExiting; |
542 | read_unlock(&cifs_tcp_ses_lock); | 552 | read_unlock(&cifs_tcp_ses_lock); |
543 | 553 | ||
@@ -552,9 +562,7 @@ static void cifs_umount_begin(struct super_block *sb) | |||
552 | wake_up_all(&tcon->ses->server->response_q); | 562 | wake_up_all(&tcon->ses->server->response_q); |
553 | msleep(1); | 563 | msleep(1); |
554 | } | 564 | } |
555 | /* BB FIXME - finish add checks for tidStatus BB */ | ||
556 | 565 | ||
557 | unlock_kernel(); | ||
558 | return; | 566 | return; |
559 | } | 567 | } |
560 | 568 | ||
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 9570a0e8023f..6c170948300d 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -24,6 +24,19 @@ | |||
24 | 24 | ||
25 | #define ROOT_I 2 | 25 | #define ROOT_I 2 |
26 | 26 | ||
27 | /* | ||
28 | * ino_t is 32-bits on 32-bit arch. We have to squash the 64-bit value down | ||
29 | * so that it will fit. | ||
30 | */ | ||
31 | static inline ino_t | ||
32 | cifs_uniqueid_to_ino_t(u64 fileid) | ||
33 | { | ||
34 | ino_t ino = (ino_t) fileid; | ||
35 | if (sizeof(ino_t) < sizeof(u64)) | ||
36 | ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8; | ||
37 | return ino; | ||
38 | } | ||
39 | |||
27 | extern struct file_system_type cifs_fs_type; | 40 | extern struct file_system_type cifs_fs_type; |
28 | extern const struct address_space_operations cifs_addr_ops; | 41 | extern const struct address_space_operations cifs_addr_ops; |
29 | extern const struct address_space_operations cifs_addr_ops_smallbuf; | 42 | extern const struct address_space_operations cifs_addr_ops_smallbuf; |
@@ -100,5 +113,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
100 | extern const struct export_operations cifs_export_ops; | 113 | extern const struct export_operations cifs_export_ops; |
101 | #endif /* EXPERIMENTAL */ | 114 | #endif /* EXPERIMENTAL */ |
102 | 115 | ||
103 | #define CIFS_VERSION "1.59" | 116 | #define CIFS_VERSION "1.60" |
104 | #endif /* _CIFSFS_H */ | 117 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a61ab772c6f6..6084d6379c03 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -83,7 +83,7 @@ enum securityEnum { | |||
83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ | 83 | NTLM, /* Legacy NTLM012 auth with NTLM hash */ |
84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ | 84 | NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ |
85 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ | 85 | RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ |
86 | NTLMSSP, /* NTLMSSP via SPNEGO, NTLMv2 hash */ | 86 | /* NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */ |
87 | Kerberos, /* Kerberos via SPNEGO */ | 87 | Kerberos, /* Kerberos via SPNEGO */ |
88 | MSKerberos, /* MS Kerberos via SPNEGO */ | 88 | MSKerberos, /* MS Kerberos via SPNEGO */ |
89 | }; | 89 | }; |
@@ -260,6 +260,8 @@ struct cifsTconInfo { | |||
260 | atomic_t num_closes; | 260 | atomic_t num_closes; |
261 | atomic_t num_deletes; | 261 | atomic_t num_deletes; |
262 | atomic_t num_mkdirs; | 262 | atomic_t num_mkdirs; |
263 | atomic_t num_posixopens; | ||
264 | atomic_t num_posixmkdirs; | ||
263 | atomic_t num_rmdirs; | 265 | atomic_t num_rmdirs; |
264 | atomic_t num_renames; | 266 | atomic_t num_renames; |
265 | atomic_t num_t2renames; | 267 | atomic_t num_t2renames; |
@@ -364,13 +366,13 @@ struct cifsInodeInfo { | |||
364 | struct list_head openFileList; | 366 | struct list_head openFileList; |
365 | int write_behind_rc; | 367 | int write_behind_rc; |
366 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ | 368 | __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ |
367 | atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ | ||
368 | unsigned long time; /* jiffies of last update/check of inode */ | 369 | unsigned long time; /* jiffies of last update/check of inode */ |
369 | bool clientCanCacheRead:1; /* read oplock */ | 370 | bool clientCanCacheRead:1; /* read oplock */ |
370 | bool clientCanCacheAll:1; /* read and writebehind oplock */ | 371 | bool clientCanCacheAll:1; /* read and writebehind oplock */ |
371 | bool oplockPending:1; | 372 | bool oplockPending:1; |
372 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ | 373 | bool delete_pending:1; /* DELETE_ON_CLOSE is set */ |
373 | u64 server_eof; /* current file size on server */ | 374 | u64 server_eof; /* current file size on server */ |
375 | u64 uniqueid; /* server inode number */ | ||
374 | struct inode vfs_inode; | 376 | struct inode vfs_inode; |
375 | }; | 377 | }; |
376 | 378 | ||
@@ -472,6 +474,32 @@ struct dfs_info3_param { | |||
472 | char *node_name; | 474 | char *node_name; |
473 | }; | 475 | }; |
474 | 476 | ||
477 | /* | ||
478 | * common struct for holding inode info when searching for or updating an | ||
479 | * inode with new info | ||
480 | */ | ||
481 | |||
482 | #define CIFS_FATTR_DFS_REFERRAL 0x1 | ||
483 | #define CIFS_FATTR_DELETE_PENDING 0x2 | ||
484 | #define CIFS_FATTR_NEED_REVAL 0x4 | ||
485 | |||
486 | struct cifs_fattr { | ||
487 | u32 cf_flags; | ||
488 | u32 cf_cifsattrs; | ||
489 | u64 cf_uniqueid; | ||
490 | u64 cf_eof; | ||
491 | u64 cf_bytes; | ||
492 | uid_t cf_uid; | ||
493 | gid_t cf_gid; | ||
494 | umode_t cf_mode; | ||
495 | dev_t cf_rdev; | ||
496 | unsigned int cf_nlink; | ||
497 | unsigned int cf_dtype; | ||
498 | struct timespec cf_atime; | ||
499 | struct timespec cf_mtime; | ||
500 | struct timespec cf_ctime; | ||
501 | }; | ||
502 | |||
475 | static inline void free_dfs_info_param(struct dfs_info3_param *param) | 503 | static inline void free_dfs_info_param(struct dfs_info3_param *param) |
476 | { | 504 | { |
477 | if (param) { | 505 | if (param) { |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index a785f69dbc9f..2d07f890a842 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -2328,19 +2328,7 @@ struct file_attrib_tag { | |||
2328 | typedef struct { | 2328 | typedef struct { |
2329 | __le32 NextEntryOffset; | 2329 | __le32 NextEntryOffset; |
2330 | __u32 ResumeKey; /* as with FileIndex - no need to convert */ | 2330 | __u32 ResumeKey; /* as with FileIndex - no need to convert */ |
2331 | __le64 EndOfFile; | 2331 | FILE_UNIX_BASIC_INFO basic; |
2332 | __le64 NumOfBytes; | ||
2333 | __le64 LastStatusChange; /*SNIA specs DCE time for the 3 time fields */ | ||
2334 | __le64 LastAccessTime; | ||
2335 | __le64 LastModificationTime; | ||
2336 | __le64 Uid; | ||
2337 | __le64 Gid; | ||
2338 | __le32 Type; | ||
2339 | __le64 DevMajor; | ||
2340 | __le64 DevMinor; | ||
2341 | __le64 UniqueId; | ||
2342 | __le64 Permissions; | ||
2343 | __le64 Nlinks; | ||
2344 | char FileName[1]; | 2332 | char FileName[1]; |
2345 | } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ | 2333 | } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ |
2346 | 2334 | ||
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index f9452329bcce..da8fbf565991 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -74,7 +74,7 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr); | |||
74 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 74 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); |
75 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 75 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
76 | enum securityEnum *secType); | 76 | enum securityEnum *secType); |
77 | extern int cifs_inet_pton(const int, const char *source, void *dst); | 77 | extern int cifs_convert_address(char *src, void *dst); |
78 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); | 78 | extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); |
79 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 79 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
80 | const struct cifsTconInfo *, int /* length of | 80 | const struct cifsTconInfo *, int /* length of |
@@ -98,9 +98,13 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, | |||
98 | extern int cifs_posix_open(char *full_path, struct inode **pinode, | 98 | extern int cifs_posix_open(char *full_path, struct inode **pinode, |
99 | struct super_block *sb, int mode, int oflags, | 99 | struct super_block *sb, int mode, int oflags, |
100 | int *poplock, __u16 *pnetfid, int xid); | 100 | int *poplock, __u16 *pnetfid, int xid); |
101 | extern void posix_fill_in_inode(struct inode *tmp_inode, | 101 | extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, |
102 | FILE_UNIX_BASIC_INFO *pData, int isNewInode); | 102 | FILE_UNIX_BASIC_INFO *info, |
103 | extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum); | 103 | struct cifs_sb_info *cifs_sb); |
104 | extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); | ||
105 | extern struct inode *cifs_iget(struct super_block *sb, | ||
106 | struct cifs_fattr *fattr); | ||
107 | |||
104 | extern int cifs_get_inode_info(struct inode **pinode, | 108 | extern int cifs_get_inode_info(struct inode **pinode, |
105 | const unsigned char *search_path, | 109 | const unsigned char *search_path, |
106 | FILE_ALL_INFO *pfile_info, | 110 | FILE_ALL_INFO *pfile_info, |
@@ -108,8 +112,9 @@ extern int cifs_get_inode_info(struct inode **pinode, | |||
108 | extern int cifs_get_inode_info_unix(struct inode **pinode, | 112 | extern int cifs_get_inode_info_unix(struct inode **pinode, |
109 | const unsigned char *search_path, | 113 | const unsigned char *search_path, |
110 | struct super_block *sb, int xid); | 114 | struct super_block *sb, int xid); |
111 | extern void acl_to_uid_mode(struct cifs_sb_info *cifs_sb, struct inode *inode, | 115 | extern void cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, |
112 | const char *path, const __u16 *pfid); | 116 | struct cifs_fattr *fattr, struct inode *inode, |
117 | const char *path, const __u16 *pfid); | ||
113 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); | 118 | extern int mode_to_acl(struct inode *inode, const char *path, __u64); |
114 | 119 | ||
115 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, | 120 | extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, |
@@ -215,7 +220,11 @@ struct cifs_unix_set_info_args { | |||
215 | dev_t device; | 220 | dev_t device; |
216 | }; | 221 | }; |
217 | 222 | ||
218 | extern int CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *pTcon, | 223 | extern int CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, |
224 | const struct cifs_unix_set_info_args *args, | ||
225 | u16 fid, u32 pid_of_opener); | ||
226 | |||
227 | extern int CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *pTcon, | ||
219 | char *fileName, | 228 | char *fileName, |
220 | const struct cifs_unix_set_info_args *args, | 229 | const struct cifs_unix_set_info_args *args, |
221 | const struct nls_table *nls_codepage, | 230 | const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b84c61d5bca4..1866bc2927d4 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -594,7 +594,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
594 | else if (secFlags & CIFSSEC_MAY_KRB5) | 594 | else if (secFlags & CIFSSEC_MAY_KRB5) |
595 | server->secType = Kerberos; | 595 | server->secType = Kerberos; |
596 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) | 596 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) |
597 | server->secType = NTLMSSP; | 597 | server->secType = RawNTLMSSP; |
598 | else if (secFlags & CIFSSEC_MAY_LANMAN) | 598 | else if (secFlags & CIFSSEC_MAY_LANMAN) |
599 | server->secType = LANMAN; | 599 | server->secType = LANMAN; |
600 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL | 600 | /* #ifdef CONFIG_CIFS_EXPERIMENTAL |
@@ -729,7 +729,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
729 | * the tcon is no longer on the list, so no need to take lock before | 729 | * the tcon is no longer on the list, so no need to take lock before |
730 | * checking this. | 730 | * checking this. |
731 | */ | 731 | */ |
732 | if (tcon->need_reconnect) | 732 | if ((tcon->need_reconnect) || (tcon->ses->need_reconnect)) |
733 | return 0; | 733 | return 0; |
734 | 734 | ||
735 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, | 735 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, |
@@ -1113,7 +1113,10 @@ PsxCreat: | |||
1113 | psx_create_err: | 1113 | psx_create_err: |
1114 | cifs_buf_release(pSMB); | 1114 | cifs_buf_release(pSMB); |
1115 | 1115 | ||
1116 | cifs_stats_inc(&tcon->num_mkdirs); | 1116 | if (posix_flags & SMB_O_DIRECTORY) |
1117 | cifs_stats_inc(&tcon->num_posixmkdirs); | ||
1118 | else | ||
1119 | cifs_stats_inc(&tcon->num_posixopens); | ||
1117 | 1120 | ||
1118 | if (rc == -EAGAIN) | 1121 | if (rc == -EAGAIN) |
1119 | goto PsxCreat; | 1122 | goto PsxCreat; |
@@ -5074,10 +5077,114 @@ SetAttrLgcyRetry: | |||
5074 | } | 5077 | } |
5075 | #endif /* temporarily unneeded SetAttr legacy function */ | 5078 | #endif /* temporarily unneeded SetAttr legacy function */ |
5076 | 5079 | ||
5080 | static void | ||
5081 | cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, | ||
5082 | const struct cifs_unix_set_info_args *args) | ||
5083 | { | ||
5084 | u64 mode = args->mode; | ||
5085 | |||
5086 | /* | ||
5087 | * Samba server ignores set of file size to zero due to bugs in some | ||
5088 | * older clients, but we should be precise - we use SetFileSize to | ||
5089 | * set file size and do not want to truncate file size to zero | ||
5090 | * accidently as happened on one Samba server beta by putting | ||
5091 | * zero instead of -1 here | ||
5092 | */ | ||
5093 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | ||
5094 | data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); | ||
5095 | data_offset->LastStatusChange = cpu_to_le64(args->ctime); | ||
5096 | data_offset->LastAccessTime = cpu_to_le64(args->atime); | ||
5097 | data_offset->LastModificationTime = cpu_to_le64(args->mtime); | ||
5098 | data_offset->Uid = cpu_to_le64(args->uid); | ||
5099 | data_offset->Gid = cpu_to_le64(args->gid); | ||
5100 | /* better to leave device as zero when it is */ | ||
5101 | data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); | ||
5102 | data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); | ||
5103 | data_offset->Permissions = cpu_to_le64(mode); | ||
5104 | |||
5105 | if (S_ISREG(mode)) | ||
5106 | data_offset->Type = cpu_to_le32(UNIX_FILE); | ||
5107 | else if (S_ISDIR(mode)) | ||
5108 | data_offset->Type = cpu_to_le32(UNIX_DIR); | ||
5109 | else if (S_ISLNK(mode)) | ||
5110 | data_offset->Type = cpu_to_le32(UNIX_SYMLINK); | ||
5111 | else if (S_ISCHR(mode)) | ||
5112 | data_offset->Type = cpu_to_le32(UNIX_CHARDEV); | ||
5113 | else if (S_ISBLK(mode)) | ||
5114 | data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); | ||
5115 | else if (S_ISFIFO(mode)) | ||
5116 | data_offset->Type = cpu_to_le32(UNIX_FIFO); | ||
5117 | else if (S_ISSOCK(mode)) | ||
5118 | data_offset->Type = cpu_to_le32(UNIX_SOCKET); | ||
5119 | } | ||
5120 | |||
5077 | int | 5121 | int |
5078 | CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | 5122 | CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon, |
5079 | const struct cifs_unix_set_info_args *args, | 5123 | const struct cifs_unix_set_info_args *args, |
5080 | const struct nls_table *nls_codepage, int remap) | 5124 | u16 fid, u32 pid_of_opener) |
5125 | { | ||
5126 | struct smb_com_transaction2_sfi_req *pSMB = NULL; | ||
5127 | FILE_UNIX_BASIC_INFO *data_offset; | ||
5128 | int rc = 0; | ||
5129 | u16 params, param_offset, offset, byte_count, count; | ||
5130 | |||
5131 | cFYI(1, ("Set Unix Info (via SetFileInfo)")); | ||
5132 | rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB); | ||
5133 | |||
5134 | if (rc) | ||
5135 | return rc; | ||
5136 | |||
5137 | pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener); | ||
5138 | pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16)); | ||
5139 | |||
5140 | params = 6; | ||
5141 | pSMB->MaxSetupCount = 0; | ||
5142 | pSMB->Reserved = 0; | ||
5143 | pSMB->Flags = 0; | ||
5144 | pSMB->Timeout = 0; | ||
5145 | pSMB->Reserved2 = 0; | ||
5146 | param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4; | ||
5147 | offset = param_offset + params; | ||
5148 | |||
5149 | data_offset = (FILE_UNIX_BASIC_INFO *) | ||
5150 | ((char *)(&pSMB->hdr.Protocol) + offset); | ||
5151 | count = sizeof(FILE_UNIX_BASIC_INFO); | ||
5152 | |||
5153 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
5154 | /* BB find max SMB PDU from sess */ | ||
5155 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
5156 | pSMB->SetupCount = 1; | ||
5157 | pSMB->Reserved3 = 0; | ||
5158 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); | ||
5159 | byte_count = 3 /* pad */ + params + count; | ||
5160 | pSMB->DataCount = cpu_to_le16(count); | ||
5161 | pSMB->ParameterCount = cpu_to_le16(params); | ||
5162 | pSMB->TotalDataCount = pSMB->DataCount; | ||
5163 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
5164 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
5165 | pSMB->DataOffset = cpu_to_le16(offset); | ||
5166 | pSMB->Fid = fid; | ||
5167 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | ||
5168 | pSMB->Reserved4 = 0; | ||
5169 | pSMB->hdr.smb_buf_length += byte_count; | ||
5170 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
5171 | |||
5172 | cifs_fill_unix_set_info(data_offset, args); | ||
5173 | |||
5174 | rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0); | ||
5175 | if (rc) | ||
5176 | cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc)); | ||
5177 | |||
5178 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
5179 | since file handle passed in no longer valid */ | ||
5180 | |||
5181 | return rc; | ||
5182 | } | ||
5183 | |||
5184 | int | ||
5185 | CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | ||
5186 | const struct cifs_unix_set_info_args *args, | ||
5187 | const struct nls_table *nls_codepage, int remap) | ||
5081 | { | 5188 | { |
5082 | TRANSACTION2_SPI_REQ *pSMB = NULL; | 5189 | TRANSACTION2_SPI_REQ *pSMB = NULL; |
5083 | TRANSACTION2_SPI_RSP *pSMBr = NULL; | 5190 | TRANSACTION2_SPI_RSP *pSMBr = NULL; |
@@ -5086,7 +5193,6 @@ CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName, | |||
5086 | int bytes_returned = 0; | 5193 | int bytes_returned = 0; |
5087 | FILE_UNIX_BASIC_INFO *data_offset; | 5194 | FILE_UNIX_BASIC_INFO *data_offset; |
5088 | __u16 params, param_offset, offset, count, byte_count; | 5195 | __u16 params, param_offset, offset, count, byte_count; |
5089 | __u64 mode = args->mode; | ||
5090 | 5196 | ||
5091 | cFYI(1, ("In SetUID/GID/Mode")); | 5197 | cFYI(1, ("In SetUID/GID/Mode")); |
5092 | setPermsRetry: | 5198 | setPermsRetry: |
@@ -5137,38 +5243,8 @@ setPermsRetry: | |||
5137 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); | 5243 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); |
5138 | pSMB->Reserved4 = 0; | 5244 | pSMB->Reserved4 = 0; |
5139 | pSMB->hdr.smb_buf_length += byte_count; | 5245 | pSMB->hdr.smb_buf_length += byte_count; |
5140 | /* Samba server ignores set of file size to zero due to bugs in some | ||
5141 | older clients, but we should be precise - we use SetFileSize to | ||
5142 | set file size and do not want to truncate file size to zero | ||
5143 | accidently as happened on one Samba server beta by putting | ||
5144 | zero instead of -1 here */ | ||
5145 | data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64); | ||
5146 | data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64); | ||
5147 | data_offset->LastStatusChange = cpu_to_le64(args->ctime); | ||
5148 | data_offset->LastAccessTime = cpu_to_le64(args->atime); | ||
5149 | data_offset->LastModificationTime = cpu_to_le64(args->mtime); | ||
5150 | data_offset->Uid = cpu_to_le64(args->uid); | ||
5151 | data_offset->Gid = cpu_to_le64(args->gid); | ||
5152 | /* better to leave device as zero when it is */ | ||
5153 | data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); | ||
5154 | data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); | ||
5155 | data_offset->Permissions = cpu_to_le64(mode); | ||
5156 | |||
5157 | if (S_ISREG(mode)) | ||
5158 | data_offset->Type = cpu_to_le32(UNIX_FILE); | ||
5159 | else if (S_ISDIR(mode)) | ||
5160 | data_offset->Type = cpu_to_le32(UNIX_DIR); | ||
5161 | else if (S_ISLNK(mode)) | ||
5162 | data_offset->Type = cpu_to_le32(UNIX_SYMLINK); | ||
5163 | else if (S_ISCHR(mode)) | ||
5164 | data_offset->Type = cpu_to_le32(UNIX_CHARDEV); | ||
5165 | else if (S_ISBLK(mode)) | ||
5166 | data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); | ||
5167 | else if (S_ISFIFO(mode)) | ||
5168 | data_offset->Type = cpu_to_le32(UNIX_FIFO); | ||
5169 | else if (S_ISSOCK(mode)) | ||
5170 | data_offset->Type = cpu_to_le32(UNIX_SOCKET); | ||
5171 | 5246 | ||
5247 | cifs_fill_unix_set_info(data_offset, args); | ||
5172 | 5248 | ||
5173 | pSMB->ByteCount = cpu_to_le16(byte_count); | 5249 | pSMB->ByteCount = cpu_to_le16(byte_count); |
5174 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 5250 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 97f4311b9a8e..1f3345d7fa79 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -70,7 +70,6 @@ struct smb_vol { | |||
70 | mode_t file_mode; | 70 | mode_t file_mode; |
71 | mode_t dir_mode; | 71 | mode_t dir_mode; |
72 | unsigned secFlg; | 72 | unsigned secFlg; |
73 | bool rw:1; | ||
74 | bool retry:1; | 73 | bool retry:1; |
75 | bool intr:1; | 74 | bool intr:1; |
76 | bool setuids:1; | 75 | bool setuids:1; |
@@ -804,6 +803,10 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
804 | char *data; | 803 | char *data; |
805 | unsigned int temp_len, i, j; | 804 | unsigned int temp_len, i, j; |
806 | char separator[2]; | 805 | char separator[2]; |
806 | short int override_uid = -1; | ||
807 | short int override_gid = -1; | ||
808 | bool uid_specified = false; | ||
809 | bool gid_specified = false; | ||
807 | 810 | ||
808 | separator[0] = ','; | 811 | separator[0] = ','; |
809 | separator[1] = 0; | 812 | separator[1] = 0; |
@@ -832,7 +835,6 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
832 | vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; | 835 | vol->dir_mode = vol->file_mode = S_IRUGO | S_IXUGO | S_IWUSR; |
833 | 836 | ||
834 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 837 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
835 | vol->rw = true; | ||
836 | /* default is always to request posix paths. */ | 838 | /* default is always to request posix paths. */ |
837 | vol->posix_paths = 1; | 839 | vol->posix_paths = 1; |
838 | /* default to using server inode numbers where available */ | 840 | /* default to using server inode numbers where available */ |
@@ -1095,18 +1097,20 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1095 | "too long.\n"); | 1097 | "too long.\n"); |
1096 | return 1; | 1098 | return 1; |
1097 | } | 1099 | } |
1098 | } else if (strnicmp(data, "uid", 3) == 0) { | 1100 | } else if (!strnicmp(data, "uid", 3) && value && *value) { |
1099 | if (value && *value) | 1101 | vol->linux_uid = simple_strtoul(value, &value, 0); |
1100 | vol->linux_uid = | 1102 | uid_specified = true; |
1101 | simple_strtoul(value, &value, 0); | 1103 | } else if (!strnicmp(data, "forceuid", 8)) { |
1102 | } else if (strnicmp(data, "forceuid", 8) == 0) { | 1104 | override_uid = 1; |
1103 | vol->override_uid = 1; | 1105 | } else if (!strnicmp(data, "noforceuid", 10)) { |
1104 | } else if (strnicmp(data, "gid", 3) == 0) { | 1106 | override_uid = 0; |
1105 | if (value && *value) | 1107 | } else if (!strnicmp(data, "gid", 3) && value && *value) { |
1106 | vol->linux_gid = | 1108 | vol->linux_gid = simple_strtoul(value, &value, 0); |
1107 | simple_strtoul(value, &value, 0); | 1109 | gid_specified = true; |
1108 | } else if (strnicmp(data, "forcegid", 8) == 0) { | 1110 | } else if (!strnicmp(data, "forcegid", 8)) { |
1109 | vol->override_gid = 1; | 1111 | override_gid = 1; |
1112 | } else if (!strnicmp(data, "noforcegid", 10)) { | ||
1113 | override_gid = 0; | ||
1110 | } else if (strnicmp(data, "file_mode", 4) == 0) { | 1114 | } else if (strnicmp(data, "file_mode", 4) == 0) { |
1111 | if (value && *value) { | 1115 | if (value && *value) { |
1112 | vol->file_mode = | 1116 | vol->file_mode = |
@@ -1199,7 +1203,9 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1199 | } else if (strnicmp(data, "guest", 5) == 0) { | 1203 | } else if (strnicmp(data, "guest", 5) == 0) { |
1200 | /* ignore */ | 1204 | /* ignore */ |
1201 | } else if (strnicmp(data, "rw", 2) == 0) { | 1205 | } else if (strnicmp(data, "rw", 2) == 0) { |
1202 | vol->rw = true; | 1206 | /* ignore */ |
1207 | } else if (strnicmp(data, "ro", 2) == 0) { | ||
1208 | /* ignore */ | ||
1203 | } else if (strnicmp(data, "noblocksend", 11) == 0) { | 1209 | } else if (strnicmp(data, "noblocksend", 11) == 0) { |
1204 | vol->noblocksnd = 1; | 1210 | vol->noblocksnd = 1; |
1205 | } else if (strnicmp(data, "noautotune", 10) == 0) { | 1211 | } else if (strnicmp(data, "noautotune", 10) == 0) { |
@@ -1218,8 +1224,6 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1218 | parse these options again and set anything and it | 1224 | parse these options again and set anything and it |
1219 | is ok to just ignore them */ | 1225 | is ok to just ignore them */ |
1220 | continue; | 1226 | continue; |
1221 | } else if (strnicmp(data, "ro", 2) == 0) { | ||
1222 | vol->rw = false; | ||
1223 | } else if (strnicmp(data, "hard", 4) == 0) { | 1227 | } else if (strnicmp(data, "hard", 4) == 0) { |
1224 | vol->retry = 1; | 1228 | vol->retry = 1; |
1225 | } else if (strnicmp(data, "soft", 4) == 0) { | 1229 | } else if (strnicmp(data, "soft", 4) == 0) { |
@@ -1357,6 +1361,18 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1357 | if (vol->UNCip == NULL) | 1361 | if (vol->UNCip == NULL) |
1358 | vol->UNCip = &vol->UNC[2]; | 1362 | vol->UNCip = &vol->UNC[2]; |
1359 | 1363 | ||
1364 | if (uid_specified) | ||
1365 | vol->override_uid = override_uid; | ||
1366 | else if (override_uid == 1) | ||
1367 | printk(KERN_NOTICE "CIFS: ignoring forceuid mount option " | ||
1368 | "specified with no uid= option.\n"); | ||
1369 | |||
1370 | if (gid_specified) | ||
1371 | vol->override_gid = override_gid; | ||
1372 | else if (override_gid == 1) | ||
1373 | printk(KERN_NOTICE "CIFS: ignoring forcegid mount option " | ||
1374 | "specified with no gid= option.\n"); | ||
1375 | |||
1360 | return 0; | 1376 | return 0; |
1361 | } | 1377 | } |
1362 | 1378 | ||
@@ -1386,8 +1402,10 @@ cifs_find_tcp_session(struct sockaddr_storage *addr) | |||
1386 | server->addr.sockAddr.sin_addr.s_addr)) | 1402 | server->addr.sockAddr.sin_addr.s_addr)) |
1387 | continue; | 1403 | continue; |
1388 | else if (addr->ss_family == AF_INET6 && | 1404 | else if (addr->ss_family == AF_INET6 && |
1389 | !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, | 1405 | (!ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr, |
1390 | &addr6->sin6_addr)) | 1406 | &addr6->sin6_addr) || |
1407 | server->addr.sockAddr6.sin6_scope_id != | ||
1408 | addr6->sin6_scope_id)) | ||
1391 | continue; | 1409 | continue; |
1392 | 1410 | ||
1393 | ++server->srv_count; | 1411 | ++server->srv_count; |
@@ -1433,28 +1451,15 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1433 | 1451 | ||
1434 | memset(&addr, 0, sizeof(struct sockaddr_storage)); | 1452 | memset(&addr, 0, sizeof(struct sockaddr_storage)); |
1435 | 1453 | ||
1436 | if (volume_info->UNCip && volume_info->UNC) { | 1454 | cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, volume_info->UNCip)); |
1437 | rc = cifs_inet_pton(AF_INET, volume_info->UNCip, | ||
1438 | &sin_server->sin_addr.s_addr); | ||
1439 | |||
1440 | if (rc <= 0) { | ||
1441 | /* not ipv4 address, try ipv6 */ | ||
1442 | rc = cifs_inet_pton(AF_INET6, volume_info->UNCip, | ||
1443 | &sin_server6->sin6_addr.in6_u); | ||
1444 | if (rc > 0) | ||
1445 | addr.ss_family = AF_INET6; | ||
1446 | } else { | ||
1447 | addr.ss_family = AF_INET; | ||
1448 | } | ||
1449 | 1455 | ||
1450 | if (rc <= 0) { | 1456 | if (volume_info->UNCip && volume_info->UNC) { |
1457 | rc = cifs_convert_address(volume_info->UNCip, &addr); | ||
1458 | if (!rc) { | ||
1451 | /* we failed translating address */ | 1459 | /* we failed translating address */ |
1452 | rc = -EINVAL; | 1460 | rc = -EINVAL; |
1453 | goto out_err; | 1461 | goto out_err; |
1454 | } | 1462 | } |
1455 | |||
1456 | cFYI(1, ("UNC: %s ip: %s", volume_info->UNC, | ||
1457 | volume_info->UNCip)); | ||
1458 | } else if (volume_info->UNCip) { | 1463 | } else if (volume_info->UNCip) { |
1459 | /* BB using ip addr as tcp_ses name to connect to the | 1464 | /* BB using ip addr as tcp_ses name to connect to the |
1460 | DFS root below */ | 1465 | DFS root below */ |
@@ -1513,14 +1518,14 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1513 | cFYI(1, ("attempting ipv6 connect")); | 1518 | cFYI(1, ("attempting ipv6 connect")); |
1514 | /* BB should we allow ipv6 on port 139? */ | 1519 | /* BB should we allow ipv6 on port 139? */ |
1515 | /* other OS never observed in Wild doing 139 with v6 */ | 1520 | /* other OS never observed in Wild doing 139 with v6 */ |
1521 | sin_server6->sin6_port = htons(volume_info->port); | ||
1516 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1522 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, |
1517 | sizeof(struct sockaddr_in6)); | 1523 | sizeof(struct sockaddr_in6)); |
1518 | sin_server6->sin6_port = htons(volume_info->port); | ||
1519 | rc = ipv6_connect(tcp_ses); | 1524 | rc = ipv6_connect(tcp_ses); |
1520 | } else { | 1525 | } else { |
1526 | sin_server->sin_port = htons(volume_info->port); | ||
1521 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1527 | memcpy(&tcp_ses->addr.sockAddr, sin_server, |
1522 | sizeof(struct sockaddr_in)); | 1528 | sizeof(struct sockaddr_in)); |
1523 | sin_server->sin_port = htons(volume_info->port); | ||
1524 | rc = ipv4_connect(tcp_ses); | 1529 | rc = ipv4_connect(tcp_ses); |
1525 | } | 1530 | } |
1526 | if (rc < 0) { | 1531 | if (rc < 0) { |
@@ -2465,10 +2470,10 @@ try_mount_again: | |||
2465 | tcon->local_lease = volume_info->local_lease; | 2470 | tcon->local_lease = volume_info->local_lease; |
2466 | } | 2471 | } |
2467 | if (pSesInfo) { | 2472 | if (pSesInfo) { |
2468 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { | 2473 | if (pSesInfo->capabilities & CAP_LARGE_FILES) |
2469 | sb->s_maxbytes = (u64) 1 << 63; | 2474 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
2470 | } else | 2475 | else |
2471 | sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ | 2476 | sb->s_maxbytes = MAX_NON_LFS; |
2472 | } | 2477 | } |
2473 | 2478 | ||
2474 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | 2479 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
@@ -2557,11 +2562,20 @@ remote_path_check: | |||
2557 | 2562 | ||
2558 | if (mount_data != mount_data_global) | 2563 | if (mount_data != mount_data_global) |
2559 | kfree(mount_data); | 2564 | kfree(mount_data); |
2565 | |||
2560 | mount_data = cifs_compose_mount_options( | 2566 | mount_data = cifs_compose_mount_options( |
2561 | cifs_sb->mountdata, full_path + 1, | 2567 | cifs_sb->mountdata, full_path + 1, |
2562 | referrals, &fake_devname); | 2568 | referrals, &fake_devname); |
2563 | kfree(fake_devname); | 2569 | |
2564 | free_dfs_info_array(referrals, num_referrals); | 2570 | free_dfs_info_array(referrals, num_referrals); |
2571 | kfree(fake_devname); | ||
2572 | kfree(full_path); | ||
2573 | |||
2574 | if (IS_ERR(mount_data)) { | ||
2575 | rc = PTR_ERR(mount_data); | ||
2576 | mount_data = NULL; | ||
2577 | goto mount_fail_check; | ||
2578 | } | ||
2565 | 2579 | ||
2566 | if (tcon) | 2580 | if (tcon) |
2567 | cifs_put_tcon(tcon); | 2581 | cifs_put_tcon(tcon); |
@@ -2569,8 +2583,6 @@ remote_path_check: | |||
2569 | cifs_put_smb_ses(pSesInfo); | 2583 | cifs_put_smb_ses(pSesInfo); |
2570 | 2584 | ||
2571 | cleanup_volume_info(&volume_info); | 2585 | cleanup_volume_info(&volume_info); |
2572 | FreeXid(xid); | ||
2573 | kfree(full_path); | ||
2574 | referral_walks_count++; | 2586 | referral_walks_count++; |
2575 | goto try_mount_again; | 2587 | goto try_mount_again; |
2576 | } | 2588 | } |
@@ -2739,6 +2751,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2739 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | 2751 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); |
2740 | 2752 | ||
2741 | /* mostly informational -- no need to fail on error here */ | 2753 | /* mostly informational -- no need to fail on error here */ |
2754 | kfree(tcon->nativeFileSystem); | ||
2742 | tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, | 2755 | tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, |
2743 | bytes_left, is_unicode, | 2756 | bytes_left, is_unicode, |
2744 | nls_codepage); | 2757 | nls_codepage); |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 3758965d73d5..4326ffd90fa9 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -188,6 +188,7 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
188 | FILE_UNIX_BASIC_INFO *presp_data; | 188 | FILE_UNIX_BASIC_INFO *presp_data; |
189 | __u32 posix_flags = 0; | 189 | __u32 posix_flags = 0; |
190 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 190 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
191 | struct cifs_fattr fattr; | ||
191 | 192 | ||
192 | cFYI(1, ("posix open %s", full_path)); | 193 | cFYI(1, ("posix open %s", full_path)); |
193 | 194 | ||
@@ -236,22 +237,21 @@ int cifs_posix_open(char *full_path, struct inode **pinode, | |||
236 | if (presp_data->Type == cpu_to_le32(-1)) | 237 | if (presp_data->Type == cpu_to_le32(-1)) |
237 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | 238 | goto posix_open_ret; /* open ok, caller does qpathinfo */ |
238 | 239 | ||
239 | /* get new inode and set it up */ | ||
240 | if (!pinode) | 240 | if (!pinode) |
241 | goto posix_open_ret; /* caller does not need info */ | 241 | goto posix_open_ret; /* caller does not need info */ |
242 | 242 | ||
243 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
244 | |||
245 | /* get new inode and set it up */ | ||
243 | if (*pinode == NULL) { | 246 | if (*pinode == NULL) { |
244 | __u64 unique_id = le64_to_cpu(presp_data->UniqueId); | 247 | *pinode = cifs_iget(sb, &fattr); |
245 | *pinode = cifs_new_inode(sb, &unique_id); | 248 | if (!*pinode) { |
249 | rc = -ENOMEM; | ||
250 | goto posix_open_ret; | ||
251 | } | ||
252 | } else { | ||
253 | cifs_fattr_to_inode(*pinode, &fattr); | ||
246 | } | 254 | } |
247 | /* else an inode was passed in. Update its info, don't create one */ | ||
248 | |||
249 | /* We do not need to close the file if new_inode fails since | ||
250 | the caller will retry qpathinfo as long as inode is null */ | ||
251 | if (*pinode == NULL) | ||
252 | goto posix_open_ret; | ||
253 | |||
254 | posix_fill_in_inode(*pinode, presp_data, 1); | ||
255 | 255 | ||
256 | cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); | 256 | cifs_fill_fileinfo(*pinode, *pnetfid, cifs_sb->tcon, write_only); |
257 | 257 | ||
@@ -307,8 +307,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
307 | 307 | ||
308 | full_path = build_path_from_dentry(direntry); | 308 | full_path = build_path_from_dentry(direntry); |
309 | if (full_path == NULL) { | 309 | if (full_path == NULL) { |
310 | rc = -ENOMEM; | ||
310 | FreeXid(xid); | 311 | FreeXid(xid); |
311 | return -ENOMEM; | 312 | return rc; |
312 | } | 313 | } |
313 | 314 | ||
314 | if (oplockEnabled) | 315 | if (oplockEnabled) |
@@ -424,9 +425,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
424 | args.uid = NO_CHANGE_64; | 425 | args.uid = NO_CHANGE_64; |
425 | args.gid = NO_CHANGE_64; | 426 | args.gid = NO_CHANGE_64; |
426 | } | 427 | } |
427 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, | 428 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
428 | cifs_sb->local_nls, | 429 | cifs_sb->local_nls, |
429 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 430 | cifs_sb->mnt_cifs_flags & |
431 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
430 | } else { | 432 | } else { |
431 | /* BB implement mode setting via Windows security | 433 | /* BB implement mode setting via Windows security |
432 | descriptors e.g. */ | 434 | descriptors e.g. */ |
@@ -514,10 +516,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
514 | args.uid = NO_CHANGE_64; | 516 | args.uid = NO_CHANGE_64; |
515 | args.gid = NO_CHANGE_64; | 517 | args.gid = NO_CHANGE_64; |
516 | } | 518 | } |
517 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, | 519 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, |
518 | &args, cifs_sb->local_nls, | 520 | cifs_sb->local_nls, |
519 | cifs_sb->mnt_cifs_flags & | 521 | cifs_sb->mnt_cifs_flags & |
520 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 522 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
521 | 523 | ||
522 | if (!rc) { | 524 | if (!rc) { |
523 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 525 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
@@ -540,8 +542,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
540 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | 542 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); |
541 | if (buf == NULL) { | 543 | if (buf == NULL) { |
542 | kfree(full_path); | 544 | kfree(full_path); |
545 | rc = -ENOMEM; | ||
543 | FreeXid(xid); | 546 | FreeXid(xid); |
544 | return -ENOMEM; | 547 | return rc; |
545 | } | 548 | } |
546 | 549 | ||
547 | rc = CIFSSMBOpen(xid, pTcon, full_path, | 550 | rc = CIFSSMBOpen(xid, pTcon, full_path, |
@@ -641,6 +644,15 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
641 | } | 644 | } |
642 | } | 645 | } |
643 | 646 | ||
647 | /* | ||
648 | * O_EXCL: optimize away the lookup, but don't hash the dentry. Let | ||
649 | * the VFS handle the create. | ||
650 | */ | ||
651 | if (nd->flags & LOOKUP_EXCL) { | ||
652 | d_instantiate(direntry, NULL); | ||
653 | return 0; | ||
654 | } | ||
655 | |||
644 | /* can not grab the rename sem here since it would | 656 | /* can not grab the rename sem here since it would |
645 | deadlock in the cases (beginning of sys_rename itself) | 657 | deadlock in the cases (beginning of sys_rename itself) |
646 | in which we already have the sb rename sem */ | 658 | in which we already have the sb rename sem */ |
diff --git a/fs/cifs/dns_resolve.c b/fs/cifs/dns_resolve.c index df4a306f697e..87948147d7ec 100644 --- a/fs/cifs/dns_resolve.c +++ b/fs/cifs/dns_resolve.c | |||
@@ -35,26 +35,11 @@ | |||
35 | * 0 - name is not IP | 35 | * 0 - name is not IP |
36 | */ | 36 | */ |
37 | static int | 37 | static int |
38 | is_ip(const char *name) | 38 | is_ip(char *name) |
39 | { | 39 | { |
40 | int rc; | 40 | struct sockaddr_storage ss; |
41 | struct sockaddr_in sin_server; | 41 | |
42 | struct sockaddr_in6 sin_server6; | 42 | return cifs_convert_address(name, &ss); |
43 | |||
44 | rc = cifs_inet_pton(AF_INET, name, | ||
45 | &sin_server.sin_addr.s_addr); | ||
46 | |||
47 | if (rc <= 0) { | ||
48 | /* not ipv4 address, try ipv6 */ | ||
49 | rc = cifs_inet_pton(AF_INET6, name, | ||
50 | &sin_server6.sin6_addr.in6_u); | ||
51 | if (rc > 0) | ||
52 | return 1; | ||
53 | } else { | ||
54 | return 1; | ||
55 | } | ||
56 | /* we failed translating address */ | ||
57 | return 0; | ||
58 | } | 43 | } |
59 | 44 | ||
60 | static int | 45 | static int |
@@ -72,7 +57,7 @@ dns_resolver_instantiate(struct key *key, const void *data, | |||
72 | ip[datalen] = '\0'; | 57 | ip[datalen] = '\0'; |
73 | 58 | ||
74 | /* make sure this looks like an address */ | 59 | /* make sure this looks like an address */ |
75 | if (!is_ip((const char *) ip)) { | 60 | if (!is_ip(ip)) { |
76 | kfree(ip); | 61 | kfree(ip); |
77 | return -EINVAL; | 62 | return -EINVAL; |
78 | } | 63 | } |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 06866841b97f..c34b7f8a217b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -300,14 +300,16 @@ int cifs_open(struct inode *inode, struct file *file) | |||
300 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 300 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
301 | pCifsFile = cifs_fill_filedata(file); | 301 | pCifsFile = cifs_fill_filedata(file); |
302 | if (pCifsFile) { | 302 | if (pCifsFile) { |
303 | rc = 0; | ||
303 | FreeXid(xid); | 304 | FreeXid(xid); |
304 | return 0; | 305 | return rc; |
305 | } | 306 | } |
306 | 307 | ||
307 | full_path = build_path_from_dentry(file->f_path.dentry); | 308 | full_path = build_path_from_dentry(file->f_path.dentry); |
308 | if (full_path == NULL) { | 309 | if (full_path == NULL) { |
310 | rc = -ENOMEM; | ||
309 | FreeXid(xid); | 311 | FreeXid(xid); |
310 | return -ENOMEM; | 312 | return rc; |
311 | } | 313 | } |
312 | 314 | ||
313 | cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", | 315 | cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", |
@@ -446,9 +448,9 @@ int cifs_open(struct inode *inode, struct file *file) | |||
446 | .mtime = NO_CHANGE_64, | 448 | .mtime = NO_CHANGE_64, |
447 | .device = 0, | 449 | .device = 0, |
448 | }; | 450 | }; |
449 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, | 451 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, |
450 | cifs_sb->local_nls, | 452 | cifs_sb->local_nls, |
451 | cifs_sb->mnt_cifs_flags & | 453 | cifs_sb->mnt_cifs_flags & |
452 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 454 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
453 | } | 455 | } |
454 | } | 456 | } |
@@ -491,11 +493,12 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
491 | return -EBADF; | 493 | return -EBADF; |
492 | 494 | ||
493 | xid = GetXid(); | 495 | xid = GetXid(); |
494 | mutex_unlock(&pCifsFile->fh_mutex); | 496 | mutex_lock(&pCifsFile->fh_mutex); |
495 | if (!pCifsFile->invalidHandle) { | 497 | if (!pCifsFile->invalidHandle) { |
496 | mutex_lock(&pCifsFile->fh_mutex); | 498 | mutex_unlock(&pCifsFile->fh_mutex); |
499 | rc = 0; | ||
497 | FreeXid(xid); | 500 | FreeXid(xid); |
498 | return 0; | 501 | return rc; |
499 | } | 502 | } |
500 | 503 | ||
501 | if (file->f_path.dentry == NULL) { | 504 | if (file->f_path.dentry == NULL) { |
@@ -524,7 +527,7 @@ static int cifs_reopen_file(struct file *file, bool can_flush) | |||
524 | if (full_path == NULL) { | 527 | if (full_path == NULL) { |
525 | rc = -ENOMEM; | 528 | rc = -ENOMEM; |
526 | reopen_error_exit: | 529 | reopen_error_exit: |
527 | mutex_lock(&pCifsFile->fh_mutex); | 530 | mutex_unlock(&pCifsFile->fh_mutex); |
528 | FreeXid(xid); | 531 | FreeXid(xid); |
529 | return rc; | 532 | return rc; |
530 | } | 533 | } |
@@ -566,14 +569,14 @@ reopen_error_exit: | |||
566 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 569 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
567 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 570 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
568 | if (rc) { | 571 | if (rc) { |
569 | mutex_lock(&pCifsFile->fh_mutex); | 572 | mutex_unlock(&pCifsFile->fh_mutex); |
570 | cFYI(1, ("cifs_open returned 0x%x", rc)); | 573 | cFYI(1, ("cifs_open returned 0x%x", rc)); |
571 | cFYI(1, ("oplock: %d", oplock)); | 574 | cFYI(1, ("oplock: %d", oplock)); |
572 | } else { | 575 | } else { |
573 | reopen_success: | 576 | reopen_success: |
574 | pCifsFile->netfid = netfid; | 577 | pCifsFile->netfid = netfid; |
575 | pCifsFile->invalidHandle = false; | 578 | pCifsFile->invalidHandle = false; |
576 | mutex_lock(&pCifsFile->fh_mutex); | 579 | mutex_unlock(&pCifsFile->fh_mutex); |
577 | pCifsInode = CIFS_I(inode); | 580 | pCifsInode = CIFS_I(inode); |
578 | if (pCifsInode) { | 581 | if (pCifsInode) { |
579 | if (can_flush) { | 582 | if (can_flush) { |
@@ -845,8 +848,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) | |||
845 | tcon = cifs_sb->tcon; | 848 | tcon = cifs_sb->tcon; |
846 | 849 | ||
847 | if (file->private_data == NULL) { | 850 | if (file->private_data == NULL) { |
851 | rc = -EBADF; | ||
848 | FreeXid(xid); | 852 | FreeXid(xid); |
849 | return -EBADF; | 853 | return rc; |
850 | } | 854 | } |
851 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; | 855 | netfid = ((struct cifsFileInfo *)file->private_data)->netfid; |
852 | 856 | ||
@@ -1805,8 +1809,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1805 | pTcon = cifs_sb->tcon; | 1809 | pTcon = cifs_sb->tcon; |
1806 | 1810 | ||
1807 | if (file->private_data == NULL) { | 1811 | if (file->private_data == NULL) { |
1812 | rc = -EBADF; | ||
1808 | FreeXid(xid); | 1813 | FreeXid(xid); |
1809 | return -EBADF; | 1814 | return rc; |
1810 | } | 1815 | } |
1811 | open_file = (struct cifsFileInfo *)file->private_data; | 1816 | open_file = (struct cifsFileInfo *)file->private_data; |
1812 | 1817 | ||
@@ -1885,8 +1890,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1885 | pTcon = cifs_sb->tcon; | 1890 | pTcon = cifs_sb->tcon; |
1886 | 1891 | ||
1887 | if (file->private_data == NULL) { | 1892 | if (file->private_data == NULL) { |
1893 | rc = -EBADF; | ||
1888 | FreeXid(xid); | 1894 | FreeXid(xid); |
1889 | return -EBADF; | 1895 | return rc; |
1890 | } | 1896 | } |
1891 | open_file = (struct cifsFileInfo *)file->private_data; | 1897 | open_file = (struct cifsFileInfo *)file->private_data; |
1892 | 1898 | ||
@@ -2019,8 +2025,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
2019 | 2025 | ||
2020 | xid = GetXid(); | 2026 | xid = GetXid(); |
2021 | if (file->private_data == NULL) { | 2027 | if (file->private_data == NULL) { |
2028 | rc = -EBADF; | ||
2022 | FreeXid(xid); | 2029 | FreeXid(xid); |
2023 | return -EBADF; | 2030 | return rc; |
2024 | } | 2031 | } |
2025 | open_file = (struct cifsFileInfo *)file->private_data; | 2032 | open_file = (struct cifsFileInfo *)file->private_data; |
2026 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 2033 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); |
@@ -2185,8 +2192,9 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
2185 | xid = GetXid(); | 2192 | xid = GetXid(); |
2186 | 2193 | ||
2187 | if (file->private_data == NULL) { | 2194 | if (file->private_data == NULL) { |
2195 | rc = -EBADF; | ||
2188 | FreeXid(xid); | 2196 | FreeXid(xid); |
2189 | return -EBADF; | 2197 | return rc; |
2190 | } | 2198 | } |
2191 | 2199 | ||
2192 | cFYI(1, ("readpage %p at offset %d 0x%x\n", | 2200 | cFYI(1, ("readpage %p at offset %d 0x%x\n", |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fad882b075ba..82d83839655e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -77,239 +77,202 @@ static void cifs_set_ops(struct inode *inode, const bool is_dfs_referral) | |||
77 | } | 77 | } |
78 | } | 78 | } |
79 | 79 | ||
80 | static void cifs_unix_info_to_inode(struct inode *inode, | 80 | /* populate an inode with info from a cifs_fattr struct */ |
81 | FILE_UNIX_BASIC_INFO *info, int force_uid_gid) | 81 | void |
82 | cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr) | ||
82 | { | 83 | { |
84 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | ||
83 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 85 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
84 | struct cifsInodeInfo *cifsInfo = CIFS_I(inode); | 86 | unsigned long oldtime = cifs_i->time; |
85 | __u64 num_of_bytes = le64_to_cpu(info->NumOfBytes); | 87 | |
86 | __u64 end_of_file = le64_to_cpu(info->EndOfFile); | 88 | inode->i_atime = fattr->cf_atime; |
89 | inode->i_mtime = fattr->cf_mtime; | ||
90 | inode->i_ctime = fattr->cf_ctime; | ||
91 | inode->i_rdev = fattr->cf_rdev; | ||
92 | inode->i_nlink = fattr->cf_nlink; | ||
93 | inode->i_uid = fattr->cf_uid; | ||
94 | inode->i_gid = fattr->cf_gid; | ||
95 | |||
96 | /* if dynperm is set, don't clobber existing mode */ | ||
97 | if (inode->i_state & I_NEW || | ||
98 | !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) | ||
99 | inode->i_mode = fattr->cf_mode; | ||
100 | |||
101 | cifs_i->cifsAttrs = fattr->cf_cifsattrs; | ||
102 | cifs_i->uniqueid = fattr->cf_uniqueid; | ||
103 | |||
104 | if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL) | ||
105 | cifs_i->time = 0; | ||
106 | else | ||
107 | cifs_i->time = jiffies; | ||
108 | |||
109 | cFYI(1, ("inode 0x%p old_time=%ld new_time=%ld", inode, | ||
110 | oldtime, cifs_i->time)); | ||
87 | 111 | ||
88 | inode->i_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 112 | cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING; |
89 | inode->i_mtime = | 113 | |
90 | cifs_NTtimeToUnix(info->LastModificationTime); | 114 | /* |
91 | inode->i_ctime = cifs_NTtimeToUnix(info->LastStatusChange); | 115 | * Can't safely change the file size here if the client is writing to |
92 | inode->i_mode = le64_to_cpu(info->Permissions); | 116 | * it due to potential races. |
117 | */ | ||
118 | spin_lock(&inode->i_lock); | ||
119 | if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) { | ||
120 | i_size_write(inode, fattr->cf_eof); | ||
121 | |||
122 | /* | ||
123 | * i_blocks is not related to (i_size / i_blksize), | ||
124 | * but instead 512 byte (2**9) size is required for | ||
125 | * calculating num blocks. | ||
126 | */ | ||
127 | inode->i_blocks = (512 - 1 + fattr->cf_bytes) >> 9; | ||
128 | } | ||
129 | spin_unlock(&inode->i_lock); | ||
130 | |||
131 | cifs_set_ops(inode, fattr->cf_flags & CIFS_FATTR_DFS_REFERRAL); | ||
132 | } | ||
133 | |||
134 | /* Fill a cifs_fattr struct with info from FILE_UNIX_BASIC_INFO. */ | ||
135 | void | ||
136 | cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, | ||
137 | struct cifs_sb_info *cifs_sb) | ||
138 | { | ||
139 | memset(fattr, 0, sizeof(*fattr)); | ||
140 | fattr->cf_uniqueid = le64_to_cpu(info->UniqueId); | ||
141 | fattr->cf_bytes = le64_to_cpu(info->NumOfBytes); | ||
142 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | ||
143 | |||
144 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | ||
145 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastModificationTime); | ||
146 | fattr->cf_ctime = cifs_NTtimeToUnix(info->LastStatusChange); | ||
147 | fattr->cf_mode = le64_to_cpu(info->Permissions); | ||
93 | 148 | ||
94 | /* | 149 | /* |
95 | * Since we set the inode type below we need to mask off | 150 | * Since we set the inode type below we need to mask off |
96 | * to avoid strange results if bits set above. | 151 | * to avoid strange results if bits set above. |
97 | */ | 152 | */ |
98 | inode->i_mode &= ~S_IFMT; | 153 | fattr->cf_mode &= ~S_IFMT; |
99 | switch (le32_to_cpu(info->Type)) { | 154 | switch (le32_to_cpu(info->Type)) { |
100 | case UNIX_FILE: | 155 | case UNIX_FILE: |
101 | inode->i_mode |= S_IFREG; | 156 | fattr->cf_mode |= S_IFREG; |
157 | fattr->cf_dtype = DT_REG; | ||
102 | break; | 158 | break; |
103 | case UNIX_SYMLINK: | 159 | case UNIX_SYMLINK: |
104 | inode->i_mode |= S_IFLNK; | 160 | fattr->cf_mode |= S_IFLNK; |
161 | fattr->cf_dtype = DT_LNK; | ||
105 | break; | 162 | break; |
106 | case UNIX_DIR: | 163 | case UNIX_DIR: |
107 | inode->i_mode |= S_IFDIR; | 164 | fattr->cf_mode |= S_IFDIR; |
165 | fattr->cf_dtype = DT_DIR; | ||
108 | break; | 166 | break; |
109 | case UNIX_CHARDEV: | 167 | case UNIX_CHARDEV: |
110 | inode->i_mode |= S_IFCHR; | 168 | fattr->cf_mode |= S_IFCHR; |
111 | inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor), | 169 | fattr->cf_dtype = DT_CHR; |
112 | le64_to_cpu(info->DevMinor) & MINORMASK); | 170 | fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), |
171 | le64_to_cpu(info->DevMinor) & MINORMASK); | ||
113 | break; | 172 | break; |
114 | case UNIX_BLOCKDEV: | 173 | case UNIX_BLOCKDEV: |
115 | inode->i_mode |= S_IFBLK; | 174 | fattr->cf_mode |= S_IFBLK; |
116 | inode->i_rdev = MKDEV(le64_to_cpu(info->DevMajor), | 175 | fattr->cf_dtype = DT_BLK; |
117 | le64_to_cpu(info->DevMinor) & MINORMASK); | 176 | fattr->cf_rdev = MKDEV(le64_to_cpu(info->DevMajor), |
177 | le64_to_cpu(info->DevMinor) & MINORMASK); | ||
118 | break; | 178 | break; |
119 | case UNIX_FIFO: | 179 | case UNIX_FIFO: |
120 | inode->i_mode |= S_IFIFO; | 180 | fattr->cf_mode |= S_IFIFO; |
181 | fattr->cf_dtype = DT_FIFO; | ||
121 | break; | 182 | break; |
122 | case UNIX_SOCKET: | 183 | case UNIX_SOCKET: |
123 | inode->i_mode |= S_IFSOCK; | 184 | fattr->cf_mode |= S_IFSOCK; |
185 | fattr->cf_dtype = DT_SOCK; | ||
124 | break; | 186 | break; |
125 | default: | 187 | default: |
126 | /* safest to call it a file if we do not know */ | 188 | /* safest to call it a file if we do not know */ |
127 | inode->i_mode |= S_IFREG; | 189 | fattr->cf_mode |= S_IFREG; |
190 | fattr->cf_dtype = DT_REG; | ||
128 | cFYI(1, ("unknown type %d", le32_to_cpu(info->Type))); | 191 | cFYI(1, ("unknown type %d", le32_to_cpu(info->Type))); |
129 | break; | 192 | break; |
130 | } | 193 | } |
131 | 194 | ||
132 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) && | 195 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) |
133 | !force_uid_gid) | 196 | fattr->cf_uid = cifs_sb->mnt_uid; |
134 | inode->i_uid = cifs_sb->mnt_uid; | ||
135 | else | 197 | else |
136 | inode->i_uid = le64_to_cpu(info->Uid); | 198 | fattr->cf_uid = le64_to_cpu(info->Uid); |
137 | 199 | ||
138 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) && | 200 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) |
139 | !force_uid_gid) | 201 | fattr->cf_gid = cifs_sb->mnt_gid; |
140 | inode->i_gid = cifs_sb->mnt_gid; | ||
141 | else | 202 | else |
142 | inode->i_gid = le64_to_cpu(info->Gid); | 203 | fattr->cf_gid = le64_to_cpu(info->Gid); |
143 | |||
144 | inode->i_nlink = le64_to_cpu(info->Nlinks); | ||
145 | |||
146 | cifsInfo->server_eof = end_of_file; | ||
147 | spin_lock(&inode->i_lock); | ||
148 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | ||
149 | /* | ||
150 | * We can not safely change the file size here if the client | ||
151 | * is writing to it due to potential races. | ||
152 | */ | ||
153 | i_size_write(inode, end_of_file); | ||
154 | 204 | ||
155 | /* | 205 | fattr->cf_nlink = le64_to_cpu(info->Nlinks); |
156 | * i_blocks is not related to (i_size / i_blksize), | ||
157 | * but instead 512 byte (2**9) size is required for | ||
158 | * calculating num blocks. | ||
159 | */ | ||
160 | inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
161 | } | ||
162 | spin_unlock(&inode->i_lock); | ||
163 | } | 206 | } |
164 | 207 | ||
165 | |||
166 | /* | 208 | /* |
167 | * Needed to setup inode data for the directory which is the | 209 | * Fill a cifs_fattr struct with fake inode info. |
168 | * junction to the new submount (ie to setup the fake directory | ||
169 | * which represents a DFS referral) | ||
170 | */ | ||
171 | static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat, | ||
172 | struct super_block *sb) | ||
173 | { | ||
174 | struct inode *pinode = NULL; | ||
175 | |||
176 | memset(pfnd_dat, 0, sizeof(FILE_UNIX_BASIC_INFO)); | ||
177 | |||
178 | /* __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); | ||
179 | __le64 pfnd_dat->NumOfBytes = cpu_to_le64(0); | ||
180 | __u64 UniqueId = 0; */ | ||
181 | pfnd_dat->LastStatusChange = | ||
182 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
183 | pfnd_dat->LastAccessTime = | ||
184 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
185 | pfnd_dat->LastModificationTime = | ||
186 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | ||
187 | pfnd_dat->Type = cpu_to_le32(UNIX_DIR); | ||
188 | pfnd_dat->Permissions = cpu_to_le64(S_IXUGO | S_IRWXU); | ||
189 | pfnd_dat->Nlinks = cpu_to_le64(2); | ||
190 | if (sb->s_root) | ||
191 | pinode = sb->s_root->d_inode; | ||
192 | if (pinode == NULL) | ||
193 | return; | ||
194 | |||
195 | /* fill in default values for the remaining based on root | ||
196 | inode since we can not query the server for this inode info */ | ||
197 | pfnd_dat->DevMajor = cpu_to_le64(MAJOR(pinode->i_rdev)); | ||
198 | pfnd_dat->DevMinor = cpu_to_le64(MINOR(pinode->i_rdev)); | ||
199 | pfnd_dat->Uid = cpu_to_le64(pinode->i_uid); | ||
200 | pfnd_dat->Gid = cpu_to_le64(pinode->i_gid); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * cifs_new inode - create new inode, initialize, and hash it | ||
205 | * @sb - pointer to superblock | ||
206 | * @inum - if valid pointer and serverino is enabled, replace i_ino with val | ||
207 | * | ||
208 | * Create a new inode, initialize it for CIFS and hash it. Returns the new | ||
209 | * inode or NULL if one couldn't be allocated. | ||
210 | * | 210 | * |
211 | * If the share isn't mounted with "serverino" or inum is a NULL pointer then | 211 | * Needed to setup cifs_fattr data for the directory which is the |
212 | * we'll just use the inode number assigned by new_inode(). Note that this can | 212 | * junction to the new submount (ie to setup the fake directory |
213 | * mean i_ino collisions since the i_ino assigned by new_inode is not | 213 | * which represents a DFS referral). |
214 | * guaranteed to be unique. | ||
215 | */ | 214 | */ |
216 | struct inode * | 215 | static void |
217 | cifs_new_inode(struct super_block *sb, __u64 *inum) | 216 | cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb) |
218 | { | 217 | { |
219 | struct inode *inode; | 218 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
220 | |||
221 | inode = new_inode(sb); | ||
222 | if (inode == NULL) | ||
223 | return NULL; | ||
224 | |||
225 | /* | ||
226 | * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we | ||
227 | * stop passing inum as ptr. Are there sanity checks we can use to | ||
228 | * ensure that the server is really filling in that field? Also, | ||
229 | * if serverino is disabled, perhaps we should be using iunique()? | ||
230 | */ | ||
231 | if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) | ||
232 | inode->i_ino = (unsigned long) *inum; | ||
233 | |||
234 | /* | ||
235 | * must set this here instead of cifs_alloc_inode since VFS will | ||
236 | * clobber i_flags | ||
237 | */ | ||
238 | if (sb->s_flags & MS_NOATIME) | ||
239 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
240 | |||
241 | insert_inode_hash(inode); | ||
242 | 219 | ||
243 | return inode; | 220 | cFYI(1, ("creating fake fattr for DFS referral")); |
221 | |||
222 | memset(fattr, 0, sizeof(*fattr)); | ||
223 | fattr->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU; | ||
224 | fattr->cf_uid = cifs_sb->mnt_uid; | ||
225 | fattr->cf_gid = cifs_sb->mnt_gid; | ||
226 | fattr->cf_atime = CURRENT_TIME; | ||
227 | fattr->cf_ctime = CURRENT_TIME; | ||
228 | fattr->cf_mtime = CURRENT_TIME; | ||
229 | fattr->cf_nlink = 2; | ||
230 | fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL; | ||
244 | } | 231 | } |
245 | 232 | ||
246 | int cifs_get_inode_info_unix(struct inode **pinode, | 233 | int cifs_get_inode_info_unix(struct inode **pinode, |
247 | const unsigned char *full_path, struct super_block *sb, int xid) | 234 | const unsigned char *full_path, |
235 | struct super_block *sb, int xid) | ||
248 | { | 236 | { |
249 | int rc = 0; | 237 | int rc; |
250 | FILE_UNIX_BASIC_INFO find_data; | 238 | FILE_UNIX_BASIC_INFO find_data; |
251 | struct cifsTconInfo *pTcon; | 239 | struct cifs_fattr fattr; |
252 | struct inode *inode; | 240 | struct cifsTconInfo *tcon; |
253 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 241 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
254 | bool is_dfs_referral = false; | ||
255 | struct cifsInodeInfo *cifsInfo; | ||
256 | __u64 num_of_bytes; | ||
257 | __u64 end_of_file; | ||
258 | 242 | ||
259 | pTcon = cifs_sb->tcon; | 243 | tcon = cifs_sb->tcon; |
260 | cFYI(1, ("Getting info on %s", full_path)); | 244 | cFYI(1, ("Getting info on %s", full_path)); |
261 | 245 | ||
262 | /* could have done a find first instead but this returns more info */ | 246 | /* could have done a find first instead but this returns more info */ |
263 | rc = CIFSSMBUnixQPathInfo(xid, pTcon, full_path, &find_data, | 247 | rc = CIFSSMBUnixQPathInfo(xid, tcon, full_path, &find_data, |
264 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 248 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
265 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 249 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
266 | if (rc == -EREMOTE && !is_dfs_referral) { | ||
267 | is_dfs_referral = true; | ||
268 | cFYI(DBG2, ("DFS ref")); | ||
269 | /* for DFS, server does not give us real inode data */ | ||
270 | fill_fake_finddataunix(&find_data, sb); | ||
271 | rc = 0; | ||
272 | } else if (rc) | ||
273 | goto cgiiu_exit; | ||
274 | 250 | ||
275 | num_of_bytes = le64_to_cpu(find_data.NumOfBytes); | 251 | if (!rc) { |
276 | end_of_file = le64_to_cpu(find_data.EndOfFile); | 252 | cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb); |
253 | } else if (rc == -EREMOTE) { | ||
254 | cifs_create_dfs_fattr(&fattr, sb); | ||
255 | rc = 0; | ||
256 | } else { | ||
257 | return rc; | ||
258 | } | ||
277 | 259 | ||
278 | /* get new inode */ | ||
279 | if (*pinode == NULL) { | 260 | if (*pinode == NULL) { |
280 | __u64 unique_id = le64_to_cpu(find_data.UniqueId); | 261 | /* get new inode */ |
281 | *pinode = cifs_new_inode(sb, &unique_id); | 262 | *pinode = cifs_iget(sb, &fattr); |
282 | if (*pinode == NULL) { | 263 | if (!*pinode) |
283 | rc = -ENOMEM; | 264 | rc = -ENOMEM; |
284 | goto cgiiu_exit; | 265 | } else { |
285 | } | 266 | /* we already have inode, update it */ |
267 | cifs_fattr_to_inode(*pinode, &fattr); | ||
286 | } | 268 | } |
287 | 269 | ||
288 | inode = *pinode; | ||
289 | cifsInfo = CIFS_I(inode); | ||
290 | |||
291 | cFYI(1, ("Old time %ld", cifsInfo->time)); | ||
292 | cifsInfo->time = jiffies; | ||
293 | cFYI(1, ("New time %ld", cifsInfo->time)); | ||
294 | /* this is ok to set on every inode revalidate */ | ||
295 | atomic_set(&cifsInfo->inUse, 1); | ||
296 | |||
297 | cifs_unix_info_to_inode(inode, &find_data, 0); | ||
298 | |||
299 | if (num_of_bytes < end_of_file) | ||
300 | cFYI(1, ("allocation size less than end of file")); | ||
301 | cFYI(1, ("Size %ld and blocks %llu", | ||
302 | (unsigned long) inode->i_size, | ||
303 | (unsigned long long)inode->i_blocks)); | ||
304 | |||
305 | cifs_set_ops(inode, is_dfs_referral); | ||
306 | cgiiu_exit: | ||
307 | return rc; | 270 | return rc; |
308 | } | 271 | } |
309 | 272 | ||
310 | static int decode_sfu_inode(struct inode *inode, __u64 size, | 273 | static int |
311 | const unsigned char *path, | 274 | cifs_sfu_type(struct cifs_fattr *fattr, const unsigned char *path, |
312 | struct cifs_sb_info *cifs_sb, int xid) | 275 | struct cifs_sb_info *cifs_sb, int xid) |
313 | { | 276 | { |
314 | int rc; | 277 | int rc; |
315 | int oplock = 0; | 278 | int oplock = 0; |
@@ -321,10 +284,15 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
321 | 284 | ||
322 | pbuf = buf; | 285 | pbuf = buf; |
323 | 286 | ||
324 | if (size == 0) { | 287 | fattr->cf_mode &= ~S_IFMT; |
325 | inode->i_mode |= S_IFIFO; | 288 | |
289 | if (fattr->cf_eof == 0) { | ||
290 | fattr->cf_mode |= S_IFIFO; | ||
291 | fattr->cf_dtype = DT_FIFO; | ||
326 | return 0; | 292 | return 0; |
327 | } else if (size < 8) { | 293 | } else if (fattr->cf_eof < 8) { |
294 | fattr->cf_mode |= S_IFREG; | ||
295 | fattr->cf_dtype = DT_REG; | ||
328 | return -EINVAL; /* EOPNOTSUPP? */ | 296 | return -EINVAL; /* EOPNOTSUPP? */ |
329 | } | 297 | } |
330 | 298 | ||
@@ -336,42 +304,46 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
336 | if (rc == 0) { | 304 | if (rc == 0) { |
337 | int buf_type = CIFS_NO_BUFFER; | 305 | int buf_type = CIFS_NO_BUFFER; |
338 | /* Read header */ | 306 | /* Read header */ |
339 | rc = CIFSSMBRead(xid, pTcon, | 307 | rc = CIFSSMBRead(xid, pTcon, netfid, |
340 | netfid, | ||
341 | 24 /* length */, 0 /* offset */, | 308 | 24 /* length */, 0 /* offset */, |
342 | &bytes_read, &pbuf, &buf_type); | 309 | &bytes_read, &pbuf, &buf_type); |
343 | if ((rc == 0) && (bytes_read >= 8)) { | 310 | if ((rc == 0) && (bytes_read >= 8)) { |
344 | if (memcmp("IntxBLK", pbuf, 8) == 0) { | 311 | if (memcmp("IntxBLK", pbuf, 8) == 0) { |
345 | cFYI(1, ("Block device")); | 312 | cFYI(1, ("Block device")); |
346 | inode->i_mode |= S_IFBLK; | 313 | fattr->cf_mode |= S_IFBLK; |
314 | fattr->cf_dtype = DT_BLK; | ||
347 | if (bytes_read == 24) { | 315 | if (bytes_read == 24) { |
348 | /* we have enough to decode dev num */ | 316 | /* we have enough to decode dev num */ |
349 | __u64 mjr; /* major */ | 317 | __u64 mjr; /* major */ |
350 | __u64 mnr; /* minor */ | 318 | __u64 mnr; /* minor */ |
351 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); | 319 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); |
352 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); | 320 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
353 | inode->i_rdev = MKDEV(mjr, mnr); | 321 | fattr->cf_rdev = MKDEV(mjr, mnr); |
354 | } | 322 | } |
355 | } else if (memcmp("IntxCHR", pbuf, 8) == 0) { | 323 | } else if (memcmp("IntxCHR", pbuf, 8) == 0) { |
356 | cFYI(1, ("Char device")); | 324 | cFYI(1, ("Char device")); |
357 | inode->i_mode |= S_IFCHR; | 325 | fattr->cf_mode |= S_IFCHR; |
326 | fattr->cf_dtype = DT_CHR; | ||
358 | if (bytes_read == 24) { | 327 | if (bytes_read == 24) { |
359 | /* we have enough to decode dev num */ | 328 | /* we have enough to decode dev num */ |
360 | __u64 mjr; /* major */ | 329 | __u64 mjr; /* major */ |
361 | __u64 mnr; /* minor */ | 330 | __u64 mnr; /* minor */ |
362 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); | 331 | mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); |
363 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); | 332 | mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); |
364 | inode->i_rdev = MKDEV(mjr, mnr); | 333 | fattr->cf_rdev = MKDEV(mjr, mnr); |
365 | } | 334 | } |
366 | } else if (memcmp("IntxLNK", pbuf, 7) == 0) { | 335 | } else if (memcmp("IntxLNK", pbuf, 7) == 0) { |
367 | cFYI(1, ("Symlink")); | 336 | cFYI(1, ("Symlink")); |
368 | inode->i_mode |= S_IFLNK; | 337 | fattr->cf_mode |= S_IFLNK; |
338 | fattr->cf_dtype = DT_LNK; | ||
369 | } else { | 339 | } else { |
370 | inode->i_mode |= S_IFREG; /* file? */ | 340 | fattr->cf_mode |= S_IFREG; /* file? */ |
341 | fattr->cf_dtype = DT_REG; | ||
371 | rc = -EOPNOTSUPP; | 342 | rc = -EOPNOTSUPP; |
372 | } | 343 | } |
373 | } else { | 344 | } else { |
374 | inode->i_mode |= S_IFREG; /* then it is a file */ | 345 | fattr->cf_mode |= S_IFREG; /* then it is a file */ |
346 | fattr->cf_dtype = DT_REG; | ||
375 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ | 347 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ |
376 | } | 348 | } |
377 | CIFSSMBClose(xid, pTcon, netfid); | 349 | CIFSSMBClose(xid, pTcon, netfid); |
@@ -381,9 +353,13 @@ static int decode_sfu_inode(struct inode *inode, __u64 size, | |||
381 | 353 | ||
382 | #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ | 354 | #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ |
383 | 355 | ||
384 | static int get_sfu_mode(struct inode *inode, | 356 | /* |
385 | const unsigned char *path, | 357 | * Fetch mode bits as provided by SFU. |
386 | struct cifs_sb_info *cifs_sb, int xid) | 358 | * |
359 | * FIXME: Doesn't this clobber the type bit we got from cifs_sfu_type ? | ||
360 | */ | ||
361 | static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path, | ||
362 | struct cifs_sb_info *cifs_sb, int xid) | ||
387 | { | 363 | { |
388 | #ifdef CONFIG_CIFS_XATTR | 364 | #ifdef CONFIG_CIFS_XATTR |
389 | ssize_t rc; | 365 | ssize_t rc; |
@@ -391,68 +367,80 @@ static int get_sfu_mode(struct inode *inode, | |||
391 | __u32 mode; | 367 | __u32 mode; |
392 | 368 | ||
393 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", | 369 | rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", |
394 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, | 370 | ea_value, 4 /* size of buf */, cifs_sb->local_nls, |
395 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 371 | cifs_sb->mnt_cifs_flags & |
372 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
396 | if (rc < 0) | 373 | if (rc < 0) |
397 | return (int)rc; | 374 | return (int)rc; |
398 | else if (rc > 3) { | 375 | else if (rc > 3) { |
399 | mode = le32_to_cpu(*((__le32 *)ea_value)); | 376 | mode = le32_to_cpu(*((__le32 *)ea_value)); |
400 | inode->i_mode &= ~SFBITS_MASK; | 377 | fattr->cf_mode &= ~SFBITS_MASK; |
401 | cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode)); | 378 | cFYI(1, ("special bits 0%o org mode 0%o", mode, |
402 | inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; | 379 | fattr->cf_mode)); |
380 | fattr->cf_mode = (mode & SFBITS_MASK) | fattr->cf_mode; | ||
403 | cFYI(1, ("special mode bits 0%o", mode)); | 381 | cFYI(1, ("special mode bits 0%o", mode)); |
404 | return 0; | ||
405 | } else { | ||
406 | return 0; | ||
407 | } | 382 | } |
383 | |||
384 | return 0; | ||
408 | #else | 385 | #else |
409 | return -EOPNOTSUPP; | 386 | return -EOPNOTSUPP; |
410 | #endif | 387 | #endif |
411 | } | 388 | } |
412 | 389 | ||
413 | /* | 390 | /* Fill a cifs_fattr struct with info from FILE_ALL_INFO */ |
414 | * Needed to setup inode data for the directory which is the | 391 | static void |
415 | * junction to the new submount (ie to setup the fake directory | 392 | cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, |
416 | * which represents a DFS referral) | 393 | struct cifs_sb_info *cifs_sb, bool adjust_tz) |
417 | */ | ||
418 | static void fill_fake_finddata(FILE_ALL_INFO *pfnd_dat, | ||
419 | struct super_block *sb) | ||
420 | { | 394 | { |
421 | memset(pfnd_dat, 0, sizeof(FILE_ALL_INFO)); | 395 | memset(fattr, 0, sizeof(*fattr)); |
422 | 396 | fattr->cf_cifsattrs = le32_to_cpu(info->Attributes); | |
423 | /* __le64 pfnd_dat->AllocationSize = cpu_to_le64(0); | 397 | if (info->DeletePending) |
424 | __le64 pfnd_dat->EndOfFile = cpu_to_le64(0); | 398 | fattr->cf_flags |= CIFS_FATTR_DELETE_PENDING; |
425 | __u8 pfnd_dat->DeletePending = 0; | 399 | |
426 | __u8 pfnd_data->Directory = 0; | 400 | if (info->LastAccessTime) |
427 | __le32 pfnd_dat->EASize = 0; | 401 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
428 | __u64 pfnd_dat->IndexNumber = 0; | 402 | else |
429 | __u64 pfnd_dat->IndexNumber1 = 0; */ | 403 | fattr->cf_atime = CURRENT_TIME; |
430 | pfnd_dat->CreationTime = | 404 | |
431 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 405 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
432 | pfnd_dat->LastAccessTime = | 406 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
433 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 407 | |
434 | pfnd_dat->LastWriteTime = | 408 | if (adjust_tz) { |
435 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 409 | fattr->cf_ctime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; |
436 | pfnd_dat->ChangeTime = | 410 | fattr->cf_mtime.tv_sec += cifs_sb->tcon->ses->server->timeAdj; |
437 | cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); | 411 | } |
438 | pfnd_dat->Attributes = cpu_to_le32(ATTR_DIRECTORY); | 412 | |
439 | pfnd_dat->NumberOfLinks = cpu_to_le32(2); | 413 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
414 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | ||
415 | |||
416 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | ||
417 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | ||
418 | fattr->cf_dtype = DT_DIR; | ||
419 | } else { | ||
420 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; | ||
421 | fattr->cf_dtype = DT_REG; | ||
422 | |||
423 | /* clear write bits if ATTR_READONLY is set */ | ||
424 | if (fattr->cf_cifsattrs & ATTR_READONLY) | ||
425 | fattr->cf_mode &= ~(S_IWUGO); | ||
426 | } | ||
427 | |||
428 | fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); | ||
429 | |||
430 | fattr->cf_uid = cifs_sb->mnt_uid; | ||
431 | fattr->cf_gid = cifs_sb->mnt_gid; | ||
440 | } | 432 | } |
441 | 433 | ||
442 | int cifs_get_inode_info(struct inode **pinode, | 434 | int cifs_get_inode_info(struct inode **pinode, |
443 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, | 435 | const unsigned char *full_path, FILE_ALL_INFO *pfindData, |
444 | struct super_block *sb, int xid, const __u16 *pfid) | 436 | struct super_block *sb, int xid, const __u16 *pfid) |
445 | { | 437 | { |
446 | int rc = 0; | 438 | int rc = 0, tmprc; |
447 | __u32 attr; | ||
448 | struct cifsInodeInfo *cifsInfo; | ||
449 | struct cifsTconInfo *pTcon; | 439 | struct cifsTconInfo *pTcon; |
450 | struct inode *inode; | ||
451 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 440 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
452 | char *buf = NULL; | 441 | char *buf = NULL; |
453 | bool adjustTZ = false; | 442 | bool adjustTZ = false; |
454 | bool is_dfs_referral = false; | 443 | struct cifs_fattr fattr; |
455 | umode_t default_mode; | ||
456 | 444 | ||
457 | pTcon = cifs_sb->tcon; | 445 | pTcon = cifs_sb->tcon; |
458 | cFYI(1, ("Getting info on %s", full_path)); | 446 | cFYI(1, ("Getting info on %s", full_path)); |
@@ -487,163 +475,85 @@ int cifs_get_inode_info(struct inode **pinode, | |||
487 | adjustTZ = true; | 475 | adjustTZ = true; |
488 | } | 476 | } |
489 | } | 477 | } |
490 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 478 | |
491 | if (rc == -EREMOTE) { | 479 | if (!rc) { |
492 | is_dfs_referral = true; | 480 | cifs_all_info_to_fattr(&fattr, (FILE_ALL_INFO *) pfindData, |
493 | fill_fake_finddata(pfindData, sb); | 481 | cifs_sb, adjustTZ); |
482 | } else if (rc == -EREMOTE) { | ||
483 | cifs_create_dfs_fattr(&fattr, sb); | ||
494 | rc = 0; | 484 | rc = 0; |
495 | } else if (rc) | 485 | } else { |
496 | goto cgii_exit; | 486 | goto cgii_exit; |
487 | } | ||
497 | 488 | ||
498 | attr = le32_to_cpu(pfindData->Attributes); | 489 | /* |
499 | 490 | * If an inode wasn't passed in, then get the inode number | |
500 | /* get new inode */ | 491 | * |
492 | * Is an i_ino of zero legal? Can we use that to check if the server | ||
493 | * supports returning inode numbers? Are there other sanity checks we | ||
494 | * can use to ensure that the server is really filling in that field? | ||
495 | * | ||
496 | * We can not use the IndexNumber field by default from Windows or | ||
497 | * Samba (in ALL_INFO buf) but we can request it explicitly. The SNIA | ||
498 | * CIFS spec claims that this value is unique within the scope of a | ||
499 | * share, and the windows docs hint that it's actually unique | ||
500 | * per-machine. | ||
501 | * | ||
502 | * There may be higher info levels that work but are there Windows | ||
503 | * server or network appliances for which IndexNumber field is not | ||
504 | * guaranteed unique? | ||
505 | */ | ||
501 | if (*pinode == NULL) { | 506 | if (*pinode == NULL) { |
502 | __u64 inode_num; | ||
503 | __u64 *pinum = &inode_num; | ||
504 | |||
505 | /* Is an i_ino of zero legal? Can we use that to check | ||
506 | if the server supports returning inode numbers? Are | ||
507 | there other sanity checks we can use to ensure that | ||
508 | the server is really filling in that field? */ | ||
509 | |||
510 | /* We can not use the IndexNumber field by default from | ||
511 | Windows or Samba (in ALL_INFO buf) but we can request | ||
512 | it explicitly. It may not be unique presumably if | ||
513 | the server has multiple devices mounted under one share */ | ||
514 | |||
515 | /* There may be higher info levels that work but are | ||
516 | there Windows server or network appliances for which | ||
517 | IndexNumber field is not guaranteed unique? */ | ||
518 | |||
519 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { | 507 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { |
520 | int rc1 = 0; | 508 | int rc1 = 0; |
521 | 509 | ||
522 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, | 510 | rc1 = CIFSGetSrvInodeNumber(xid, pTcon, |
523 | full_path, pinum, | 511 | full_path, &fattr.cf_uniqueid, |
524 | cifs_sb->local_nls, | 512 | cifs_sb->local_nls, |
525 | cifs_sb->mnt_cifs_flags & | 513 | cifs_sb->mnt_cifs_flags & |
526 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 514 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
527 | if (rc1) { | 515 | if (rc1) { |
528 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); | 516 | cFYI(1, ("GetSrvInodeNum rc %d", rc1)); |
529 | pinum = NULL; | 517 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
530 | /* BB EOPNOSUPP disable SERVER_INUM? */ | 518 | /* disable serverino if call not supported */ |
519 | if (rc1 == -EINVAL) | ||
520 | cifs_sb->mnt_cifs_flags &= | ||
521 | ~CIFS_MOUNT_SERVER_INUM; | ||
531 | } | 522 | } |
532 | } else { | 523 | } else { |
533 | pinum = NULL; | 524 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
534 | } | ||
535 | |||
536 | *pinode = cifs_new_inode(sb, pinum); | ||
537 | if (*pinode == NULL) { | ||
538 | rc = -ENOMEM; | ||
539 | goto cgii_exit; | ||
540 | } | 525 | } |
541 | } | ||
542 | inode = *pinode; | ||
543 | cifsInfo = CIFS_I(inode); | ||
544 | cifsInfo->cifsAttrs = attr; | ||
545 | cifsInfo->delete_pending = pfindData->DeletePending ? true : false; | ||
546 | cFYI(1, ("Old time %ld", cifsInfo->time)); | ||
547 | cifsInfo->time = jiffies; | ||
548 | cFYI(1, ("New time %ld", cifsInfo->time)); | ||
549 | |||
550 | /* blksize needs to be multiple of two. So safer to default to | ||
551 | blksize and blkbits set in superblock so 2**blkbits and blksize | ||
552 | will match rather than setting to: | ||
553 | (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ | ||
554 | |||
555 | /* Linux can not store file creation time so ignore it */ | ||
556 | if (pfindData->LastAccessTime) | ||
557 | inode->i_atime = cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
558 | else /* do not need to use current_fs_time - time not stored */ | ||
559 | inode->i_atime = CURRENT_TIME; | ||
560 | inode->i_mtime = cifs_NTtimeToUnix(pfindData->LastWriteTime); | ||
561 | inode->i_ctime = cifs_NTtimeToUnix(pfindData->ChangeTime); | ||
562 | cFYI(DBG2, ("Attributes came in as 0x%x", attr)); | ||
563 | if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) { | ||
564 | inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj; | ||
565 | inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; | ||
566 | } | ||
567 | |||
568 | /* get default inode mode */ | ||
569 | if (attr & ATTR_DIRECTORY) | ||
570 | default_mode = cifs_sb->mnt_dir_mode; | ||
571 | else | ||
572 | default_mode = cifs_sb->mnt_file_mode; | ||
573 | |||
574 | /* set permission bits */ | ||
575 | if (atomic_read(&cifsInfo->inUse) == 0 || | ||
576 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | ||
577 | inode->i_mode = default_mode; | ||
578 | else { | ||
579 | /* just reenable write bits if !ATTR_READONLY */ | ||
580 | if ((inode->i_mode & S_IWUGO) == 0 && | ||
581 | (attr & ATTR_READONLY) == 0) | ||
582 | inode->i_mode |= (S_IWUGO & default_mode); | ||
583 | |||
584 | inode->i_mode &= ~S_IFMT; | ||
585 | } | ||
586 | /* clear write bits if ATTR_READONLY is set */ | ||
587 | if (attr & ATTR_READONLY) | ||
588 | inode->i_mode &= ~S_IWUGO; | ||
589 | |||
590 | /* set inode type */ | ||
591 | if ((attr & ATTR_SYSTEM) && | ||
592 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | ||
593 | /* no need to fix endianness on 0 */ | ||
594 | if (pfindData->EndOfFile == 0) | ||
595 | inode->i_mode |= S_IFIFO; | ||
596 | else if (decode_sfu_inode(inode, | ||
597 | le64_to_cpu(pfindData->EndOfFile), | ||
598 | full_path, cifs_sb, xid)) | ||
599 | cFYI(1, ("unknown SFU file type\n")); | ||
600 | } else { | 526 | } else { |
601 | if (attr & ATTR_DIRECTORY) | 527 | fattr.cf_uniqueid = CIFS_I(*pinode)->uniqueid; |
602 | inode->i_mode |= S_IFDIR; | ||
603 | else | ||
604 | inode->i_mode |= S_IFREG; | ||
605 | } | 528 | } |
606 | 529 | ||
607 | cifsInfo->server_eof = le64_to_cpu(pfindData->EndOfFile); | 530 | /* query for SFU type info if supported and needed */ |
608 | spin_lock(&inode->i_lock); | 531 | if (fattr.cf_cifsattrs & ATTR_SYSTEM && |
609 | if (is_size_safe_to_change(cifsInfo, cifsInfo->server_eof)) { | 532 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { |
610 | /* can not safely shrink the file size here if the | 533 | tmprc = cifs_sfu_type(&fattr, full_path, cifs_sb, xid); |
611 | client is writing to it due to potential races */ | 534 | if (tmprc) |
612 | i_size_write(inode, cifsInfo->server_eof); | 535 | cFYI(1, ("cifs_sfu_type failed: %d", tmprc)); |
613 | |||
614 | /* 512 bytes (2**9) is the fake blocksize that must be | ||
615 | used for this calculation */ | ||
616 | inode->i_blocks = (512 - 1 + le64_to_cpu( | ||
617 | pfindData->AllocationSize)) >> 9; | ||
618 | } | 536 | } |
619 | spin_unlock(&inode->i_lock); | ||
620 | 537 | ||
621 | inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); | ||
622 | |||
623 | /* BB fill in uid and gid here? with help from winbind? | ||
624 | or retrieve from NTFS stream extended attribute */ | ||
625 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 538 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
626 | /* fill in 0777 bits from ACL */ | 539 | /* fill in 0777 bits from ACL */ |
627 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 540 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
628 | cFYI(1, ("Getting mode bits from ACL")); | 541 | cFYI(1, ("Getting mode bits from ACL")); |
629 | acl_to_uid_mode(cifs_sb, inode, full_path, pfid); | 542 | cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, pfid); |
630 | } | 543 | } |
631 | #endif | 544 | #endif |
632 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
633 | /* fill in remaining high mode bits e.g. SUID, VTX */ | ||
634 | get_sfu_mode(inode, full_path, cifs_sb, xid); | ||
635 | } else if (atomic_read(&cifsInfo->inUse) == 0) { | ||
636 | inode->i_uid = cifs_sb->mnt_uid; | ||
637 | inode->i_gid = cifs_sb->mnt_gid; | ||
638 | /* set so we do not keep refreshing these fields with | ||
639 | bad data after user has changed them in memory */ | ||
640 | atomic_set(&cifsInfo->inUse, 1); | ||
641 | } | ||
642 | |||
643 | cifs_set_ops(inode, is_dfs_referral); | ||
644 | |||
645 | 545 | ||
546 | /* fill in remaining high mode bits e.g. SUID, VTX */ | ||
547 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | ||
548 | cifs_sfu_mode(&fattr, full_path, cifs_sb, xid); | ||
646 | 549 | ||
550 | if (!*pinode) { | ||
551 | *pinode = cifs_iget(sb, &fattr); | ||
552 | if (!*pinode) | ||
553 | rc = -ENOMEM; | ||
554 | } else { | ||
555 | cifs_fattr_to_inode(*pinode, &fattr); | ||
556 | } | ||
647 | 557 | ||
648 | cgii_exit: | 558 | cgii_exit: |
649 | kfree(buf); | 559 | kfree(buf); |
@@ -695,33 +605,78 @@ char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | |||
695 | return full_path; | 605 | return full_path; |
696 | } | 606 | } |
697 | 607 | ||
608 | static int | ||
609 | cifs_find_inode(struct inode *inode, void *opaque) | ||
610 | { | ||
611 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | ||
612 | |||
613 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | ||
614 | return 0; | ||
615 | |||
616 | return 1; | ||
617 | } | ||
618 | |||
619 | static int | ||
620 | cifs_init_inode(struct inode *inode, void *opaque) | ||
621 | { | ||
622 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | ||
623 | |||
624 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | /* Given fattrs, get a corresponding inode */ | ||
629 | struct inode * | ||
630 | cifs_iget(struct super_block *sb, struct cifs_fattr *fattr) | ||
631 | { | ||
632 | unsigned long hash; | ||
633 | struct inode *inode; | ||
634 | |||
635 | cFYI(1, ("looking for uniqueid=%llu", fattr->cf_uniqueid)); | ||
636 | |||
637 | /* hash down to 32-bits on 32-bit arch */ | ||
638 | hash = cifs_uniqueid_to_ino_t(fattr->cf_uniqueid); | ||
639 | |||
640 | inode = iget5_locked(sb, hash, cifs_find_inode, cifs_init_inode, fattr); | ||
641 | |||
642 | /* we have fattrs in hand, update the inode */ | ||
643 | if (inode) { | ||
644 | cifs_fattr_to_inode(inode, fattr); | ||
645 | if (sb->s_flags & MS_NOATIME) | ||
646 | inode->i_flags |= S_NOATIME | S_NOCMTIME; | ||
647 | if (inode->i_state & I_NEW) { | ||
648 | inode->i_ino = hash; | ||
649 | unlock_new_inode(inode); | ||
650 | } | ||
651 | } | ||
652 | |||
653 | return inode; | ||
654 | } | ||
655 | |||
698 | /* gets root inode */ | 656 | /* gets root inode */ |
699 | struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | 657 | struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) |
700 | { | 658 | { |
701 | int xid; | 659 | int xid; |
702 | struct cifs_sb_info *cifs_sb; | 660 | struct cifs_sb_info *cifs_sb; |
703 | struct inode *inode; | 661 | struct inode *inode = NULL; |
704 | long rc; | 662 | long rc; |
705 | char *full_path; | 663 | char *full_path; |
706 | 664 | ||
707 | inode = iget_locked(sb, ino); | 665 | cifs_sb = CIFS_SB(sb); |
708 | if (!inode) | ||
709 | return ERR_PTR(-ENOMEM); | ||
710 | if (!(inode->i_state & I_NEW)) | ||
711 | return inode; | ||
712 | |||
713 | cifs_sb = CIFS_SB(inode->i_sb); | ||
714 | full_path = cifs_build_path_to_root(cifs_sb); | 666 | full_path = cifs_build_path_to_root(cifs_sb); |
715 | if (full_path == NULL) | 667 | if (full_path == NULL) |
716 | return ERR_PTR(-ENOMEM); | 668 | return ERR_PTR(-ENOMEM); |
717 | 669 | ||
718 | xid = GetXid(); | 670 | xid = GetXid(); |
719 | if (cifs_sb->tcon->unix_ext) | 671 | if (cifs_sb->tcon->unix_ext) |
720 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | 672 | rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); |
721 | xid); | ||
722 | else | 673 | else |
723 | rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb, | 674 | rc = cifs_get_inode_info(&inode, full_path, NULL, sb, |
724 | xid, NULL); | 675 | xid, NULL); |
676 | |||
677 | if (!inode) | ||
678 | return ERR_PTR(-ENOMEM); | ||
679 | |||
725 | if (rc && cifs_sb->tcon->ipc) { | 680 | if (rc && cifs_sb->tcon->ipc) { |
726 | cFYI(1, ("ipc connection - fake read inode")); | 681 | cFYI(1, ("ipc connection - fake read inode")); |
727 | inode->i_mode |= S_IFDIR; | 682 | inode->i_mode |= S_IFDIR; |
@@ -737,7 +692,6 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
737 | return ERR_PTR(rc); | 692 | return ERR_PTR(rc); |
738 | } | 693 | } |
739 | 694 | ||
740 | unlock_new_inode(inode); | ||
741 | 695 | ||
742 | kfree(full_path); | 696 | kfree(full_path); |
743 | /* can not call macro FreeXid here since in a void func | 697 | /* can not call macro FreeXid here since in a void func |
@@ -988,8 +942,9 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) | |||
988 | * sb->s_vfs_rename_mutex here */ | 942 | * sb->s_vfs_rename_mutex here */ |
989 | full_path = build_path_from_dentry(dentry); | 943 | full_path = build_path_from_dentry(dentry); |
990 | if (full_path == NULL) { | 944 | if (full_path == NULL) { |
945 | rc = -ENOMEM; | ||
991 | FreeXid(xid); | 946 | FreeXid(xid); |
992 | return -ENOMEM; | 947 | return rc; |
993 | } | 948 | } |
994 | 949 | ||
995 | if ((tcon->ses->capabilities & CAP_UNIX) && | 950 | if ((tcon->ses->capabilities & CAP_UNIX) && |
@@ -1062,44 +1017,6 @@ out_reval: | |||
1062 | return rc; | 1017 | return rc; |
1063 | } | 1018 | } |
1064 | 1019 | ||
1065 | void posix_fill_in_inode(struct inode *tmp_inode, | ||
1066 | FILE_UNIX_BASIC_INFO *pData, int isNewInode) | ||
1067 | { | ||
1068 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
1069 | loff_t local_size; | ||
1070 | struct timespec local_mtime; | ||
1071 | |||
1072 | cifsInfo->time = jiffies; | ||
1073 | atomic_inc(&cifsInfo->inUse); | ||
1074 | |||
1075 | /* save mtime and size */ | ||
1076 | local_mtime = tmp_inode->i_mtime; | ||
1077 | local_size = tmp_inode->i_size; | ||
1078 | |||
1079 | cifs_unix_info_to_inode(tmp_inode, pData, 1); | ||
1080 | cifs_set_ops(tmp_inode, false); | ||
1081 | |||
1082 | if (!S_ISREG(tmp_inode->i_mode)) | ||
1083 | return; | ||
1084 | |||
1085 | /* | ||
1086 | * No sense invalidating pages for new inode | ||
1087 | * since we we have not started caching | ||
1088 | * readahead file data yet. | ||
1089 | */ | ||
1090 | if (isNewInode) | ||
1091 | return; | ||
1092 | |||
1093 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
1094 | (local_size == tmp_inode->i_size)) { | ||
1095 | cFYI(1, ("inode exists but unchanged")); | ||
1096 | } else { | ||
1097 | /* file may have changed on server */ | ||
1098 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
1099 | invalidate_remote_inode(tmp_inode); | ||
1100 | } | ||
1101 | } | ||
1102 | |||
1103 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | 1020 | int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) |
1104 | { | 1021 | { |
1105 | int rc = 0, tmprc; | 1022 | int rc = 0, tmprc; |
@@ -1108,6 +1025,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1108 | struct cifsTconInfo *pTcon; | 1025 | struct cifsTconInfo *pTcon; |
1109 | char *full_path = NULL; | 1026 | char *full_path = NULL; |
1110 | struct inode *newinode = NULL; | 1027 | struct inode *newinode = NULL; |
1028 | struct cifs_fattr fattr; | ||
1111 | 1029 | ||
1112 | cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); | 1030 | cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); |
1113 | 1031 | ||
@@ -1118,8 +1036,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1118 | 1036 | ||
1119 | full_path = build_path_from_dentry(direntry); | 1037 | full_path = build_path_from_dentry(direntry); |
1120 | if (full_path == NULL) { | 1038 | if (full_path == NULL) { |
1039 | rc = -ENOMEM; | ||
1121 | FreeXid(xid); | 1040 | FreeXid(xid); |
1122 | return -ENOMEM; | 1041 | return rc; |
1123 | } | 1042 | } |
1124 | 1043 | ||
1125 | if ((pTcon->ses->capabilities & CAP_UNIX) && | 1044 | if ((pTcon->ses->capabilities & CAP_UNIX) && |
@@ -1146,7 +1065,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1146 | cFYI(1, ("posix mkdir returned 0x%x", rc)); | 1065 | cFYI(1, ("posix mkdir returned 0x%x", rc)); |
1147 | d_drop(direntry); | 1066 | d_drop(direntry); |
1148 | } else { | 1067 | } else { |
1149 | __u64 unique_id; | ||
1150 | if (pInfo->Type == cpu_to_le32(-1)) { | 1068 | if (pInfo->Type == cpu_to_le32(-1)) { |
1151 | /* no return info, go query for it */ | 1069 | /* no return info, go query for it */ |
1152 | kfree(pInfo); | 1070 | kfree(pInfo); |
@@ -1160,20 +1078,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1160 | else | 1078 | else |
1161 | direntry->d_op = &cifs_dentry_ops; | 1079 | direntry->d_op = &cifs_dentry_ops; |
1162 | 1080 | ||
1163 | unique_id = le64_to_cpu(pInfo->UniqueId); | 1081 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); |
1164 | newinode = cifs_new_inode(inode->i_sb, &unique_id); | 1082 | newinode = cifs_iget(inode->i_sb, &fattr); |
1165 | if (newinode == NULL) { | 1083 | if (!newinode) { |
1166 | kfree(pInfo); | 1084 | kfree(pInfo); |
1167 | goto mkdir_get_info; | 1085 | goto mkdir_get_info; |
1168 | } | 1086 | } |
1169 | 1087 | ||
1170 | newinode->i_nlink = 2; | ||
1171 | d_instantiate(direntry, newinode); | 1088 | d_instantiate(direntry, newinode); |
1172 | 1089 | ||
1173 | /* we already checked in POSIXCreate whether | ||
1174 | frame was long enough */ | ||
1175 | posix_fill_in_inode(direntry->d_inode, | ||
1176 | pInfo, 1 /* NewInode */); | ||
1177 | #ifdef CONFIG_CIFS_DEBUG2 | 1090 | #ifdef CONFIG_CIFS_DEBUG2 |
1178 | cFYI(1, ("instantiated dentry %p %s to inode %p", | 1091 | cFYI(1, ("instantiated dentry %p %s to inode %p", |
1179 | direntry, direntry->d_name.name, newinode)); | 1092 | direntry, direntry->d_name.name, newinode)); |
@@ -1236,10 +1149,10 @@ mkdir_get_info: | |||
1236 | args.uid = NO_CHANGE_64; | 1149 | args.uid = NO_CHANGE_64; |
1237 | args.gid = NO_CHANGE_64; | 1150 | args.gid = NO_CHANGE_64; |
1238 | } | 1151 | } |
1239 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | 1152 | CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, |
1240 | cifs_sb->local_nls, | 1153 | cifs_sb->local_nls, |
1241 | cifs_sb->mnt_cifs_flags & | 1154 | cifs_sb->mnt_cifs_flags & |
1242 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1155 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1243 | } else { | 1156 | } else { |
1244 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && | 1157 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && |
1245 | (mode & S_IWUGO) == 0) { | 1158 | (mode & S_IWUGO) == 0) { |
@@ -1303,8 +1216,9 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) | |||
1303 | 1216 | ||
1304 | full_path = build_path_from_dentry(direntry); | 1217 | full_path = build_path_from_dentry(direntry); |
1305 | if (full_path == NULL) { | 1218 | if (full_path == NULL) { |
1219 | rc = -ENOMEM; | ||
1306 | FreeXid(xid); | 1220 | FreeXid(xid); |
1307 | return -ENOMEM; | 1221 | return rc; |
1308 | } | 1222 | } |
1309 | 1223 | ||
1310 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, | 1224 | rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls, |
@@ -1508,8 +1422,9 @@ int cifs_revalidate(struct dentry *direntry) | |||
1508 | since that would deadlock */ | 1422 | since that would deadlock */ |
1509 | full_path = build_path_from_dentry(direntry); | 1423 | full_path = build_path_from_dentry(direntry); |
1510 | if (full_path == NULL) { | 1424 | if (full_path == NULL) { |
1425 | rc = -ENOMEM; | ||
1511 | FreeXid(xid); | 1426 | FreeXid(xid); |
1512 | return -ENOMEM; | 1427 | return rc; |
1513 | } | 1428 | } |
1514 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " | 1429 | cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld " |
1515 | "jiffies %ld", full_path, direntry->d_inode, | 1430 | "jiffies %ld", full_path, direntry->d_inode, |
@@ -1618,6 +1533,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
1618 | if (!err) { | 1533 | if (!err) { |
1619 | generic_fillattr(dentry->d_inode, stat); | 1534 | generic_fillattr(dentry->d_inode, stat); |
1620 | stat->blksize = CIFS_MAX_MSGSIZE; | 1535 | stat->blksize = CIFS_MAX_MSGSIZE; |
1536 | stat->ino = CIFS_I(dentry->d_inode)->uniqueid; | ||
1621 | } | 1537 | } |
1622 | return err; | 1538 | return err; |
1623 | } | 1539 | } |
@@ -1782,6 +1698,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1782 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 1698 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
1783 | struct cifsTconInfo *pTcon = cifs_sb->tcon; | 1699 | struct cifsTconInfo *pTcon = cifs_sb->tcon; |
1784 | struct cifs_unix_set_info_args *args = NULL; | 1700 | struct cifs_unix_set_info_args *args = NULL; |
1701 | struct cifsFileInfo *open_file; | ||
1785 | 1702 | ||
1786 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", | 1703 | cFYI(1, ("setattr_unix on file %s attrs->ia_valid=0x%x", |
1787 | direntry->d_name.name, attrs->ia_valid)); | 1704 | direntry->d_name.name, attrs->ia_valid)); |
@@ -1868,10 +1785,18 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
1868 | args->ctime = NO_CHANGE_64; | 1785 | args->ctime = NO_CHANGE_64; |
1869 | 1786 | ||
1870 | args->device = 0; | 1787 | args->device = 0; |
1871 | rc = CIFSSMBUnixSetInfo(xid, pTcon, full_path, args, | 1788 | open_file = find_writable_file(cifsInode); |
1872 | cifs_sb->local_nls, | 1789 | if (open_file) { |
1873 | cifs_sb->mnt_cifs_flags & | 1790 | u16 nfid = open_file->netfid; |
1874 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1791 | u32 npid = open_file->pid; |
1792 | rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid); | ||
1793 | atomic_dec(&open_file->wrtPending); | ||
1794 | } else { | ||
1795 | rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, args, | ||
1796 | cifs_sb->local_nls, | ||
1797 | cifs_sb->mnt_cifs_flags & | ||
1798 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
1799 | } | ||
1875 | 1800 | ||
1876 | if (!rc) | 1801 | if (!rc) |
1877 | rc = inode_setattr(inode, attrs); | 1802 | rc = inode_setattr(inode, attrs); |
@@ -1911,8 +1836,9 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
1911 | 1836 | ||
1912 | full_path = build_path_from_dentry(direntry); | 1837 | full_path = build_path_from_dentry(direntry); |
1913 | if (full_path == NULL) { | 1838 | if (full_path == NULL) { |
1839 | rc = -ENOMEM; | ||
1914 | FreeXid(xid); | 1840 | FreeXid(xid); |
1915 | return -ENOMEM; | 1841 | return rc; |
1916 | } | 1842 | } |
1917 | 1843 | ||
1918 | /* | 1844 | /* |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index cd83c53fcbb5..fc1e0487eaee 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -172,8 +172,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
172 | full_path = build_path_from_dentry(direntry); | 172 | full_path = build_path_from_dentry(direntry); |
173 | 173 | ||
174 | if (full_path == NULL) { | 174 | if (full_path == NULL) { |
175 | rc = -ENOMEM; | ||
175 | FreeXid(xid); | 176 | FreeXid(xid); |
176 | return -ENOMEM; | 177 | return rc; |
177 | } | 178 | } |
178 | 179 | ||
179 | cFYI(1, ("Full path: %s", full_path)); | 180 | cFYI(1, ("Full path: %s", full_path)); |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 32d6baa0a54f..bd6d6895730d 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
@@ -133,10 +133,12 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | |||
133 | {0, 0} | 133 | {0, 0} |
134 | }; | 134 | }; |
135 | 135 | ||
136 | /* Convert string containing dotted ip address to binary form */ | 136 | /* |
137 | /* returns 0 if invalid address */ | 137 | * Convert a string containing text IPv4 or IPv6 address to binary form. |
138 | 138 | * | |
139 | int | 139 | * Returns 0 on failure. |
140 | */ | ||
141 | static int | ||
140 | cifs_inet_pton(const int address_family, const char *cp, void *dst) | 142 | cifs_inet_pton(const int address_family, const char *cp, void *dst) |
141 | { | 143 | { |
142 | int ret = 0; | 144 | int ret = 0; |
@@ -153,6 +155,52 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst) | |||
153 | return ret; | 155 | return ret; |
154 | } | 156 | } |
155 | 157 | ||
158 | /* | ||
159 | * Try to convert a string to an IPv4 address and then attempt to convert | ||
160 | * it to an IPv6 address if that fails. Set the family field if either | ||
161 | * succeeds. If it's an IPv6 address and it has a '%' sign in it, try to | ||
162 | * treat the part following it as a numeric sin6_scope_id. | ||
163 | * | ||
164 | * Returns 0 on failure. | ||
165 | */ | ||
166 | int | ||
167 | cifs_convert_address(char *src, void *dst) | ||
168 | { | ||
169 | int rc; | ||
170 | char *pct, *endp; | ||
171 | struct sockaddr_in *s4 = (struct sockaddr_in *) dst; | ||
172 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; | ||
173 | |||
174 | /* IPv4 address */ | ||
175 | if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) { | ||
176 | s4->sin_family = AF_INET; | ||
177 | return 1; | ||
178 | } | ||
179 | |||
180 | /* temporarily terminate string */ | ||
181 | pct = strchr(src, '%'); | ||
182 | if (pct) | ||
183 | *pct = '\0'; | ||
184 | |||
185 | rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr); | ||
186 | |||
187 | /* repair temp termination (if any) and make pct point to scopeid */ | ||
188 | if (pct) | ||
189 | *pct++ = '%'; | ||
190 | |||
191 | if (!rc) | ||
192 | return rc; | ||
193 | |||
194 | s6->sin6_family = AF_INET6; | ||
195 | if (pct) { | ||
196 | s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); | ||
197 | if (!*pct || *endp) | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | return rc; | ||
202 | } | ||
203 | |||
156 | /***************************************************************************** | 204 | /***************************************************************************** |
157 | convert a NT status code to a dos class/code | 205 | convert a NT status code to a dos class/code |
158 | *****************************************************************************/ | 206 | *****************************************************************************/ |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 86d0055dc529..f823a4a208a7 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -63,374 +63,123 @@ static inline void dump_cifs_file_struct(struct file *file, char *label) | |||
63 | } | 63 | } |
64 | #endif /* DEBUG2 */ | 64 | #endif /* DEBUG2 */ |
65 | 65 | ||
66 | /* Returns 1 if new inode created, 2 if both dentry and inode were */ | 66 | /* |
67 | /* Might check in the future if inode number changed so we can rehash inode */ | 67 | * Find the dentry that matches "name". If there isn't one, create one. If it's |
68 | static int | 68 | * a negative dentry or the uniqueid changed, then drop it and recreate it. |
69 | construct_dentry(struct qstr *qstring, struct file *file, | 69 | */ |
70 | struct inode **ptmp_inode, struct dentry **pnew_dentry, | 70 | static struct dentry * |
71 | __u64 *inum) | 71 | cifs_readdir_lookup(struct dentry *parent, struct qstr *name, |
72 | struct cifs_fattr *fattr) | ||
72 | { | 73 | { |
73 | struct dentry *tmp_dentry = NULL; | 74 | struct dentry *dentry, *alias; |
74 | struct super_block *sb = file->f_path.dentry->d_sb; | 75 | struct inode *inode; |
75 | int rc = 0; | 76 | struct super_block *sb = parent->d_inode->i_sb; |
77 | |||
78 | cFYI(1, ("For %s", name->name)); | ||
79 | |||
80 | dentry = d_lookup(parent, name); | ||
81 | if (dentry) { | ||
82 | /* FIXME: check for inode number changes? */ | ||
83 | if (dentry->d_inode != NULL) | ||
84 | return dentry; | ||
85 | d_drop(dentry); | ||
86 | dput(dentry); | ||
87 | } | ||
76 | 88 | ||
77 | cFYI(1, ("For %s", qstring->name)); | 89 | dentry = d_alloc(parent, name); |
78 | 90 | if (dentry == NULL) | |
79 | qstring->hash = full_name_hash(qstring->name, qstring->len); | 91 | return NULL; |
80 | tmp_dentry = d_lookup(file->f_path.dentry, qstring); | ||
81 | if (tmp_dentry) { | ||
82 | /* BB: overwrite old name? i.e. tmp_dentry->d_name and | ||
83 | * tmp_dentry->d_name.len?? | ||
84 | */ | ||
85 | cFYI(0, ("existing dentry with inode 0x%p", | ||
86 | tmp_dentry->d_inode)); | ||
87 | *ptmp_inode = tmp_dentry->d_inode; | ||
88 | if (*ptmp_inode == NULL) { | ||
89 | *ptmp_inode = cifs_new_inode(sb, inum); | ||
90 | if (*ptmp_inode == NULL) | ||
91 | return rc; | ||
92 | rc = 1; | ||
93 | } | ||
94 | } else { | ||
95 | tmp_dentry = d_alloc(file->f_path.dentry, qstring); | ||
96 | if (tmp_dentry == NULL) { | ||
97 | cERROR(1, ("Failed allocating dentry")); | ||
98 | *ptmp_inode = NULL; | ||
99 | return rc; | ||
100 | } | ||
101 | 92 | ||
102 | if (CIFS_SB(sb)->tcon->nocase) | 93 | inode = cifs_iget(sb, fattr); |
103 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | 94 | if (!inode) { |
104 | else | 95 | dput(dentry); |
105 | tmp_dentry->d_op = &cifs_dentry_ops; | 96 | return NULL; |
97 | } | ||
106 | 98 | ||
107 | *ptmp_inode = cifs_new_inode(sb, inum); | 99 | if (CIFS_SB(sb)->tcon->nocase) |
108 | if (*ptmp_inode == NULL) | 100 | dentry->d_op = &cifs_ci_dentry_ops; |
109 | return rc; | 101 | else |
110 | rc = 2; | 102 | dentry->d_op = &cifs_dentry_ops; |
103 | |||
104 | alias = d_materialise_unique(dentry, inode); | ||
105 | if (alias != NULL) { | ||
106 | dput(dentry); | ||
107 | if (IS_ERR(alias)) | ||
108 | return NULL; | ||
109 | dentry = alias; | ||
111 | } | 110 | } |
112 | 111 | ||
113 | tmp_dentry->d_time = jiffies; | 112 | return dentry; |
114 | *pnew_dentry = tmp_dentry; | ||
115 | return rc; | ||
116 | } | 113 | } |
117 | 114 | ||
118 | static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, | 115 | static void |
119 | char *buf, unsigned int *pobject_type, int isNewInode) | 116 | cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb) |
120 | { | 117 | { |
121 | loff_t local_size; | 118 | fattr->cf_uid = cifs_sb->mnt_uid; |
122 | struct timespec local_mtime; | 119 | fattr->cf_gid = cifs_sb->mnt_gid; |
123 | |||
124 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
125 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
126 | __u32 attr; | ||
127 | __u64 allocation_size; | ||
128 | __u64 end_of_file; | ||
129 | umode_t default_mode; | ||
130 | |||
131 | /* save mtime and size */ | ||
132 | local_mtime = tmp_inode->i_mtime; | ||
133 | local_size = tmp_inode->i_size; | ||
134 | |||
135 | if (new_buf_type) { | ||
136 | FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; | ||
137 | |||
138 | attr = le32_to_cpu(pfindData->ExtFileAttributes); | ||
139 | allocation_size = le64_to_cpu(pfindData->AllocationSize); | ||
140 | end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
141 | tmp_inode->i_atime = | ||
142 | cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
143 | tmp_inode->i_mtime = | ||
144 | cifs_NTtimeToUnix(pfindData->LastWriteTime); | ||
145 | tmp_inode->i_ctime = | ||
146 | cifs_NTtimeToUnix(pfindData->ChangeTime); | ||
147 | } else { /* legacy, OS2 and DOS style */ | ||
148 | int offset = cifs_sb->tcon->ses->server->timeAdj; | ||
149 | FIND_FILE_STANDARD_INFO *pfindData = | ||
150 | (FIND_FILE_STANDARD_INFO *)buf; | ||
151 | |||
152 | tmp_inode->i_mtime = cnvrtDosUnixTm(pfindData->LastWriteDate, | ||
153 | pfindData->LastWriteTime, | ||
154 | offset); | ||
155 | tmp_inode->i_atime = cnvrtDosUnixTm(pfindData->LastAccessDate, | ||
156 | pfindData->LastAccessTime, | ||
157 | offset); | ||
158 | tmp_inode->i_ctime = cnvrtDosUnixTm(pfindData->LastWriteDate, | ||
159 | pfindData->LastWriteTime, | ||
160 | offset); | ||
161 | attr = le16_to_cpu(pfindData->Attributes); | ||
162 | allocation_size = le32_to_cpu(pfindData->AllocationSize); | ||
163 | end_of_file = le32_to_cpu(pfindData->DataSize); | ||
164 | } | ||
165 | 120 | ||
166 | /* Linux can not store file creation time unfortunately so ignore it */ | 121 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
167 | 122 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | |
168 | cifsInfo->cifsAttrs = attr; | 123 | fattr->cf_dtype = DT_DIR; |
169 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 124 | } else { |
170 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 125 | fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode; |
171 | /* get more accurate mode via ACL - so force inode refresh */ | 126 | fattr->cf_dtype = DT_REG; |
172 | cifsInfo->time = 0; | ||
173 | } else | ||
174 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
175 | cifsInfo->time = jiffies; | ||
176 | |||
177 | /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ | ||
178 | /* 2767 perms - indicate mandatory locking */ | ||
179 | /* BB fill in uid and gid here? with help from winbind? | ||
180 | or retrieve from NTFS stream extended attribute */ | ||
181 | if (atomic_read(&cifsInfo->inUse) == 0) { | ||
182 | tmp_inode->i_uid = cifs_sb->mnt_uid; | ||
183 | tmp_inode->i_gid = cifs_sb->mnt_gid; | ||
184 | } | ||
185 | |||
186 | if (attr & ATTR_DIRECTORY) | ||
187 | default_mode = cifs_sb->mnt_dir_mode; | ||
188 | else | ||
189 | default_mode = cifs_sb->mnt_file_mode; | ||
190 | |||
191 | /* set initial permissions */ | ||
192 | if ((atomic_read(&cifsInfo->inUse) == 0) || | ||
193 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) | ||
194 | tmp_inode->i_mode = default_mode; | ||
195 | else { | ||
196 | /* just reenable write bits if !ATTR_READONLY */ | ||
197 | if ((tmp_inode->i_mode & S_IWUGO) == 0 && | ||
198 | (attr & ATTR_READONLY) == 0) | ||
199 | tmp_inode->i_mode |= (S_IWUGO & default_mode); | ||
200 | |||
201 | tmp_inode->i_mode &= ~S_IFMT; | ||
202 | } | 127 | } |
203 | 128 | ||
204 | /* clear write bits if ATTR_READONLY is set */ | 129 | if (fattr->cf_cifsattrs & ATTR_READONLY) |
205 | if (attr & ATTR_READONLY) | 130 | fattr->cf_mode &= ~S_IWUGO; |
206 | tmp_inode->i_mode &= ~S_IWUGO; | ||
207 | 131 | ||
208 | /* set inode type */ | 132 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL && |
209 | if ((attr & ATTR_SYSTEM) && | 133 | fattr->cf_cifsattrs & ATTR_SYSTEM) { |
210 | (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { | 134 | if (fattr->cf_eof == 0) { |
211 | if (end_of_file == 0) { | 135 | fattr->cf_mode &= ~S_IFMT; |
212 | tmp_inode->i_mode |= S_IFIFO; | 136 | fattr->cf_mode |= S_IFIFO; |
213 | *pobject_type = DT_FIFO; | 137 | fattr->cf_dtype = DT_FIFO; |
214 | } else { | 138 | } else { |
215 | /* | 139 | /* |
216 | * trying to get the type can be slow, so just call | 140 | * trying to get the type and mode via SFU can be slow, |
217 | * this a regular file for now, and mark for reval | 141 | * so just call those regular files for now, and mark |
142 | * for reval | ||
218 | */ | 143 | */ |
219 | tmp_inode->i_mode |= S_IFREG; | 144 | fattr->cf_flags |= CIFS_FATTR_NEED_REVAL; |
220 | *pobject_type = DT_REG; | ||
221 | cifsInfo->time = 0; | ||
222 | } | ||
223 | } else { | ||
224 | if (attr & ATTR_DIRECTORY) { | ||
225 | tmp_inode->i_mode |= S_IFDIR; | ||
226 | *pobject_type = DT_DIR; | ||
227 | } else { | ||
228 | tmp_inode->i_mode |= S_IFREG; | ||
229 | *pobject_type = DT_REG; | ||
230 | } | 145 | } |
231 | } | 146 | } |
147 | } | ||
232 | 148 | ||
233 | /* can not fill in nlink here as in qpathinfo version and Unx search */ | 149 | void |
234 | if (atomic_read(&cifsInfo->inUse) == 0) | 150 | cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, |
235 | atomic_set(&cifsInfo->inUse, 1); | 151 | struct cifs_sb_info *cifs_sb) |
236 | 152 | { | |
237 | cifsInfo->server_eof = end_of_file; | 153 | memset(fattr, 0, sizeof(*fattr)); |
238 | spin_lock(&tmp_inode->i_lock); | 154 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); |
239 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | 155 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
240 | /* can not safely change the file size here if the | 156 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
241 | client is writing to it due to potential races */ | 157 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
242 | i_size_write(tmp_inode, end_of_file); | 158 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
243 | 159 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | |
244 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | 160 | |
245 | /* for this calculation, even though the reported blocksize is larger */ | 161 | cifs_fill_common_info(fattr, cifs_sb); |
246 | tmp_inode->i_blocks = (512 - 1 + allocation_size) >> 9; | ||
247 | } | ||
248 | spin_unlock(&tmp_inode->i_lock); | ||
249 | |||
250 | if (allocation_size < end_of_file) | ||
251 | cFYI(1, ("May be sparse file, allocation less than file size")); | ||
252 | cFYI(1, ("File Size %ld and blocks %llu", | ||
253 | (unsigned long)tmp_inode->i_size, | ||
254 | (unsigned long long)tmp_inode->i_blocks)); | ||
255 | if (S_ISREG(tmp_inode->i_mode)) { | ||
256 | cFYI(1, ("File inode")); | ||
257 | tmp_inode->i_op = &cifs_file_inode_ops; | ||
258 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { | ||
259 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
260 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
261 | else | ||
262 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
263 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
264 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
265 | else | ||
266 | tmp_inode->i_fop = &cifs_file_ops; | ||
267 | |||
268 | if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
269 | (cifs_sb->tcon->ses->server->maxBuf < | ||
270 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) | ||
271 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | ||
272 | else | ||
273 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
274 | |||
275 | if (isNewInode) | ||
276 | return; /* No sense invalidating pages for new inode | ||
277 | since have not started caching readahead file | ||
278 | data yet */ | ||
279 | |||
280 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
281 | (local_size == tmp_inode->i_size)) { | ||
282 | cFYI(1, ("inode exists but unchanged")); | ||
283 | } else { | ||
284 | /* file may have changed on server */ | ||
285 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
286 | invalidate_remote_inode(tmp_inode); | ||
287 | } | ||
288 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
289 | cFYI(1, ("Directory inode")); | ||
290 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
291 | tmp_inode->i_fop = &cifs_dir_ops; | ||
292 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
293 | cFYI(1, ("Symbolic Link inode")); | ||
294 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
295 | } else { | ||
296 | cFYI(1, ("Init special inode")); | ||
297 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
298 | tmp_inode->i_rdev); | ||
299 | } | ||
300 | } | 162 | } |
301 | 163 | ||
302 | static void unix_fill_in_inode(struct inode *tmp_inode, | 164 | void |
303 | FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode) | 165 | cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info, |
166 | struct cifs_sb_info *cifs_sb) | ||
304 | { | 167 | { |
305 | loff_t local_size; | 168 | int offset = cifs_sb->tcon->ses->server->timeAdj; |
306 | struct timespec local_mtime; | ||
307 | |||
308 | struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); | ||
309 | struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); | ||
310 | |||
311 | __u32 type = le32_to_cpu(pfindData->Type); | ||
312 | __u64 num_of_bytes = le64_to_cpu(pfindData->NumOfBytes); | ||
313 | __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); | ||
314 | cifsInfo->time = jiffies; | ||
315 | atomic_inc(&cifsInfo->inUse); | ||
316 | |||
317 | /* save mtime and size */ | ||
318 | local_mtime = tmp_inode->i_mtime; | ||
319 | local_size = tmp_inode->i_size; | ||
320 | |||
321 | tmp_inode->i_atime = | ||
322 | cifs_NTtimeToUnix(pfindData->LastAccessTime); | ||
323 | tmp_inode->i_mtime = | ||
324 | cifs_NTtimeToUnix(pfindData->LastModificationTime); | ||
325 | tmp_inode->i_ctime = | ||
326 | cifs_NTtimeToUnix(pfindData->LastStatusChange); | ||
327 | |||
328 | tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); | ||
329 | /* since we set the inode type below we need to mask off type | ||
330 | to avoid strange results if bits above were corrupt */ | ||
331 | tmp_inode->i_mode &= ~S_IFMT; | ||
332 | if (type == UNIX_FILE) { | ||
333 | *pobject_type = DT_REG; | ||
334 | tmp_inode->i_mode |= S_IFREG; | ||
335 | } else if (type == UNIX_SYMLINK) { | ||
336 | *pobject_type = DT_LNK; | ||
337 | tmp_inode->i_mode |= S_IFLNK; | ||
338 | } else if (type == UNIX_DIR) { | ||
339 | *pobject_type = DT_DIR; | ||
340 | tmp_inode->i_mode |= S_IFDIR; | ||
341 | } else if (type == UNIX_CHARDEV) { | ||
342 | *pobject_type = DT_CHR; | ||
343 | tmp_inode->i_mode |= S_IFCHR; | ||
344 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), | ||
345 | le64_to_cpu(pfindData->DevMinor) & MINORMASK); | ||
346 | } else if (type == UNIX_BLOCKDEV) { | ||
347 | *pobject_type = DT_BLK; | ||
348 | tmp_inode->i_mode |= S_IFBLK; | ||
349 | tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), | ||
350 | le64_to_cpu(pfindData->DevMinor) & MINORMASK); | ||
351 | } else if (type == UNIX_FIFO) { | ||
352 | *pobject_type = DT_FIFO; | ||
353 | tmp_inode->i_mode |= S_IFIFO; | ||
354 | } else if (type == UNIX_SOCKET) { | ||
355 | *pobject_type = DT_SOCK; | ||
356 | tmp_inode->i_mode |= S_IFSOCK; | ||
357 | } else { | ||
358 | /* safest to just call it a file */ | ||
359 | *pobject_type = DT_REG; | ||
360 | tmp_inode->i_mode |= S_IFREG; | ||
361 | cFYI(1, ("unknown inode type %d", type)); | ||
362 | } | ||
363 | 169 | ||
364 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) | 170 | memset(fattr, 0, sizeof(*fattr)); |
365 | tmp_inode->i_uid = cifs_sb->mnt_uid; | 171 | fattr->cf_atime = cnvrtDosUnixTm(info->LastAccessDate, |
366 | else | 172 | info->LastAccessTime, offset); |
367 | tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); | 173 | fattr->cf_ctime = cnvrtDosUnixTm(info->LastWriteDate, |
368 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) | 174 | info->LastWriteTime, offset); |
369 | tmp_inode->i_gid = cifs_sb->mnt_gid; | 175 | fattr->cf_mtime = cnvrtDosUnixTm(info->LastWriteDate, |
370 | else | 176 | info->LastWriteTime, offset); |
371 | tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); | ||
372 | tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); | ||
373 | |||
374 | cifsInfo->server_eof = end_of_file; | ||
375 | spin_lock(&tmp_inode->i_lock); | ||
376 | if (is_size_safe_to_change(cifsInfo, end_of_file)) { | ||
377 | /* can not safely change the file size here if the | ||
378 | client is writing to it due to potential races */ | ||
379 | i_size_write(tmp_inode, end_of_file); | ||
380 | |||
381 | /* 512 bytes (2**9) is the fake blocksize that must be used */ | ||
382 | /* for this calculation, not the real blocksize */ | ||
383 | tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9; | ||
384 | } | ||
385 | spin_unlock(&tmp_inode->i_lock); | ||
386 | 177 | ||
387 | if (S_ISREG(tmp_inode->i_mode)) { | 178 | fattr->cf_cifsattrs = le16_to_cpu(info->Attributes); |
388 | cFYI(1, ("File inode")); | 179 | fattr->cf_bytes = le32_to_cpu(info->AllocationSize); |
389 | tmp_inode->i_op = &cifs_file_inode_ops; | 180 | fattr->cf_eof = le32_to_cpu(info->DataSize); |
390 | 181 | ||
391 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { | 182 | cifs_fill_common_info(fattr, cifs_sb); |
392 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
393 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
394 | else | ||
395 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
396 | } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
397 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
398 | else | ||
399 | tmp_inode->i_fop = &cifs_file_ops; | ||
400 | |||
401 | if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
402 | (cifs_sb->tcon->ses->server->maxBuf < | ||
403 | PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) | ||
404 | tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; | ||
405 | else | ||
406 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | ||
407 | |||
408 | if (isNewInode) | ||
409 | return; /* No sense invalidating pages for new inode | ||
410 | since we have not started caching readahead | ||
411 | file data for it yet */ | ||
412 | |||
413 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | ||
414 | (local_size == tmp_inode->i_size)) { | ||
415 | cFYI(1, ("inode exists but unchanged")); | ||
416 | } else { | ||
417 | /* file may have changed on server */ | ||
418 | cFYI(1, ("invalidate inode, readdir detected change")); | ||
419 | invalidate_remote_inode(tmp_inode); | ||
420 | } | ||
421 | } else if (S_ISDIR(tmp_inode->i_mode)) { | ||
422 | cFYI(1, ("Directory inode")); | ||
423 | tmp_inode->i_op = &cifs_dir_inode_ops; | ||
424 | tmp_inode->i_fop = &cifs_dir_ops; | ||
425 | } else if (S_ISLNK(tmp_inode->i_mode)) { | ||
426 | cFYI(1, ("Symbolic Link inode")); | ||
427 | tmp_inode->i_op = &cifs_symlink_inode_ops; | ||
428 | /* tmp_inode->i_fop = *//* do not need to set to anything */ | ||
429 | } else { | ||
430 | cFYI(1, ("Special inode")); | ||
431 | init_special_inode(tmp_inode, tmp_inode->i_mode, | ||
432 | tmp_inode->i_rdev); | ||
433 | } | ||
434 | } | 183 | } |
435 | 184 | ||
436 | /* BB eventually need to add the following helper function to | 185 | /* BB eventually need to add the following helper function to |
@@ -872,7 +621,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, | |||
872 | len = strnlen(filename, PATH_MAX); | 621 | len = strnlen(filename, PATH_MAX); |
873 | } | 622 | } |
874 | 623 | ||
875 | *pinum = le64_to_cpu(pFindData->UniqueId); | 624 | *pinum = le64_to_cpu(pFindData->basic.UniqueId); |
876 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { | 625 | } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) { |
877 | FILE_DIRECTORY_INFO *pFindData = | 626 | FILE_DIRECTORY_INFO *pFindData = |
878 | (FILE_DIRECTORY_INFO *)current_entry; | 627 | (FILE_DIRECTORY_INFO *)current_entry; |
@@ -932,11 +681,12 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
932 | int rc = 0; | 681 | int rc = 0; |
933 | struct qstr qstring; | 682 | struct qstr qstring; |
934 | struct cifsFileInfo *pCifsF; | 683 | struct cifsFileInfo *pCifsF; |
935 | unsigned int obj_type; | 684 | u64 inum; |
936 | __u64 inum; | 685 | ino_t ino; |
686 | struct super_block *sb; | ||
937 | struct cifs_sb_info *cifs_sb; | 687 | struct cifs_sb_info *cifs_sb; |
938 | struct inode *tmp_inode; | ||
939 | struct dentry *tmp_dentry; | 688 | struct dentry *tmp_dentry; |
689 | struct cifs_fattr fattr; | ||
940 | 690 | ||
941 | /* get filename and len into qstring */ | 691 | /* get filename and len into qstring */ |
942 | /* get dentry */ | 692 | /* get dentry */ |
@@ -954,60 +704,53 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
954 | if (rc != 0) | 704 | if (rc != 0) |
955 | return 0; | 705 | return 0; |
956 | 706 | ||
957 | cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); | 707 | sb = file->f_path.dentry->d_sb; |
708 | cifs_sb = CIFS_SB(sb); | ||
958 | 709 | ||
959 | qstring.name = scratch_buf; | 710 | qstring.name = scratch_buf; |
960 | rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, | 711 | rc = cifs_get_name_from_search_buf(&qstring, pfindEntry, |
961 | pCifsF->srch_inf.info_level, | 712 | pCifsF->srch_inf.info_level, |
962 | pCifsF->srch_inf.unicode, cifs_sb, | 713 | pCifsF->srch_inf.unicode, cifs_sb, |
963 | max_len, | 714 | max_len, &inum /* returned */); |
964 | &inum /* returned */); | ||
965 | 715 | ||
966 | if (rc) | 716 | if (rc) |
967 | return rc; | 717 | return rc; |
968 | 718 | ||
969 | /* only these two infolevels return valid inode numbers */ | ||
970 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX || | ||
971 | pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) | ||
972 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, | ||
973 | &inum); | ||
974 | else | ||
975 | rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry, | ||
976 | NULL); | ||
977 | |||
978 | if ((tmp_inode == NULL) || (tmp_dentry == NULL)) | ||
979 | return -ENOMEM; | ||
980 | |||
981 | /* we pass in rc below, indicating whether it is a new inode, | ||
982 | so we can figure out whether to invalidate the inode cached | ||
983 | data if the file has changed */ | ||
984 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) | 719 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) |
985 | unix_fill_in_inode(tmp_inode, | 720 | cifs_unix_basic_to_fattr(&fattr, |
986 | (FILE_UNIX_INFO *)pfindEntry, | 721 | &((FILE_UNIX_INFO *) pfindEntry)->basic, |
987 | &obj_type, rc); | 722 | cifs_sb); |
988 | else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) | 723 | else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) |
989 | fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, | 724 | cifs_std_info_to_fattr(&fattr, (FIND_FILE_STANDARD_INFO *) |
990 | pfindEntry, &obj_type, rc); | 725 | pfindEntry, cifs_sb); |
991 | else | 726 | else |
992 | fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); | 727 | cifs_dir_info_to_fattr(&fattr, (FILE_DIRECTORY_INFO *) |
728 | pfindEntry, cifs_sb); | ||
993 | 729 | ||
994 | if (rc) /* new inode - needs to be tied to dentry */ { | 730 | /* FIXME: make _to_fattr functions fill this out */ |
995 | d_instantiate(tmp_dentry, tmp_inode); | 731 | if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO) |
996 | if (rc == 2) | 732 | fattr.cf_uniqueid = inum; |
997 | d_rehash(tmp_dentry); | 733 | else |
998 | } | 734 | fattr.cf_uniqueid = iunique(sb, ROOT_I); |
999 | 735 | ||
736 | ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid); | ||
737 | tmp_dentry = cifs_readdir_lookup(file->f_dentry, &qstring, &fattr); | ||
1000 | 738 | ||
1001 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, | 739 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, |
1002 | tmp_inode->i_ino, obj_type); | 740 | ino, fattr.cf_dtype); |
741 | |||
742 | /* | ||
743 | * we can not return filldir errors to the caller since they are | ||
744 | * "normal" when the stat blocksize is too small - we return remapped | ||
745 | * error instead | ||
746 | * | ||
747 | * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above | ||
748 | * case already. Why should we be clobbering other errors from it? | ||
749 | */ | ||
1003 | if (rc) { | 750 | if (rc) { |
1004 | cFYI(1, ("filldir rc = %d", rc)); | 751 | cFYI(1, ("filldir rc = %d", rc)); |
1005 | /* we can not return filldir errors to the caller | ||
1006 | since they are "normal" when the stat blocksize | ||
1007 | is too small - we return remapped error instead */ | ||
1008 | rc = -EOVERFLOW; | 752 | rc = -EOVERFLOW; |
1009 | } | 753 | } |
1010 | |||
1011 | dput(tmp_dentry); | 754 | dput(tmp_dentry); |
1012 | return rc; | 755 | return rc; |
1013 | } | 756 | } |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 897a052270f9..7085a6275c4c 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -802,7 +802,7 @@ ssetup_ntlmssp_authenticate: | |||
802 | #endif /* CONFIG_CIFS_UPCALL */ | 802 | #endif /* CONFIG_CIFS_UPCALL */ |
803 | } else { | 803 | } else { |
804 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 804 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
805 | if ((experimEnabled > 1) && (type == RawNTLMSSP)) { | 805 | if (type == RawNTLMSSP) { |
806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 806 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { |
807 | cERROR(1, ("NTLMSSP requires Unicode support")); | 807 | cERROR(1, ("NTLMSSP requires Unicode support")); |
808 | rc = -ENOSYS; | 808 | rc = -ENOSYS; |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index e9527eedc639..a75afa3dd9e1 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -64,8 +64,9 @@ int cifs_removexattr(struct dentry *direntry, const char *ea_name) | |||
64 | 64 | ||
65 | full_path = build_path_from_dentry(direntry); | 65 | full_path = build_path_from_dentry(direntry); |
66 | if (full_path == NULL) { | 66 | if (full_path == NULL) { |
67 | rc = -ENOMEM; | ||
67 | FreeXid(xid); | 68 | FreeXid(xid); |
68 | return -ENOMEM; | 69 | return rc; |
69 | } | 70 | } |
70 | if (ea_name == NULL) { | 71 | if (ea_name == NULL) { |
71 | cFYI(1, ("Null xattr names not supported")); | 72 | cFYI(1, ("Null xattr names not supported")); |
@@ -118,8 +119,9 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
118 | 119 | ||
119 | full_path = build_path_from_dentry(direntry); | 120 | full_path = build_path_from_dentry(direntry); |
120 | if (full_path == NULL) { | 121 | if (full_path == NULL) { |
122 | rc = -ENOMEM; | ||
121 | FreeXid(xid); | 123 | FreeXid(xid); |
122 | return -ENOMEM; | 124 | return rc; |
123 | } | 125 | } |
124 | /* return dos attributes as pseudo xattr */ | 126 | /* return dos attributes as pseudo xattr */ |
125 | /* return alt name if available as pseudo attr */ | 127 | /* return alt name if available as pseudo attr */ |
@@ -225,8 +227,9 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, | |||
225 | 227 | ||
226 | full_path = build_path_from_dentry(direntry); | 228 | full_path = build_path_from_dentry(direntry); |
227 | if (full_path == NULL) { | 229 | if (full_path == NULL) { |
230 | rc = -ENOMEM; | ||
228 | FreeXid(xid); | 231 | FreeXid(xid); |
229 | return -ENOMEM; | 232 | return rc; |
230 | } | 233 | } |
231 | /* return dos attributes as pseudo xattr */ | 234 | /* return dos attributes as pseudo xattr */ |
232 | /* return alt name if available as pseudo attr */ | 235 | /* return alt name if available as pseudo attr */ |
@@ -351,8 +354,9 @@ ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | |||
351 | 354 | ||
352 | full_path = build_path_from_dentry(direntry); | 355 | full_path = build_path_from_dentry(direntry); |
353 | if (full_path == NULL) { | 356 | if (full_path == NULL) { |
357 | rc = -ENOMEM; | ||
354 | FreeXid(xid); | 358 | FreeXid(xid); |
355 | return -ENOMEM; | 359 | return rc; |
356 | } | 360 | } |
357 | /* return dos attributes as pseudo xattr */ | 361 | /* return dos attributes as pseudo xattr */ |
358 | /* return alt name if available as pseudo attr */ | 362 | /* return alt name if available as pseudo attr */ |
diff --git a/fs/compat.c b/fs/compat.c index 6aefb776dfeb..94502dab972a 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <linux/smb_mount.h> | 32 | #include <linux/smb_mount.h> |
33 | #include <linux/ncp_mount.h> | 33 | #include <linux/ncp_mount.h> |
34 | #include <linux/nfs4_mount.h> | 34 | #include <linux/nfs4_mount.h> |
35 | #include <linux/smp_lock.h> | ||
36 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
37 | #include <linux/ctype.h> | 36 | #include <linux/ctype.h> |
38 | #include <linux/module.h> | 37 | #include <linux/module.h> |
@@ -471,7 +470,7 @@ asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, | |||
471 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); | 470 | ret = sys_fcntl(fd, cmd, (unsigned long)&f); |
472 | set_fs(old_fs); | 471 | set_fs(old_fs); |
473 | if (cmd == F_GETLK && ret == 0) { | 472 | if (cmd == F_GETLK && ret == 0) { |
474 | /* GETLK was successfule and we need to return the data... | 473 | /* GETLK was successful and we need to return the data... |
475 | * but it needs to fit in the compat structure. | 474 | * but it needs to fit in the compat structure. |
476 | * l_start shouldn't be too big, unless the original | 475 | * l_start shouldn't be too big, unless the original |
477 | * start + end is greater than COMPAT_OFF_T_MAX, in which | 476 | * start + end is greater than COMPAT_OFF_T_MAX, in which |
@@ -1486,8 +1485,8 @@ int compat_do_execve(char * filename, | |||
1486 | if (!bprm) | 1485 | if (!bprm) |
1487 | goto out_files; | 1486 | goto out_files; |
1488 | 1487 | ||
1489 | retval = mutex_lock_interruptible(¤t->cred_guard_mutex); | 1488 | retval = -ERESTARTNOINTR; |
1490 | if (retval < 0) | 1489 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) |
1491 | goto out_free; | 1490 | goto out_free; |
1492 | current->in_execve = 1; | 1491 | current->in_execve = 1; |
1493 | 1492 | ||
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index b83f6bcfa51a..f91fd51b32e3 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/compiler.h> | 19 | #include <linux/compiler.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
22 | #include <linux/smp_lock.h> | ||
22 | #include <linux/ioctl.h> | 23 | #include <linux/ioctl.h> |
23 | #include <linux/if.h> | 24 | #include <linux/if.h> |
24 | #include <linux/if_bridge.h> | 25 | #include <linux/if_bridge.h> |
@@ -31,6 +32,7 @@ | |||
31 | #include <linux/skbuff.h> | 32 | #include <linux/skbuff.h> |
32 | #include <linux/netlink.h> | 33 | #include <linux/netlink.h> |
33 | #include <linux/vt.h> | 34 | #include <linux/vt.h> |
35 | #include <linux/falloc.h> | ||
34 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
35 | #include <linux/file.h> | 37 | #include <linux/file.h> |
36 | #include <linux/ppp_defs.h> | 38 | #include <linux/ppp_defs.h> |
@@ -94,7 +96,6 @@ | |||
94 | #include <linux/atm_tcp.h> | 96 | #include <linux/atm_tcp.h> |
95 | #include <linux/sonet.h> | 97 | #include <linux/sonet.h> |
96 | #include <linux/atm_suni.h> | 98 | #include <linux/atm_suni.h> |
97 | #include <linux/mtd/mtd.h> | ||
98 | 99 | ||
99 | #include <linux/usb.h> | 100 | #include <linux/usb.h> |
100 | #include <linux/usbdevice_fs.h> | 101 | #include <linux/usbdevice_fs.h> |
@@ -788,12 +789,6 @@ static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
788 | if (put_user(compat_ptr(data), &sgio->usr_ptr)) | 789 | if (put_user(compat_ptr(data), &sgio->usr_ptr)) |
789 | return -EFAULT; | 790 | return -EFAULT; |
790 | 791 | ||
791 | if (copy_in_user(&sgio->status, &sgio32->status, | ||
792 | (4 * sizeof(unsigned char)) + | ||
793 | (2 * sizeof(unsigned short)) + | ||
794 | (3 * sizeof(int)))) | ||
795 | return -EFAULT; | ||
796 | |||
797 | err = sys_ioctl(fd, cmd, (unsigned long) sgio); | 792 | err = sys_ioctl(fd, cmd, (unsigned long) sgio); |
798 | 793 | ||
799 | if (err >= 0) { | 794 | if (err >= 0) { |
@@ -1411,46 +1406,6 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
1411 | #define HIDPGETCONNLIST _IOR('H', 210, int) | 1406 | #define HIDPGETCONNLIST _IOR('H', 210, int) |
1412 | #define HIDPGETCONNINFO _IOR('H', 211, int) | 1407 | #define HIDPGETCONNINFO _IOR('H', 211, int) |
1413 | 1408 | ||
1414 | struct mtd_oob_buf32 { | ||
1415 | u_int32_t start; | ||
1416 | u_int32_t length; | ||
1417 | compat_caddr_t ptr; /* unsigned char* */ | ||
1418 | }; | ||
1419 | |||
1420 | #define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) | ||
1421 | #define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) | ||
1422 | |||
1423 | static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) | ||
1424 | { | ||
1425 | struct mtd_oob_buf __user *buf = compat_alloc_user_space(sizeof(*buf)); | ||
1426 | struct mtd_oob_buf32 __user *buf32 = compat_ptr(arg); | ||
1427 | u32 data; | ||
1428 | char __user *datap; | ||
1429 | unsigned int real_cmd; | ||
1430 | int err; | ||
1431 | |||
1432 | real_cmd = (cmd == MEMREADOOB32) ? | ||
1433 | MEMREADOOB : MEMWRITEOOB; | ||
1434 | |||
1435 | if (copy_in_user(&buf->start, &buf32->start, | ||
1436 | 2 * sizeof(u32)) || | ||
1437 | get_user(data, &buf32->ptr)) | ||
1438 | return -EFAULT; | ||
1439 | datap = compat_ptr(data); | ||
1440 | if (put_user(datap, &buf->ptr)) | ||
1441 | return -EFAULT; | ||
1442 | |||
1443 | err = sys_ioctl(fd, real_cmd, (unsigned long) buf); | ||
1444 | |||
1445 | if (!err) { | ||
1446 | if (copy_in_user(&buf32->start, &buf->start, | ||
1447 | 2 * sizeof(u32))) | ||
1448 | err = -EFAULT; | ||
1449 | } | ||
1450 | |||
1451 | return err; | ||
1452 | } | ||
1453 | |||
1454 | #ifdef CONFIG_BLOCK | 1409 | #ifdef CONFIG_BLOCK |
1455 | struct raw32_config_request | 1410 | struct raw32_config_request |
1456 | { | 1411 | { |
@@ -1765,7 +1720,7 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd, unsigned long a | |||
1765 | 1720 | ||
1766 | /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE | 1721 | /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE |
1767 | * for some operations; this forces use of the newer bridge-utils that | 1722 | * for some operations; this forces use of the newer bridge-utils that |
1768 | * use compatiable ioctls | 1723 | * use compatible ioctls |
1769 | */ | 1724 | */ |
1770 | static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) | 1725 | static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) |
1771 | { | 1726 | { |
@@ -1826,6 +1781,41 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg) | |||
1826 | return sys_ioctl(fd, cmd, (unsigned long)tn); | 1781 | return sys_ioctl(fd, cmd, (unsigned long)tn); |
1827 | } | 1782 | } |
1828 | 1783 | ||
1784 | /* on ia32 l_start is on a 32-bit boundary */ | ||
1785 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | ||
1786 | struct space_resv_32 { | ||
1787 | __s16 l_type; | ||
1788 | __s16 l_whence; | ||
1789 | __s64 l_start __attribute__((packed)); | ||
1790 | /* len == 0 means until end of file */ | ||
1791 | __s64 l_len __attribute__((packed)); | ||
1792 | __s32 l_sysid; | ||
1793 | __u32 l_pid; | ||
1794 | __s32 l_pad[4]; /* reserve area */ | ||
1795 | }; | ||
1796 | |||
1797 | #define FS_IOC_RESVSP_32 _IOW ('X', 40, struct space_resv_32) | ||
1798 | #define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32) | ||
1799 | |||
1800 | /* just account for different alignment */ | ||
1801 | static int compat_ioctl_preallocate(struct file *file, unsigned long arg) | ||
1802 | { | ||
1803 | struct space_resv_32 __user *p32 = (void __user *)arg; | ||
1804 | struct space_resv __user *p = compat_alloc_user_space(sizeof(*p)); | ||
1805 | |||
1806 | if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) || | ||
1807 | copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) || | ||
1808 | copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) || | ||
1809 | copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) || | ||
1810 | copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) || | ||
1811 | copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) || | ||
1812 | copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32))) | ||
1813 | return -EFAULT; | ||
1814 | |||
1815 | return ioctl_preallocate(file, p); | ||
1816 | } | ||
1817 | #endif | ||
1818 | |||
1829 | 1819 | ||
1830 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, | 1820 | typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int, |
1831 | unsigned long, struct file *); | 1821 | unsigned long, struct file *); |
@@ -1915,6 +1905,7 @@ COMPATIBLE_IOCTL(FIONCLEX) | |||
1915 | COMPATIBLE_IOCTL(FIOASYNC) | 1905 | COMPATIBLE_IOCTL(FIOASYNC) |
1916 | COMPATIBLE_IOCTL(FIONBIO) | 1906 | COMPATIBLE_IOCTL(FIONBIO) |
1917 | COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ | 1907 | COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ |
1908 | COMPATIBLE_IOCTL(FS_IOC_FIEMAP) | ||
1918 | /* 0x00 */ | 1909 | /* 0x00 */ |
1919 | COMPATIBLE_IOCTL(FIBMAP) | 1910 | COMPATIBLE_IOCTL(FIBMAP) |
1920 | COMPATIBLE_IOCTL(FIGETBSZ) | 1911 | COMPATIBLE_IOCTL(FIGETBSZ) |
@@ -2432,15 +2423,6 @@ COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32) | |||
2432 | COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) | 2423 | COMPATIBLE_IOCTL(USBDEVFS_REAPURB32) |
2433 | COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) | 2424 | COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32) |
2434 | COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) | 2425 | COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT) |
2435 | /* MTD */ | ||
2436 | COMPATIBLE_IOCTL(MEMGETINFO) | ||
2437 | COMPATIBLE_IOCTL(MEMERASE) | ||
2438 | COMPATIBLE_IOCTL(MEMLOCK) | ||
2439 | COMPATIBLE_IOCTL(MEMUNLOCK) | ||
2440 | COMPATIBLE_IOCTL(MEMGETREGIONCOUNT) | ||
2441 | COMPATIBLE_IOCTL(MEMGETREGIONINFO) | ||
2442 | COMPATIBLE_IOCTL(MEMGETBADBLOCK) | ||
2443 | COMPATIBLE_IOCTL(MEMSETBADBLOCK) | ||
2444 | /* NBD */ | 2426 | /* NBD */ |
2445 | ULONG_IOCTL(NBD_SET_SOCK) | 2427 | ULONG_IOCTL(NBD_SET_SOCK) |
2446 | ULONG_IOCTL(NBD_SET_BLKSIZE) | 2428 | ULONG_IOCTL(NBD_SET_BLKSIZE) |
@@ -2550,8 +2532,6 @@ COMPATIBLE_IOCTL(JSIOCGBUTTONS) | |||
2550 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) | 2532 | COMPATIBLE_IOCTL(JSIOCGNAME(0)) |
2551 | 2533 | ||
2552 | /* now things that need handlers */ | 2534 | /* now things that need handlers */ |
2553 | HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) | ||
2554 | HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) | ||
2555 | #ifdef CONFIG_NET | 2535 | #ifdef CONFIG_NET |
2556 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) | 2536 | HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) |
2557 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) | 2537 | HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) |
@@ -2814,6 +2794,18 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | |||
2814 | case FIOQSIZE: | 2794 | case FIOQSIZE: |
2815 | break; | 2795 | break; |
2816 | 2796 | ||
2797 | #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) | ||
2798 | case FS_IOC_RESVSP_32: | ||
2799 | case FS_IOC_RESVSP64_32: | ||
2800 | error = compat_ioctl_preallocate(filp, arg); | ||
2801 | goto out_fput; | ||
2802 | #else | ||
2803 | case FS_IOC_RESVSP: | ||
2804 | case FS_IOC_RESVSP64: | ||
2805 | error = ioctl_preallocate(filp, (void __user *)arg); | ||
2806 | goto out_fput; | ||
2807 | #endif | ||
2808 | |||
2817 | case FIBMAP: | 2809 | case FIBMAP: |
2818 | case FIGETBSZ: | 2810 | case FIGETBSZ: |
2819 | case FIONREAD: | 2811 | case FIONREAD: |
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 33a90120f6ad..4d74fc72c195 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -67,6 +67,8 @@ static int debugfs_u8_get(void *data, u64 *val) | |||
67 | return 0; | 67 | return 0; |
68 | } | 68 | } |
69 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); | 69 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); |
70 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n"); | ||
71 | DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n"); | ||
70 | 72 | ||
71 | /** | 73 | /** |
72 | * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value | 74 | * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value |
@@ -95,6 +97,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n"); | |||
95 | struct dentry *debugfs_create_u8(const char *name, mode_t mode, | 97 | struct dentry *debugfs_create_u8(const char *name, mode_t mode, |
96 | struct dentry *parent, u8 *value) | 98 | struct dentry *parent, u8 *value) |
97 | { | 99 | { |
100 | /* if there are no write bits set, make read only */ | ||
101 | if (!(mode & S_IWUGO)) | ||
102 | return debugfs_create_file(name, mode, parent, value, &fops_u8_ro); | ||
103 | /* if there are no read bits set, make write only */ | ||
104 | if (!(mode & S_IRUGO)) | ||
105 | return debugfs_create_file(name, mode, parent, value, &fops_u8_wo); | ||
106 | |||
98 | return debugfs_create_file(name, mode, parent, value, &fops_u8); | 107 | return debugfs_create_file(name, mode, parent, value, &fops_u8); |
99 | } | 108 | } |
100 | EXPORT_SYMBOL_GPL(debugfs_create_u8); | 109 | EXPORT_SYMBOL_GPL(debugfs_create_u8); |
@@ -110,6 +119,8 @@ static int debugfs_u16_get(void *data, u64 *val) | |||
110 | return 0; | 119 | return 0; |
111 | } | 120 | } |
112 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); | 121 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); |
122 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n"); | ||
123 | DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n"); | ||
113 | 124 | ||
114 | /** | 125 | /** |
115 | * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value | 126 | * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value |
@@ -138,6 +149,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n"); | |||
138 | struct dentry *debugfs_create_u16(const char *name, mode_t mode, | 149 | struct dentry *debugfs_create_u16(const char *name, mode_t mode, |
139 | struct dentry *parent, u16 *value) | 150 | struct dentry *parent, u16 *value) |
140 | { | 151 | { |
152 | /* if there are no write bits set, make read only */ | ||
153 | if (!(mode & S_IWUGO)) | ||
154 | return debugfs_create_file(name, mode, parent, value, &fops_u16_ro); | ||
155 | /* if there are no read bits set, make write only */ | ||
156 | if (!(mode & S_IRUGO)) | ||
157 | return debugfs_create_file(name, mode, parent, value, &fops_u16_wo); | ||
158 | |||
141 | return debugfs_create_file(name, mode, parent, value, &fops_u16); | 159 | return debugfs_create_file(name, mode, parent, value, &fops_u16); |
142 | } | 160 | } |
143 | EXPORT_SYMBOL_GPL(debugfs_create_u16); | 161 | EXPORT_SYMBOL_GPL(debugfs_create_u16); |
@@ -153,6 +171,8 @@ static int debugfs_u32_get(void *data, u64 *val) | |||
153 | return 0; | 171 | return 0; |
154 | } | 172 | } |
155 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); | 173 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); |
174 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n"); | ||
175 | DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n"); | ||
156 | 176 | ||
157 | /** | 177 | /** |
158 | * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value | 178 | * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value |
@@ -181,6 +201,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n"); | |||
181 | struct dentry *debugfs_create_u32(const char *name, mode_t mode, | 201 | struct dentry *debugfs_create_u32(const char *name, mode_t mode, |
182 | struct dentry *parent, u32 *value) | 202 | struct dentry *parent, u32 *value) |
183 | { | 203 | { |
204 | /* if there are no write bits set, make read only */ | ||
205 | if (!(mode & S_IWUGO)) | ||
206 | return debugfs_create_file(name, mode, parent, value, &fops_u32_ro); | ||
207 | /* if there are no read bits set, make write only */ | ||
208 | if (!(mode & S_IRUGO)) | ||
209 | return debugfs_create_file(name, mode, parent, value, &fops_u32_wo); | ||
210 | |||
184 | return debugfs_create_file(name, mode, parent, value, &fops_u32); | 211 | return debugfs_create_file(name, mode, parent, value, &fops_u32); |
185 | } | 212 | } |
186 | EXPORT_SYMBOL_GPL(debugfs_create_u32); | 213 | EXPORT_SYMBOL_GPL(debugfs_create_u32); |
@@ -197,6 +224,8 @@ static int debugfs_u64_get(void *data, u64 *val) | |||
197 | return 0; | 224 | return 0; |
198 | } | 225 | } |
199 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); | 226 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); |
227 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n"); | ||
228 | DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n"); | ||
200 | 229 | ||
201 | /** | 230 | /** |
202 | * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value | 231 | * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value |
@@ -225,15 +254,28 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n"); | |||
225 | struct dentry *debugfs_create_u64(const char *name, mode_t mode, | 254 | struct dentry *debugfs_create_u64(const char *name, mode_t mode, |
226 | struct dentry *parent, u64 *value) | 255 | struct dentry *parent, u64 *value) |
227 | { | 256 | { |
257 | /* if there are no write bits set, make read only */ | ||
258 | if (!(mode & S_IWUGO)) | ||
259 | return debugfs_create_file(name, mode, parent, value, &fops_u64_ro); | ||
260 | /* if there are no read bits set, make write only */ | ||
261 | if (!(mode & S_IRUGO)) | ||
262 | return debugfs_create_file(name, mode, parent, value, &fops_u64_wo); | ||
263 | |||
228 | return debugfs_create_file(name, mode, parent, value, &fops_u64); | 264 | return debugfs_create_file(name, mode, parent, value, &fops_u64); |
229 | } | 265 | } |
230 | EXPORT_SYMBOL_GPL(debugfs_create_u64); | 266 | EXPORT_SYMBOL_GPL(debugfs_create_u64); |
231 | 267 | ||
232 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); | 268 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n"); |
269 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n"); | ||
270 | DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n"); | ||
233 | 271 | ||
234 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n"); | 272 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n"); |
273 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n"); | ||
274 | DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n"); | ||
235 | 275 | ||
236 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"); | 276 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"); |
277 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n"); | ||
278 | DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n"); | ||
237 | 279 | ||
238 | /* | 280 | /* |
239 | * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value | 281 | * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value |
@@ -256,6 +298,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n" | |||
256 | struct dentry *debugfs_create_x8(const char *name, mode_t mode, | 298 | struct dentry *debugfs_create_x8(const char *name, mode_t mode, |
257 | struct dentry *parent, u8 *value) | 299 | struct dentry *parent, u8 *value) |
258 | { | 300 | { |
301 | /* if there are no write bits set, make read only */ | ||
302 | if (!(mode & S_IWUGO)) | ||
303 | return debugfs_create_file(name, mode, parent, value, &fops_x8_ro); | ||
304 | /* if there are no read bits set, make write only */ | ||
305 | if (!(mode & S_IRUGO)) | ||
306 | return debugfs_create_file(name, mode, parent, value, &fops_x8_wo); | ||
307 | |||
259 | return debugfs_create_file(name, mode, parent, value, &fops_x8); | 308 | return debugfs_create_file(name, mode, parent, value, &fops_x8); |
260 | } | 309 | } |
261 | EXPORT_SYMBOL_GPL(debugfs_create_x8); | 310 | EXPORT_SYMBOL_GPL(debugfs_create_x8); |
@@ -273,6 +322,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8); | |||
273 | struct dentry *debugfs_create_x16(const char *name, mode_t mode, | 322 | struct dentry *debugfs_create_x16(const char *name, mode_t mode, |
274 | struct dentry *parent, u16 *value) | 323 | struct dentry *parent, u16 *value) |
275 | { | 324 | { |
325 | /* if there are no write bits set, make read only */ | ||
326 | if (!(mode & S_IWUGO)) | ||
327 | return debugfs_create_file(name, mode, parent, value, &fops_x16_ro); | ||
328 | /* if there are no read bits set, make write only */ | ||
329 | if (!(mode & S_IRUGO)) | ||
330 | return debugfs_create_file(name, mode, parent, value, &fops_x16_wo); | ||
331 | |||
276 | return debugfs_create_file(name, mode, parent, value, &fops_x16); | 332 | return debugfs_create_file(name, mode, parent, value, &fops_x16); |
277 | } | 333 | } |
278 | EXPORT_SYMBOL_GPL(debugfs_create_x16); | 334 | EXPORT_SYMBOL_GPL(debugfs_create_x16); |
@@ -290,6 +346,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16); | |||
290 | struct dentry *debugfs_create_x32(const char *name, mode_t mode, | 346 | struct dentry *debugfs_create_x32(const char *name, mode_t mode, |
291 | struct dentry *parent, u32 *value) | 347 | struct dentry *parent, u32 *value) |
292 | { | 348 | { |
349 | /* if there are no write bits set, make read only */ | ||
350 | if (!(mode & S_IWUGO)) | ||
351 | return debugfs_create_file(name, mode, parent, value, &fops_x32_ro); | ||
352 | /* if there are no read bits set, make write only */ | ||
353 | if (!(mode & S_IRUGO)) | ||
354 | return debugfs_create_file(name, mode, parent, value, &fops_x32_wo); | ||
355 | |||
293 | return debugfs_create_file(name, mode, parent, value, &fops_x32); | 356 | return debugfs_create_file(name, mode, parent, value, &fops_x32); |
294 | } | 357 | } |
295 | EXPORT_SYMBOL_GPL(debugfs_create_x32); | 358 | EXPORT_SYMBOL_GPL(debugfs_create_x32); |
@@ -419,7 +482,7 @@ static const struct file_operations fops_blob = { | |||
419 | }; | 482 | }; |
420 | 483 | ||
421 | /** | 484 | /** |
422 | * debugfs_create_blob - create a debugfs file that is used to read and write a binary blob | 485 | * debugfs_create_blob - create a debugfs file that is used to read a binary blob |
423 | * @name: a pointer to a string containing the name of the file to create. | 486 | * @name: a pointer to a string containing the name of the file to create. |
424 | * @mode: the permission that the file should have | 487 | * @mode: the permission that the file should have |
425 | * @parent: a pointer to the parent dentry for this file. This should be a | 488 | * @parent: a pointer to the parent dentry for this file. This should be a |
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 0662ba6de85a..d22438ef7674 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
@@ -403,6 +403,7 @@ void debugfs_remove_recursive(struct dentry *dentry) | |||
403 | } | 403 | } |
404 | child = list_entry(parent->d_subdirs.next, struct dentry, | 404 | child = list_entry(parent->d_subdirs.next, struct dentry, |
405 | d_u.d_child); | 405 | d_u.d_child); |
406 | next_sibling: | ||
406 | 407 | ||
407 | /* | 408 | /* |
408 | * If "child" isn't empty, walk down the tree and | 409 | * If "child" isn't empty, walk down the tree and |
@@ -417,6 +418,16 @@ void debugfs_remove_recursive(struct dentry *dentry) | |||
417 | __debugfs_remove(child, parent); | 418 | __debugfs_remove(child, parent); |
418 | if (parent->d_subdirs.next == &child->d_u.d_child) { | 419 | if (parent->d_subdirs.next == &child->d_u.d_child) { |
419 | /* | 420 | /* |
421 | * Try the next sibling. | ||
422 | */ | ||
423 | if (child->d_u.d_child.next != &parent->d_subdirs) { | ||
424 | child = list_entry(child->d_u.d_child.next, | ||
425 | struct dentry, | ||
426 | d_u.d_child); | ||
427 | goto next_sibling; | ||
428 | } | ||
429 | |||
430 | /* | ||
420 | * Avoid infinite loop if we fail to remove | 431 | * Avoid infinite loop if we fail to remove |
421 | * one dentry. | 432 | * one dentry. |
422 | */ | 433 | */ |
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 9b1d285f9fe6..75efb028974b 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
@@ -423,7 +423,6 @@ static void devpts_kill_sb(struct super_block *sb) | |||
423 | } | 423 | } |
424 | 424 | ||
425 | static struct file_system_type devpts_fs_type = { | 425 | static struct file_system_type devpts_fs_type = { |
426 | .owner = THIS_MODULE, | ||
427 | .name = "devpts", | 426 | .name = "devpts", |
428 | .get_sb = devpts_get_sb, | 427 | .get_sb = devpts_get_sb, |
429 | .kill_sb = devpts_kill_sb, | 428 | .kill_sb = devpts_kill_sb, |
@@ -564,13 +563,4 @@ static int __init init_devpts_fs(void) | |||
564 | } | 563 | } |
565 | return err; | 564 | return err; |
566 | } | 565 | } |
567 | |||
568 | static void __exit exit_devpts_fs(void) | ||
569 | { | ||
570 | unregister_filesystem(&devpts_fs_type); | ||
571 | mntput(devpts_mnt); | ||
572 | } | ||
573 | |||
574 | module_init(init_devpts_fs) | 566 | module_init(init_devpts_fs) |
575 | module_exit(exit_devpts_fs) | ||
576 | MODULE_LICENSE("GPL"); | ||
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index 205ec95b347e..eb507c453c5f 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c | |||
@@ -435,7 +435,7 @@ static int search_rsb(struct dlm_ls *ls, char *name, int len, int b, | |||
435 | static int find_rsb(struct dlm_ls *ls, char *name, int namelen, | 435 | static int find_rsb(struct dlm_ls *ls, char *name, int namelen, |
436 | unsigned int flags, struct dlm_rsb **r_ret) | 436 | unsigned int flags, struct dlm_rsb **r_ret) |
437 | { | 437 | { |
438 | struct dlm_rsb *r, *tmp; | 438 | struct dlm_rsb *r = NULL, *tmp; |
439 | uint32_t hash, bucket; | 439 | uint32_t hash, bucket; |
440 | int error = -EINVAL; | 440 | int error = -EINVAL; |
441 | 441 | ||
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index cdb580a9c7a2..618a60f03886 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
@@ -902,7 +902,7 @@ static void tcp_connect_to_sock(struct connection *con) | |||
902 | int result = -EHOSTUNREACH; | 902 | int result = -EHOSTUNREACH; |
903 | struct sockaddr_storage saddr, src_addr; | 903 | struct sockaddr_storage saddr, src_addr; |
904 | int addr_len; | 904 | int addr_len; |
905 | struct socket *sock; | 905 | struct socket *sock = NULL; |
906 | 906 | ||
907 | if (con->nodeid == 0) { | 907 | if (con->nodeid == 0) { |
908 | log_print("attempt to connect sock 0 foiled"); | 908 | log_print("attempt to connect sock 0 foiled"); |
@@ -962,6 +962,8 @@ out_err: | |||
962 | if (con->sock) { | 962 | if (con->sock) { |
963 | sock_release(con->sock); | 963 | sock_release(con->sock); |
964 | con->sock = NULL; | 964 | con->sock = NULL; |
965 | } else if (sock) { | ||
966 | sock_release(sock); | ||
965 | } | 967 | } |
966 | /* | 968 | /* |
967 | * Some errors are fatal and this list might need adjusting. For other | 969 | * Some errors are fatal and this list might need adjusting. For other |
diff --git a/fs/dlm/plock.c b/fs/dlm/plock.c index 894a32d438d5..16f682e26c07 100644 --- a/fs/dlm/plock.c +++ b/fs/dlm/plock.c | |||
@@ -353,7 +353,7 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |||
353 | { | 353 | { |
354 | struct dlm_plock_info info; | 354 | struct dlm_plock_info info; |
355 | struct plock_op *op; | 355 | struct plock_op *op; |
356 | int found = 0; | 356 | int found = 0, do_callback = 0; |
357 | 357 | ||
358 | if (count != sizeof(info)) | 358 | if (count != sizeof(info)) |
359 | return -EINVAL; | 359 | return -EINVAL; |
@@ -366,21 +366,24 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count, | |||
366 | 366 | ||
367 | spin_lock(&ops_lock); | 367 | spin_lock(&ops_lock); |
368 | list_for_each_entry(op, &recv_list, list) { | 368 | list_for_each_entry(op, &recv_list, list) { |
369 | if (op->info.fsid == info.fsid && op->info.number == info.number && | 369 | if (op->info.fsid == info.fsid && |
370 | op->info.number == info.number && | ||
370 | op->info.owner == info.owner) { | 371 | op->info.owner == info.owner) { |
372 | struct plock_xop *xop = (struct plock_xop *)op; | ||
371 | list_del_init(&op->list); | 373 | list_del_init(&op->list); |
372 | found = 1; | ||
373 | op->done = 1; | ||
374 | memcpy(&op->info, &info, sizeof(info)); | 374 | memcpy(&op->info, &info, sizeof(info)); |
375 | if (xop->callback) | ||
376 | do_callback = 1; | ||
377 | else | ||
378 | op->done = 1; | ||
379 | found = 1; | ||
375 | break; | 380 | break; |
376 | } | 381 | } |
377 | } | 382 | } |
378 | spin_unlock(&ops_lock); | 383 | spin_unlock(&ops_lock); |
379 | 384 | ||
380 | if (found) { | 385 | if (found) { |
381 | struct plock_xop *xop; | 386 | if (do_callback) |
382 | xop = (struct plock_xop *)op; | ||
383 | if (xop->callback) | ||
384 | dlm_plock_callback(op); | 387 | dlm_plock_callback(op); |
385 | else | 388 | else |
386 | wake_up(&recv_wq); | 389 | wake_up(&recv_wq); |
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index b6a719a909f8..a2edb7913447 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c | |||
@@ -24,7 +24,7 @@ static void drop_pagecache_sb(struct super_block *sb) | |||
24 | continue; | 24 | continue; |
25 | __iget(inode); | 25 | __iget(inode); |
26 | spin_unlock(&inode_lock); | 26 | spin_unlock(&inode_lock); |
27 | __invalidate_mapping_pages(inode->i_mapping, 0, -1, true); | 27 | invalidate_mapping_pages(inode->i_mapping, 0, -1); |
28 | iput(toput_inode); | 28 | iput(toput_inode); |
29 | toput_inode = inode; | 29 | toput_inode = inode; |
30 | spin_lock(&inode_lock); | 30 | spin_lock(&inode_lock); |
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index af737bb56cb7..259525c9abb8 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c | |||
@@ -1303,6 +1303,13 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, | |||
1303 | } | 1303 | } |
1304 | (*new_auth_tok)->session_key.encrypted_key_size = | 1304 | (*new_auth_tok)->session_key.encrypted_key_size = |
1305 | (body_size - (ECRYPTFS_SALT_SIZE + 5)); | 1305 | (body_size - (ECRYPTFS_SALT_SIZE + 5)); |
1306 | if ((*new_auth_tok)->session_key.encrypted_key_size | ||
1307 | > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { | ||
1308 | printk(KERN_WARNING "Tag 3 packet contains key larger " | ||
1309 | "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n"); | ||
1310 | rc = -EINVAL; | ||
1311 | goto out_free; | ||
1312 | } | ||
1306 | if (unlikely(data[(*packet_size)++] != 0x04)) { | 1313 | if (unlikely(data[(*packet_size)++] != 0x04)) { |
1307 | printk(KERN_WARNING "Unknown version number [%d]\n", | 1314 | printk(KERN_WARNING "Unknown version number [%d]\n", |
1308 | data[(*packet_size) - 1]); | 1315 | data[(*packet_size) - 1]); |
@@ -1449,6 +1456,12 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents, | |||
1449 | rc = -EINVAL; | 1456 | rc = -EINVAL; |
1450 | goto out; | 1457 | goto out; |
1451 | } | 1458 | } |
1459 | if (unlikely((*tag_11_contents_size) > max_contents_bytes)) { | ||
1460 | printk(KERN_ERR "Literal data section in tag 11 packet exceeds " | ||
1461 | "expected size\n"); | ||
1462 | rc = -EINVAL; | ||
1463 | goto out; | ||
1464 | } | ||
1452 | if (data[(*packet_size)++] != 0x62) { | 1465 | if (data[(*packet_size)++] != 0x62) { |
1453 | printk(KERN_WARNING "Unrecognizable packet\n"); | 1466 | printk(KERN_WARNING "Unrecognizable packet\n"); |
1454 | rc = -EINVAL; | 1467 | rc = -EINVAL; |
diff --git a/fs/efs/dir.c b/fs/efs/dir.c index 49308a29798a..7ee6f7e3a608 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c | |||
@@ -5,12 +5,12 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/buffer_head.h> | 7 | #include <linux/buffer_head.h> |
8 | #include <linux/smp_lock.h> | ||
9 | #include "efs.h" | 8 | #include "efs.h" |
10 | 9 | ||
11 | static int efs_readdir(struct file *, void *, filldir_t); | 10 | static int efs_readdir(struct file *, void *, filldir_t); |
12 | 11 | ||
13 | const struct file_operations efs_dir_operations = { | 12 | const struct file_operations efs_dir_operations = { |
13 | .llseek = generic_file_llseek, | ||
14 | .read = generic_read_dir, | 14 | .read = generic_read_dir, |
15 | .readdir = efs_readdir, | 15 | .readdir = efs_readdir, |
16 | }; | 16 | }; |
@@ -33,8 +33,6 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { | |||
33 | if (inode->i_size & (EFS_DIRBSIZE-1)) | 33 | if (inode->i_size & (EFS_DIRBSIZE-1)) |
34 | printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); | 34 | printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); |
35 | 35 | ||
36 | lock_kernel(); | ||
37 | |||
38 | /* work out where this entry can be found */ | 36 | /* work out where this entry can be found */ |
39 | block = filp->f_pos >> EFS_DIRBSIZE_BITS; | 37 | block = filp->f_pos >> EFS_DIRBSIZE_BITS; |
40 | 38 | ||
@@ -107,7 +105,6 @@ static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) { | |||
107 | 105 | ||
108 | filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; | 106 | filp->f_pos = (block << EFS_DIRBSIZE_BITS) | slot; |
109 | out: | 107 | out: |
110 | unlock_kernel(); | ||
111 | return 0; | 108 | return 0; |
112 | } | 109 | } |
113 | 110 | ||
diff --git a/fs/efs/namei.c b/fs/efs/namei.c index c3fb5f9c4a44..1511bf9e5f80 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c | |||
@@ -8,7 +8,6 @@ | |||
8 | 8 | ||
9 | #include <linux/buffer_head.h> | 9 | #include <linux/buffer_head.h> |
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/smp_lock.h> | ||
12 | #include <linux/exportfs.h> | 11 | #include <linux/exportfs.h> |
13 | #include "efs.h" | 12 | #include "efs.h" |
14 | 13 | ||
@@ -63,16 +62,12 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei | |||
63 | efs_ino_t inodenum; | 62 | efs_ino_t inodenum; |
64 | struct inode * inode = NULL; | 63 | struct inode * inode = NULL; |
65 | 64 | ||
66 | lock_kernel(); | ||
67 | inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); | 65 | inodenum = efs_find_entry(dir, dentry->d_name.name, dentry->d_name.len); |
68 | if (inodenum) { | 66 | if (inodenum) { |
69 | inode = efs_iget(dir->i_sb, inodenum); | 67 | inode = efs_iget(dir->i_sb, inodenum); |
70 | if (IS_ERR(inode)) { | 68 | if (IS_ERR(inode)) |
71 | unlock_kernel(); | ||
72 | return ERR_CAST(inode); | 69 | return ERR_CAST(inode); |
73 | } | ||
74 | } | 70 | } |
75 | unlock_kernel(); | ||
76 | 71 | ||
77 | return d_splice_alias(inode, dentry); | 72 | return d_splice_alias(inode, dentry); |
78 | } | 73 | } |
@@ -115,11 +110,9 @@ struct dentry *efs_get_parent(struct dentry *child) | |||
115 | struct dentry *parent = ERR_PTR(-ENOENT); | 110 | struct dentry *parent = ERR_PTR(-ENOENT); |
116 | efs_ino_t ino; | 111 | efs_ino_t ino; |
117 | 112 | ||
118 | lock_kernel(); | ||
119 | ino = efs_find_entry(child->d_inode, "..", 2); | 113 | ino = efs_find_entry(child->d_inode, "..", 2); |
120 | if (ino) | 114 | if (ino) |
121 | parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino)); | 115 | parent = d_obtain_alias(efs_iget(child->d_inode->i_sb, ino)); |
122 | unlock_kernel(); | ||
123 | 116 | ||
124 | return parent; | 117 | return parent; |
125 | } | 118 | } |
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index 41911ec83aaf..75117d0dac2b 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/string.h> | 9 | #include <linux/string.h> |
10 | #include <linux/pagemap.h> | 10 | #include <linux/pagemap.h> |
11 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
12 | #include <linux/smp_lock.h> | ||
13 | #include "efs.h" | 12 | #include "efs.h" |
14 | 13 | ||
15 | static int efs_symlink_readpage(struct file *file, struct page *page) | 14 | static int efs_symlink_readpage(struct file *file, struct page *page) |
@@ -22,9 +21,8 @@ static int efs_symlink_readpage(struct file *file, struct page *page) | |||
22 | 21 | ||
23 | err = -ENAMETOOLONG; | 22 | err = -ENAMETOOLONG; |
24 | if (size > 2 * EFS_BLOCKSIZE) | 23 | if (size > 2 * EFS_BLOCKSIZE) |
25 | goto fail_notlocked; | 24 | goto fail; |
26 | 25 | ||
27 | lock_kernel(); | ||
28 | /* read first 512 bytes of link target */ | 26 | /* read first 512 bytes of link target */ |
29 | err = -EIO; | 27 | err = -EIO; |
30 | bh = sb_bread(inode->i_sb, efs_bmap(inode, 0)); | 28 | bh = sb_bread(inode->i_sb, efs_bmap(inode, 0)); |
@@ -40,14 +38,11 @@ static int efs_symlink_readpage(struct file *file, struct page *page) | |||
40 | brelse(bh); | 38 | brelse(bh); |
41 | } | 39 | } |
42 | link[size] = '\0'; | 40 | link[size] = '\0'; |
43 | unlock_kernel(); | ||
44 | SetPageUptodate(page); | 41 | SetPageUptodate(page); |
45 | kunmap(page); | 42 | kunmap(page); |
46 | unlock_page(page); | 43 | unlock_page(page); |
47 | return 0; | 44 | return 0; |
48 | fail: | 45 | fail: |
49 | unlock_kernel(); | ||
50 | fail_notlocked: | ||
51 | SetPageError(page); | 46 | SetPageError(page); |
52 | kunmap(page); | 47 | kunmap(page); |
53 | unlock_page(page); | 48 | unlock_page(page); |
diff --git a/fs/eventfd.c b/fs/eventfd.c index 3f0e1974abdc..31d12de83a2a 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c | |||
@@ -14,35 +14,44 @@ | |||
14 | #include <linux/list.h> | 14 | #include <linux/list.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/anon_inodes.h> | 16 | #include <linux/anon_inodes.h> |
17 | #include <linux/eventfd.h> | ||
18 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
19 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/kref.h> | ||
20 | #include <linux/eventfd.h> | ||
20 | 21 | ||
21 | struct eventfd_ctx { | 22 | struct eventfd_ctx { |
23 | struct kref kref; | ||
22 | wait_queue_head_t wqh; | 24 | wait_queue_head_t wqh; |
23 | /* | 25 | /* |
24 | * Every time that a write(2) is performed on an eventfd, the | 26 | * Every time that a write(2) is performed on an eventfd, the |
25 | * value of the __u64 being written is added to "count" and a | 27 | * value of the __u64 being written is added to "count" and a |
26 | * wakeup is performed on "wqh". A read(2) will return the "count" | 28 | * wakeup is performed on "wqh". A read(2) will return the "count" |
27 | * value to userspace, and will reset "count" to zero. The kernel | 29 | * value to userspace, and will reset "count" to zero. The kernel |
28 | * size eventfd_signal() also, adds to the "count" counter and | 30 | * side eventfd_signal() also, adds to the "count" counter and |
29 | * issue a wakeup. | 31 | * issue a wakeup. |
30 | */ | 32 | */ |
31 | __u64 count; | 33 | __u64 count; |
32 | unsigned int flags; | 34 | unsigned int flags; |
33 | }; | 35 | }; |
34 | 36 | ||
35 | /* | 37 | /** |
36 | * Adds "n" to the eventfd counter "count". Returns "n" in case of | 38 | * eventfd_signal - Adds @n to the eventfd counter. |
37 | * success, or a value lower then "n" in case of coutner overflow. | 39 | * @ctx: [in] Pointer to the eventfd context. |
38 | * This function is supposed to be called by the kernel in paths | 40 | * @n: [in] Value of the counter to be added to the eventfd internal counter. |
39 | * that do not allow sleeping. In this function we allow the counter | 41 | * The value cannot be negative. |
40 | * to reach the ULLONG_MAX value, and we signal this as overflow | 42 | * |
41 | * condition by returining a POLLERR to poll(2). | 43 | * This function is supposed to be called by the kernel in paths that do not |
44 | * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX | ||
45 | * value, and we signal this as overflow condition by returining a POLLERR | ||
46 | * to poll(2). | ||
47 | * | ||
48 | * Returns @n in case of success, a non-negative number lower than @n in case | ||
49 | * of overflow, or the following error codes: | ||
50 | * | ||
51 | * -EINVAL : The value of @n is negative. | ||
42 | */ | 52 | */ |
43 | int eventfd_signal(struct file *file, int n) | 53 | int eventfd_signal(struct eventfd_ctx *ctx, int n) |
44 | { | 54 | { |
45 | struct eventfd_ctx *ctx = file->private_data; | ||
46 | unsigned long flags; | 55 | unsigned long flags; |
47 | 56 | ||
48 | if (n < 0) | 57 | if (n < 0) |
@@ -59,9 +68,45 @@ int eventfd_signal(struct file *file, int n) | |||
59 | } | 68 | } |
60 | EXPORT_SYMBOL_GPL(eventfd_signal); | 69 | EXPORT_SYMBOL_GPL(eventfd_signal); |
61 | 70 | ||
71 | static void eventfd_free(struct kref *kref) | ||
72 | { | ||
73 | struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref); | ||
74 | |||
75 | kfree(ctx); | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * eventfd_ctx_get - Acquires a reference to the internal eventfd context. | ||
80 | * @ctx: [in] Pointer to the eventfd context. | ||
81 | * | ||
82 | * Returns: In case of success, returns a pointer to the eventfd context. | ||
83 | */ | ||
84 | struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx) | ||
85 | { | ||
86 | kref_get(&ctx->kref); | ||
87 | return ctx; | ||
88 | } | ||
89 | EXPORT_SYMBOL_GPL(eventfd_ctx_get); | ||
90 | |||
91 | /** | ||
92 | * eventfd_ctx_put - Releases a reference to the internal eventfd context. | ||
93 | * @ctx: [in] Pointer to eventfd context. | ||
94 | * | ||
95 | * The eventfd context reference must have been previously acquired either | ||
96 | * with eventfd_ctx_get() or eventfd_ctx_fdget()). | ||
97 | */ | ||
98 | void eventfd_ctx_put(struct eventfd_ctx *ctx) | ||
99 | { | ||
100 | kref_put(&ctx->kref, eventfd_free); | ||
101 | } | ||
102 | EXPORT_SYMBOL_GPL(eventfd_ctx_put); | ||
103 | |||
62 | static int eventfd_release(struct inode *inode, struct file *file) | 104 | static int eventfd_release(struct inode *inode, struct file *file) |
63 | { | 105 | { |
64 | kfree(file->private_data); | 106 | struct eventfd_ctx *ctx = file->private_data; |
107 | |||
108 | wake_up_poll(&ctx->wqh, POLLHUP); | ||
109 | eventfd_ctx_put(ctx); | ||
65 | return 0; | 110 | return 0; |
66 | } | 111 | } |
67 | 112 | ||
@@ -185,6 +230,16 @@ static const struct file_operations eventfd_fops = { | |||
185 | .write = eventfd_write, | 230 | .write = eventfd_write, |
186 | }; | 231 | }; |
187 | 232 | ||
233 | /** | ||
234 | * eventfd_fget - Acquire a reference of an eventfd file descriptor. | ||
235 | * @fd: [in] Eventfd file descriptor. | ||
236 | * | ||
237 | * Returns a pointer to the eventfd file structure in case of success, or the | ||
238 | * following error pointer: | ||
239 | * | ||
240 | * -EBADF : Invalid @fd file descriptor. | ||
241 | * -EINVAL : The @fd file descriptor is not an eventfd file. | ||
242 | */ | ||
188 | struct file *eventfd_fget(int fd) | 243 | struct file *eventfd_fget(int fd) |
189 | { | 244 | { |
190 | struct file *file; | 245 | struct file *file; |
@@ -201,6 +256,48 @@ struct file *eventfd_fget(int fd) | |||
201 | } | 256 | } |
202 | EXPORT_SYMBOL_GPL(eventfd_fget); | 257 | EXPORT_SYMBOL_GPL(eventfd_fget); |
203 | 258 | ||
259 | /** | ||
260 | * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context. | ||
261 | * @fd: [in] Eventfd file descriptor. | ||
262 | * | ||
263 | * Returns a pointer to the internal eventfd context, otherwise the error | ||
264 | * pointers returned by the following functions: | ||
265 | * | ||
266 | * eventfd_fget | ||
267 | */ | ||
268 | struct eventfd_ctx *eventfd_ctx_fdget(int fd) | ||
269 | { | ||
270 | struct file *file; | ||
271 | struct eventfd_ctx *ctx; | ||
272 | |||
273 | file = eventfd_fget(fd); | ||
274 | if (IS_ERR(file)) | ||
275 | return (struct eventfd_ctx *) file; | ||
276 | ctx = eventfd_ctx_get(file->private_data); | ||
277 | fput(file); | ||
278 | |||
279 | return ctx; | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); | ||
282 | |||
283 | /** | ||
284 | * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context. | ||
285 | * @file: [in] Eventfd file pointer. | ||
286 | * | ||
287 | * Returns a pointer to the internal eventfd context, otherwise the error | ||
288 | * pointer: | ||
289 | * | ||
290 | * -EINVAL : The @fd file descriptor is not an eventfd file. | ||
291 | */ | ||
292 | struct eventfd_ctx *eventfd_ctx_fileget(struct file *file) | ||
293 | { | ||
294 | if (file->f_op != &eventfd_fops) | ||
295 | return ERR_PTR(-EINVAL); | ||
296 | |||
297 | return eventfd_ctx_get(file->private_data); | ||
298 | } | ||
299 | EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); | ||
300 | |||
204 | SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) | 301 | SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) |
205 | { | 302 | { |
206 | int fd; | 303 | int fd; |
@@ -217,6 +314,7 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) | |||
217 | if (!ctx) | 314 | if (!ctx) |
218 | return -ENOMEM; | 315 | return -ENOMEM; |
219 | 316 | ||
317 | kref_init(&ctx->kref); | ||
220 | init_waitqueue_head(&ctx->wqh); | 318 | init_waitqueue_head(&ctx->wqh); |
221 | ctx->count = count; | 319 | ctx->count = count; |
222 | ctx->flags = flags; | 320 | ctx->flags = flags; |
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 5458e80fc558..085c5c063420 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c | |||
@@ -98,7 +98,7 @@ struct epoll_filefd { | |||
98 | struct nested_call_node { | 98 | struct nested_call_node { |
99 | struct list_head llink; | 99 | struct list_head llink; |
100 | void *cookie; | 100 | void *cookie; |
101 | int cpu; | 101 | void *ctx; |
102 | }; | 102 | }; |
103 | 103 | ||
104 | /* | 104 | /* |
@@ -317,17 +317,17 @@ static void ep_nested_calls_init(struct nested_calls *ncalls) | |||
317 | * @nproc: Nested call core function pointer. | 317 | * @nproc: Nested call core function pointer. |
318 | * @priv: Opaque data to be passed to the @nproc callback. | 318 | * @priv: Opaque data to be passed to the @nproc callback. |
319 | * @cookie: Cookie to be used to identify this nested call. | 319 | * @cookie: Cookie to be used to identify this nested call. |
320 | * @ctx: This instance context. | ||
320 | * | 321 | * |
321 | * Returns: Returns the code returned by the @nproc callback, or -1 if | 322 | * Returns: Returns the code returned by the @nproc callback, or -1 if |
322 | * the maximum recursion limit has been exceeded. | 323 | * the maximum recursion limit has been exceeded. |
323 | */ | 324 | */ |
324 | static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | 325 | static int ep_call_nested(struct nested_calls *ncalls, int max_nests, |
325 | int (*nproc)(void *, void *, int), void *priv, | 326 | int (*nproc)(void *, void *, int), void *priv, |
326 | void *cookie) | 327 | void *cookie, void *ctx) |
327 | { | 328 | { |
328 | int error, call_nests = 0; | 329 | int error, call_nests = 0; |
329 | unsigned long flags; | 330 | unsigned long flags; |
330 | int this_cpu = get_cpu(); | ||
331 | struct list_head *lsthead = &ncalls->tasks_call_list; | 331 | struct list_head *lsthead = &ncalls->tasks_call_list; |
332 | struct nested_call_node *tncur; | 332 | struct nested_call_node *tncur; |
333 | struct nested_call_node tnode; | 333 | struct nested_call_node tnode; |
@@ -340,7 +340,7 @@ static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | |||
340 | * very much limited. | 340 | * very much limited. |
341 | */ | 341 | */ |
342 | list_for_each_entry(tncur, lsthead, llink) { | 342 | list_for_each_entry(tncur, lsthead, llink) { |
343 | if (tncur->cpu == this_cpu && | 343 | if (tncur->ctx == ctx && |
344 | (tncur->cookie == cookie || ++call_nests > max_nests)) { | 344 | (tncur->cookie == cookie || ++call_nests > max_nests)) { |
345 | /* | 345 | /* |
346 | * Ops ... loop detected or maximum nest level reached. | 346 | * Ops ... loop detected or maximum nest level reached. |
@@ -352,7 +352,7 @@ static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | |||
352 | } | 352 | } |
353 | 353 | ||
354 | /* Add the current task and cookie to the list */ | 354 | /* Add the current task and cookie to the list */ |
355 | tnode.cpu = this_cpu; | 355 | tnode.ctx = ctx; |
356 | tnode.cookie = cookie; | 356 | tnode.cookie = cookie; |
357 | list_add(&tnode.llink, lsthead); | 357 | list_add(&tnode.llink, lsthead); |
358 | 358 | ||
@@ -364,10 +364,9 @@ static int ep_call_nested(struct nested_calls *ncalls, int max_nests, | |||
364 | /* Remove the current task from the list */ | 364 | /* Remove the current task from the list */ |
365 | spin_lock_irqsave(&ncalls->lock, flags); | 365 | spin_lock_irqsave(&ncalls->lock, flags); |
366 | list_del(&tnode.llink); | 366 | list_del(&tnode.llink); |
367 | out_unlock: | 367 | out_unlock: |
368 | spin_unlock_irqrestore(&ncalls->lock, flags); | 368 | spin_unlock_irqrestore(&ncalls->lock, flags); |
369 | 369 | ||
370 | put_cpu(); | ||
371 | return error; | 370 | return error; |
372 | } | 371 | } |
373 | 372 | ||
@@ -408,8 +407,12 @@ static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests) | |||
408 | */ | 407 | */ |
409 | static void ep_poll_safewake(wait_queue_head_t *wq) | 408 | static void ep_poll_safewake(wait_queue_head_t *wq) |
410 | { | 409 | { |
410 | int this_cpu = get_cpu(); | ||
411 | |||
411 | ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS, | 412 | ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS, |
412 | ep_poll_wakeup_proc, NULL, wq); | 413 | ep_poll_wakeup_proc, NULL, wq, (void *) (long) this_cpu); |
414 | |||
415 | put_cpu(); | ||
413 | } | 416 | } |
414 | 417 | ||
415 | /* | 418 | /* |
@@ -663,7 +666,7 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) | |||
663 | * could re-enter here. | 666 | * could re-enter here. |
664 | */ | 667 | */ |
665 | pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, | 668 | pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, |
666 | ep_poll_readyevents_proc, ep, ep); | 669 | ep_poll_readyevents_proc, ep, ep, current); |
667 | 670 | ||
668 | return pollflags != -1 ? pollflags : 0; | 671 | return pollflags != -1 ? pollflags : 0; |
669 | } | 672 | } |
@@ -1277,8 +1277,8 @@ int do_execve(char * filename, | |||
1277 | if (!bprm) | 1277 | if (!bprm) |
1278 | goto out_files; | 1278 | goto out_files; |
1279 | 1279 | ||
1280 | retval = mutex_lock_interruptible(¤t->cred_guard_mutex); | 1280 | retval = -ERESTARTNOINTR; |
1281 | if (retval < 0) | 1281 | if (mutex_lock_interruptible(¤t->cred_guard_mutex)) |
1282 | goto out_free; | 1282 | goto out_free; |
1283 | current->in_execve = 1; | 1283 | current->in_execve = 1; |
1284 | 1284 | ||
diff --git a/fs/exofs/common.h b/fs/exofs/common.h index 24667eedc023..c6718e4817fe 100644 --- a/fs/exofs/common.h +++ b/fs/exofs/common.h | |||
@@ -2,9 +2,7 @@ | |||
2 | * common.h - Common definitions for both Kernel and user-mode utilities | 2 | * common.h - Common definitions for both Kernel and user-mode utilities |
3 | * | 3 | * |
4 | * Copyright (C) 2005, 2006 | 4 | * Copyright (C) 2005, 2006 |
5 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 5 | * Avishay Traeger (avishay@gmail.com) |
6 | * Copyright (C) 2005, 2006 | ||
7 | * International Business Machines | ||
8 | * Copyright (C) 2008, 2009 | 6 | * Copyright (C) 2008, 2009 |
9 | * Boaz Harrosh <bharrosh@panasas.com> | 7 | * Boaz Harrosh <bharrosh@panasas.com> |
10 | * | 8 | * |
diff --git a/fs/exofs/dir.c b/fs/exofs/dir.c index 65b0c8c776a1..4cfab1cc75c0 100644 --- a/fs/exofs/dir.c +++ b/fs/exofs/dir.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
diff --git a/fs/exofs/exofs.h b/fs/exofs/exofs.h index 0fd4c7859679..5ec72e020b22 100644 --- a/fs/exofs/exofs.h +++ b/fs/exofs/exofs.h | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
@@ -156,6 +154,9 @@ ino_t exofs_parent_ino(struct dentry *child); | |||
156 | int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *, | 154 | int exofs_set_link(struct inode *, struct exofs_dir_entry *, struct page *, |
157 | struct inode *); | 155 | struct inode *); |
158 | 156 | ||
157 | /* super.c */ | ||
158 | int exofs_sync_fs(struct super_block *sb, int wait); | ||
159 | |||
159 | /********************* | 160 | /********************* |
160 | * operation vectors * | 161 | * operation vectors * |
161 | *********************/ | 162 | *********************/ |
diff --git a/fs/exofs/file.c b/fs/exofs/file.c index 6ed7fe484752..839b9dc1e70f 100644 --- a/fs/exofs/file.c +++ b/fs/exofs/file.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
@@ -47,16 +45,23 @@ static int exofs_file_fsync(struct file *filp, struct dentry *dentry, | |||
47 | { | 45 | { |
48 | int ret; | 46 | int ret; |
49 | struct address_space *mapping = filp->f_mapping; | 47 | struct address_space *mapping = filp->f_mapping; |
48 | struct inode *inode = dentry->d_inode; | ||
49 | struct super_block *sb; | ||
50 | 50 | ||
51 | ret = filemap_write_and_wait(mapping); | 51 | ret = filemap_write_and_wait(mapping); |
52 | if (ret) | 52 | if (ret) |
53 | return ret; | 53 | return ret; |
54 | 54 | ||
55 | /*Note: file_fsync below also calles sync_blockdev, which is a no-op | 55 | /* sync the inode attributes */ |
56 | * for exofs, but other then that it does sync_inode and | 56 | ret = write_inode_now(inode, 1); |
57 | * sync_superblock which is what we need here. | 57 | |
58 | */ | 58 | /* This is a good place to write the sb */ |
59 | return file_fsync(filp, dentry, datasync); | 59 | /* TODO: Sechedule an sb-sync on create */ |
60 | sb = inode->i_sb; | ||
61 | if (sb->s_dirt) | ||
62 | exofs_sync_fs(sb, 1); | ||
63 | |||
64 | return ret; | ||
60 | } | 65 | } |
61 | 66 | ||
62 | static int exofs_flush(struct file *file, fl_owner_t id) | 67 | static int exofs_flush(struct file *file, fl_owner_t id) |
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 77d0a295eb1c..6c10f7476699 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
@@ -295,6 +293,9 @@ static int read_exec(struct page_collect *pcol, bool is_sync) | |||
295 | err: | 293 | err: |
296 | if (!is_sync) | 294 | if (!is_sync) |
297 | _unlock_pcol_pages(pcol, ret, READ); | 295 | _unlock_pcol_pages(pcol, ret, READ); |
296 | else /* Pages unlocked by caller in sync mode only free bio */ | ||
297 | pcol_free(pcol); | ||
298 | |||
298 | kfree(pcol_copy); | 299 | kfree(pcol_copy); |
299 | if (or) | 300 | if (or) |
300 | osd_end_request(or); | 301 | osd_end_request(or); |
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c index 77fdd765e76d..b7dd0c236863 100644 --- a/fs/exofs/namei.c +++ b/fs/exofs/namei.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
diff --git a/fs/exofs/osd.c b/fs/exofs/osd.c index b3d2ccb87aaa..4372542df284 100644 --- a/fs/exofs/osd.c +++ b/fs/exofs/osd.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 8216c5b77b53..5ab10c3bbebe 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
@@ -33,6 +31,7 @@ | |||
33 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
34 | */ | 32 | */ |
35 | 33 | ||
34 | #include <linux/smp_lock.h> | ||
36 | #include <linux/string.h> | 35 | #include <linux/string.h> |
37 | #include <linux/parser.h> | 36 | #include <linux/parser.h> |
38 | #include <linux/vfs.h> | 37 | #include <linux/vfs.h> |
@@ -200,7 +199,7 @@ static const struct export_operations exofs_export_ops; | |||
200 | /* | 199 | /* |
201 | * Write the superblock to the OSD | 200 | * Write the superblock to the OSD |
202 | */ | 201 | */ |
203 | static int exofs_sync_fs(struct super_block *sb, int wait) | 202 | int exofs_sync_fs(struct super_block *sb, int wait) |
204 | { | 203 | { |
205 | struct exofs_sb_info *sbi; | 204 | struct exofs_sb_info *sbi; |
206 | struct exofs_fscb *fscb; | 205 | struct exofs_fscb *fscb; |
diff --git a/fs/exofs/symlink.c b/fs/exofs/symlink.c index 36e2d7bc7f7b..4dd687c3e747 100644 --- a/fs/exofs/symlink.c +++ b/fs/exofs/symlink.c | |||
@@ -1,8 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2005, 2006 | 2 | * Copyright (C) 2005, 2006 |
3 | * Avishay Traeger (avishay@gmail.com) (avishay@il.ibm.com) | 3 | * Avishay Traeger (avishay@gmail.com) |
4 | * Copyright (C) 2005, 2006 | ||
5 | * International Business Machines | ||
6 | * Copyright (C) 2008, 2009 | 4 | * Copyright (C) 2008, 2009 |
7 | * Boaz Harrosh <bharrosh@panasas.com> | 5 | * Boaz Harrosh <bharrosh@panasas.com> |
8 | * | 6 | * |
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index d46e38cb85c5..d636e1297cad 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
@@ -125,37 +125,12 @@ fail: | |||
125 | return ERR_PTR(-EINVAL); | 125 | return ERR_PTR(-EINVAL); |
126 | } | 126 | } |
127 | 127 | ||
128 | static inline struct posix_acl * | ||
129 | ext2_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
130 | { | ||
131 | struct posix_acl *acl = EXT2_ACL_NOT_CACHED; | ||
132 | |||
133 | spin_lock(&inode->i_lock); | ||
134 | if (*i_acl != EXT2_ACL_NOT_CACHED) | ||
135 | acl = posix_acl_dup(*i_acl); | ||
136 | spin_unlock(&inode->i_lock); | ||
137 | |||
138 | return acl; | ||
139 | } | ||
140 | |||
141 | static inline void | ||
142 | ext2_iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
143 | struct posix_acl *acl) | ||
144 | { | ||
145 | spin_lock(&inode->i_lock); | ||
146 | if (*i_acl != EXT2_ACL_NOT_CACHED) | ||
147 | posix_acl_release(*i_acl); | ||
148 | *i_acl = posix_acl_dup(acl); | ||
149 | spin_unlock(&inode->i_lock); | ||
150 | } | ||
151 | |||
152 | /* | 128 | /* |
153 | * inode->i_mutex: don't care | 129 | * inode->i_mutex: don't care |
154 | */ | 130 | */ |
155 | static struct posix_acl * | 131 | static struct posix_acl * |
156 | ext2_get_acl(struct inode *inode, int type) | 132 | ext2_get_acl(struct inode *inode, int type) |
157 | { | 133 | { |
158 | struct ext2_inode_info *ei = EXT2_I(inode); | ||
159 | int name_index; | 134 | int name_index; |
160 | char *value = NULL; | 135 | char *value = NULL; |
161 | struct posix_acl *acl; | 136 | struct posix_acl *acl; |
@@ -164,23 +139,19 @@ ext2_get_acl(struct inode *inode, int type) | |||
164 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 139 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
165 | return NULL; | 140 | return NULL; |
166 | 141 | ||
167 | switch(type) { | 142 | acl = get_cached_acl(inode, type); |
168 | case ACL_TYPE_ACCESS: | 143 | if (acl != ACL_NOT_CACHED) |
169 | acl = ext2_iget_acl(inode, &ei->i_acl); | 144 | return acl; |
170 | if (acl != EXT2_ACL_NOT_CACHED) | 145 | |
171 | return acl; | 146 | switch (type) { |
172 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; | 147 | case ACL_TYPE_ACCESS: |
173 | break; | 148 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS; |
174 | 149 | break; | |
175 | case ACL_TYPE_DEFAULT: | 150 | case ACL_TYPE_DEFAULT: |
176 | acl = ext2_iget_acl(inode, &ei->i_default_acl); | 151 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; |
177 | if (acl != EXT2_ACL_NOT_CACHED) | 152 | break; |
178 | return acl; | 153 | default: |
179 | name_index = EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT; | 154 | BUG(); |
180 | break; | ||
181 | |||
182 | default: | ||
183 | return ERR_PTR(-EINVAL); | ||
184 | } | 155 | } |
185 | retval = ext2_xattr_get(inode, name_index, "", NULL, 0); | 156 | retval = ext2_xattr_get(inode, name_index, "", NULL, 0); |
186 | if (retval > 0) { | 157 | if (retval > 0) { |
@@ -197,17 +168,9 @@ ext2_get_acl(struct inode *inode, int type) | |||
197 | acl = ERR_PTR(retval); | 168 | acl = ERR_PTR(retval); |
198 | kfree(value); | 169 | kfree(value); |
199 | 170 | ||
200 | if (!IS_ERR(acl)) { | 171 | if (!IS_ERR(acl)) |
201 | switch(type) { | 172 | set_cached_acl(inode, type, acl); |
202 | case ACL_TYPE_ACCESS: | ||
203 | ext2_iset_acl(inode, &ei->i_acl, acl); | ||
204 | break; | ||
205 | 173 | ||
206 | case ACL_TYPE_DEFAULT: | ||
207 | ext2_iset_acl(inode, &ei->i_default_acl, acl); | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | return acl; | 174 | return acl; |
212 | } | 175 | } |
213 | 176 | ||
@@ -217,7 +180,6 @@ ext2_get_acl(struct inode *inode, int type) | |||
217 | static int | 180 | static int |
218 | ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 181 | ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) |
219 | { | 182 | { |
220 | struct ext2_inode_info *ei = EXT2_I(inode); | ||
221 | int name_index; | 183 | int name_index; |
222 | void *value = NULL; | 184 | void *value = NULL; |
223 | size_t size = 0; | 185 | size_t size = 0; |
@@ -263,17 +225,8 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
263 | error = ext2_xattr_set(inode, name_index, "", value, size, 0); | 225 | error = ext2_xattr_set(inode, name_index, "", value, size, 0); |
264 | 226 | ||
265 | kfree(value); | 227 | kfree(value); |
266 | if (!error) { | 228 | if (!error) |
267 | switch(type) { | 229 | set_cached_acl(inode, type, acl); |
268 | case ACL_TYPE_ACCESS: | ||
269 | ext2_iset_acl(inode, &ei->i_acl, acl); | ||
270 | break; | ||
271 | |||
272 | case ACL_TYPE_DEFAULT: | ||
273 | ext2_iset_acl(inode, &ei->i_default_acl, acl); | ||
274 | break; | ||
275 | } | ||
276 | } | ||
277 | return error; | 230 | return error; |
278 | } | 231 | } |
279 | 232 | ||
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index b42cf578554b..ecefe478898f 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h | |||
@@ -53,10 +53,6 @@ static inline int ext2_acl_count(size_t size) | |||
53 | 53 | ||
54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL |
55 | 55 | ||
56 | /* Value for inode->u.ext2_i.i_acl and inode->u.ext2_i.i_default_acl | ||
57 | if the ACL has not been cached */ | ||
58 | #define EXT2_ACL_NOT_CACHED ((void *)-1) | ||
59 | |||
60 | /* acl.c */ | 56 | /* acl.c */ |
61 | extern int ext2_permission (struct inode *, int); | 57 | extern int ext2_permission (struct inode *, int); |
62 | extern int ext2_acl_chmod (struct inode *); | 58 | extern int ext2_acl_chmod (struct inode *); |
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 003500498c22..6cde970b0a1a 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
@@ -450,7 +450,7 @@ ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child) | |||
450 | 450 | ||
451 | /* Releases the page */ | 451 | /* Releases the page */ |
452 | void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, | 452 | void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, |
453 | struct page *page, struct inode *inode) | 453 | struct page *page, struct inode *inode, int update_times) |
454 | { | 454 | { |
455 | loff_t pos = page_offset(page) + | 455 | loff_t pos = page_offset(page) + |
456 | (char *) de - (char *) page_address(page); | 456 | (char *) de - (char *) page_address(page); |
@@ -465,7 +465,8 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, | |||
465 | ext2_set_de_type(de, inode); | 465 | ext2_set_de_type(de, inode); |
466 | err = ext2_commit_chunk(page, pos, len); | 466 | err = ext2_commit_chunk(page, pos, len); |
467 | ext2_put_page(page); | 467 | ext2_put_page(page); |
468 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 468 | if (update_times) |
469 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | ||
469 | EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; | 470 | EXT2_I(dir)->i_flags &= ~EXT2_BTREE_FL; |
470 | mark_inode_dirty(dir); | 471 | mark_inode_dirty(dir); |
471 | } | 472 | } |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index b2bbf45039e0..9a8a8e27a063 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -27,7 +27,7 @@ struct ext2_inode_info { | |||
27 | /* | 27 | /* |
28 | * i_block_group is the number of the block group which contains | 28 | * i_block_group is the number of the block group which contains |
29 | * this file's inode. Constant across the lifetime of the inode, | 29 | * this file's inode. Constant across the lifetime of the inode, |
30 | * it is ued for making block allocation decisions - we try to | 30 | * it is used for making block allocation decisions - we try to |
31 | * place a file's data blocks near its inode block, and new inodes | 31 | * place a file's data blocks near its inode block, and new inodes |
32 | * near to their parent directory's inode. | 32 | * near to their parent directory's inode. |
33 | */ | 33 | */ |
@@ -47,10 +47,6 @@ struct ext2_inode_info { | |||
47 | */ | 47 | */ |
48 | struct rw_semaphore xattr_sem; | 48 | struct rw_semaphore xattr_sem; |
49 | #endif | 49 | #endif |
50 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
51 | struct posix_acl *i_acl; | ||
52 | struct posix_acl *i_default_acl; | ||
53 | #endif | ||
54 | rwlock_t i_meta_lock; | 50 | rwlock_t i_meta_lock; |
55 | 51 | ||
56 | /* | 52 | /* |
@@ -111,7 +107,7 @@ extern struct ext2_dir_entry_2 * ext2_find_entry (struct inode *,struct qstr *, | |||
111 | extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); | 107 | extern int ext2_delete_entry (struct ext2_dir_entry_2 *, struct page *); |
112 | extern int ext2_empty_dir (struct inode *); | 108 | extern int ext2_empty_dir (struct inode *); |
113 | extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); | 109 | extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); |
114 | extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *); | 110 | extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *, int); |
115 | 111 | ||
116 | /* ialloc.c */ | 112 | /* ialloc.c */ |
117 | extern struct inode * ext2_new_inode (struct inode *, int); | 113 | extern struct inode * ext2_new_inode (struct inode *, int); |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 29ed682061f6..e27130341d4f 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
@@ -1224,10 +1224,6 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) | |||
1224 | return inode; | 1224 | return inode; |
1225 | 1225 | ||
1226 | ei = EXT2_I(inode); | 1226 | ei = EXT2_I(inode); |
1227 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
1228 | ei->i_acl = EXT2_ACL_NOT_CACHED; | ||
1229 | ei->i_default_acl = EXT2_ACL_NOT_CACHED; | ||
1230 | #endif | ||
1231 | ei->i_block_alloc_info = NULL; | 1227 | ei->i_block_alloc_info = NULL; |
1232 | 1228 | ||
1233 | raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); | 1229 | raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); |
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 7cb4badef927..e7431309bdca 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/compat.h> | 14 | #include <linux/compat.h> |
15 | #include <linux/mount.h> | 15 | #include <linux/mount.h> |
16 | #include <linux/smp_lock.h> | ||
17 | #include <asm/current.h> | 16 | #include <asm/current.h> |
18 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
19 | 18 | ||
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 90ea17998a73..e1dedb0f7873 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c | |||
@@ -66,8 +66,16 @@ static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, str | |||
66 | inode = NULL; | 66 | inode = NULL; |
67 | if (ino) { | 67 | if (ino) { |
68 | inode = ext2_iget(dir->i_sb, ino); | 68 | inode = ext2_iget(dir->i_sb, ino); |
69 | if (IS_ERR(inode)) | 69 | if (unlikely(IS_ERR(inode))) { |
70 | return ERR_CAST(inode); | 70 | if (PTR_ERR(inode) == -ESTALE) { |
71 | ext2_error(dir->i_sb, __func__, | ||
72 | "deleted inode referenced: %lu", | ||
73 | ino); | ||
74 | return ERR_PTR(-EIO); | ||
75 | } else { | ||
76 | return ERR_CAST(inode); | ||
77 | } | ||
78 | } | ||
71 | } | 79 | } |
72 | return d_splice_alias(inode, dentry); | 80 | return d_splice_alias(inode, dentry); |
73 | } | 81 | } |
@@ -320,7 +328,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, | |||
320 | if (!new_de) | 328 | if (!new_de) |
321 | goto out_dir; | 329 | goto out_dir; |
322 | inode_inc_link_count(old_inode); | 330 | inode_inc_link_count(old_inode); |
323 | ext2_set_link(new_dir, new_de, new_page, old_inode); | 331 | ext2_set_link(new_dir, new_de, new_page, old_inode, 1); |
324 | new_inode->i_ctime = CURRENT_TIME_SEC; | 332 | new_inode->i_ctime = CURRENT_TIME_SEC; |
325 | if (dir_de) | 333 | if (dir_de) |
326 | drop_nlink(new_inode); | 334 | drop_nlink(new_inode); |
@@ -352,7 +360,8 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, | |||
352 | inode_dec_link_count(old_inode); | 360 | inode_dec_link_count(old_inode); |
353 | 361 | ||
354 | if (dir_de) { | 362 | if (dir_de) { |
355 | ext2_set_link(old_inode, dir_de, dir_page, new_dir); | 363 | if (old_dir != new_dir) |
364 | ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); | ||
356 | inode_dec_link_count(old_dir); | 365 | inode_dec_link_count(old_dir); |
357 | } | 366 | } |
358 | return 0; | 367 | return 0; |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 458999638c3d..1a9ffee47d56 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -152,10 +152,6 @@ static struct inode *ext2_alloc_inode(struct super_block *sb) | |||
152 | ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); | 152 | ei = (struct ext2_inode_info *)kmem_cache_alloc(ext2_inode_cachep, GFP_KERNEL); |
153 | if (!ei) | 153 | if (!ei) |
154 | return NULL; | 154 | return NULL; |
155 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
156 | ei->i_acl = EXT2_ACL_NOT_CACHED; | ||
157 | ei->i_default_acl = EXT2_ACL_NOT_CACHED; | ||
158 | #endif | ||
159 | ei->i_block_alloc_info = NULL; | 155 | ei->i_block_alloc_info = NULL; |
160 | ei->vfs_inode.i_version = 1; | 156 | ei->vfs_inode.i_version = 1; |
161 | return &ei->vfs_inode; | 157 | return &ei->vfs_inode; |
@@ -198,18 +194,6 @@ static void destroy_inodecache(void) | |||
198 | static void ext2_clear_inode(struct inode *inode) | 194 | static void ext2_clear_inode(struct inode *inode) |
199 | { | 195 | { |
200 | struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info; | 196 | struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info; |
201 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | ||
202 | struct ext2_inode_info *ei = EXT2_I(inode); | ||
203 | |||
204 | if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) { | ||
205 | posix_acl_release(ei->i_acl); | ||
206 | ei->i_acl = EXT2_ACL_NOT_CACHED; | ||
207 | } | ||
208 | if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) { | ||
209 | posix_acl_release(ei->i_default_acl); | ||
210 | ei->i_default_acl = EXT2_ACL_NOT_CACHED; | ||
211 | } | ||
212 | #endif | ||
213 | ext2_discard_reservation(inode); | 197 | ext2_discard_reservation(inode); |
214 | EXT2_I(inode)->i_block_alloc_info = NULL; | 198 | EXT2_I(inode)->i_block_alloc_info = NULL; |
215 | if (unlikely(rsv)) | 199 | if (unlikely(rsv)) |
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index d81ef2fdb08e..e167bae37ef0 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
@@ -126,30 +126,6 @@ fail: | |||
126 | return ERR_PTR(-EINVAL); | 126 | return ERR_PTR(-EINVAL); |
127 | } | 127 | } |
128 | 128 | ||
129 | static inline struct posix_acl * | ||
130 | ext3_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
131 | { | ||
132 | struct posix_acl *acl = EXT3_ACL_NOT_CACHED; | ||
133 | |||
134 | spin_lock(&inode->i_lock); | ||
135 | if (*i_acl != EXT3_ACL_NOT_CACHED) | ||
136 | acl = posix_acl_dup(*i_acl); | ||
137 | spin_unlock(&inode->i_lock); | ||
138 | |||
139 | return acl; | ||
140 | } | ||
141 | |||
142 | static inline void | ||
143 | ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
144 | struct posix_acl *acl) | ||
145 | { | ||
146 | spin_lock(&inode->i_lock); | ||
147 | if (*i_acl != EXT3_ACL_NOT_CACHED) | ||
148 | posix_acl_release(*i_acl); | ||
149 | *i_acl = posix_acl_dup(acl); | ||
150 | spin_unlock(&inode->i_lock); | ||
151 | } | ||
152 | |||
153 | /* | 129 | /* |
154 | * Inode operation get_posix_acl(). | 130 | * Inode operation get_posix_acl(). |
155 | * | 131 | * |
@@ -158,7 +134,6 @@ ext3_iset_acl(struct inode *inode, struct posix_acl **i_acl, | |||
158 | static struct posix_acl * | 134 | static struct posix_acl * |
159 | ext3_get_acl(struct inode *inode, int type) | 135 | ext3_get_acl(struct inode *inode, int type) |
160 | { | 136 | { |
161 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
162 | int name_index; | 137 | int name_index; |
163 | char *value = NULL; | 138 | char *value = NULL; |
164 | struct posix_acl *acl; | 139 | struct posix_acl *acl; |
@@ -167,24 +142,21 @@ ext3_get_acl(struct inode *inode, int type) | |||
167 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 142 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
168 | return NULL; | 143 | return NULL; |
169 | 144 | ||
170 | switch(type) { | 145 | acl = get_cached_acl(inode, type); |
171 | case ACL_TYPE_ACCESS: | 146 | if (acl != ACL_NOT_CACHED) |
172 | acl = ext3_iget_acl(inode, &ei->i_acl); | 147 | return acl; |
173 | if (acl != EXT3_ACL_NOT_CACHED) | 148 | |
174 | return acl; | 149 | switch (type) { |
175 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; | 150 | case ACL_TYPE_ACCESS: |
176 | break; | 151 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; |
177 | 152 | break; | |
178 | case ACL_TYPE_DEFAULT: | 153 | case ACL_TYPE_DEFAULT: |
179 | acl = ext3_iget_acl(inode, &ei->i_default_acl); | 154 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; |
180 | if (acl != EXT3_ACL_NOT_CACHED) | 155 | break; |
181 | return acl; | 156 | default: |
182 | name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; | 157 | BUG(); |
183 | break; | ||
184 | |||
185 | default: | ||
186 | return ERR_PTR(-EINVAL); | ||
187 | } | 158 | } |
159 | |||
188 | retval = ext3_xattr_get(inode, name_index, "", NULL, 0); | 160 | retval = ext3_xattr_get(inode, name_index, "", NULL, 0); |
189 | if (retval > 0) { | 161 | if (retval > 0) { |
190 | value = kmalloc(retval, GFP_NOFS); | 162 | value = kmalloc(retval, GFP_NOFS); |
@@ -200,17 +172,9 @@ ext3_get_acl(struct inode *inode, int type) | |||
200 | acl = ERR_PTR(retval); | 172 | acl = ERR_PTR(retval); |
201 | kfree(value); | 173 | kfree(value); |
202 | 174 | ||
203 | if (!IS_ERR(acl)) { | 175 | if (!IS_ERR(acl)) |
204 | switch(type) { | 176 | set_cached_acl(inode, type, acl); |
205 | case ACL_TYPE_ACCESS: | ||
206 | ext3_iset_acl(inode, &ei->i_acl, acl); | ||
207 | break; | ||
208 | 177 | ||
209 | case ACL_TYPE_DEFAULT: | ||
210 | ext3_iset_acl(inode, &ei->i_default_acl, acl); | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | return acl; | 178 | return acl; |
215 | } | 179 | } |
216 | 180 | ||
@@ -223,7 +187,6 @@ static int | |||
223 | ext3_set_acl(handle_t *handle, struct inode *inode, int type, | 187 | ext3_set_acl(handle_t *handle, struct inode *inode, int type, |
224 | struct posix_acl *acl) | 188 | struct posix_acl *acl) |
225 | { | 189 | { |
226 | struct ext3_inode_info *ei = EXT3_I(inode); | ||
227 | int name_index; | 190 | int name_index; |
228 | void *value = NULL; | 191 | void *value = NULL; |
229 | size_t size = 0; | 192 | size_t size = 0; |
@@ -268,17 +231,10 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, | |||
268 | value, size, 0); | 231 | value, size, 0); |
269 | 232 | ||
270 | kfree(value); | 233 | kfree(value); |
271 | if (!error) { | ||
272 | switch(type) { | ||
273 | case ACL_TYPE_ACCESS: | ||
274 | ext3_iset_acl(inode, &ei->i_acl, acl); | ||
275 | break; | ||
276 | 234 | ||
277 | case ACL_TYPE_DEFAULT: | 235 | if (!error) |
278 | ext3_iset_acl(inode, &ei->i_default_acl, acl); | 236 | set_cached_acl(inode, type, acl); |
279 | break; | 237 | |
280 | } | ||
281 | } | ||
282 | return error; | 238 | return error; |
283 | } | 239 | } |
284 | 240 | ||
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 42da16b8cac0..07d15a3a5969 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h | |||
@@ -53,10 +53,6 @@ static inline int ext3_acl_count(size_t size) | |||
53 | 53 | ||
54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL |
55 | 55 | ||
56 | /* Value for inode->u.ext3_i.i_acl and inode->u.ext3_i.i_default_acl | ||
57 | if the ACL has not been cached */ | ||
58 | #define EXT3_ACL_NOT_CACHED ((void *)-1) | ||
59 | |||
60 | /* acl.c */ | 56 | /* acl.c */ |
61 | extern int ext3_permission (struct inode *, int); | 57 | extern int ext3_permission (struct inode *, int); |
62 | extern int ext3_acl_chmod (struct inode *); | 58 | extern int ext3_acl_chmod (struct inode *); |
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 3d724a95882f..373fa90c796a 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c | |||
@@ -130,8 +130,7 @@ static int ext3_readdir(struct file * filp, | |||
130 | struct buffer_head *bh = NULL; | 130 | struct buffer_head *bh = NULL; |
131 | 131 | ||
132 | map_bh.b_state = 0; | 132 | map_bh.b_state = 0; |
133 | err = ext3_get_blocks_handle(NULL, inode, blk, 1, | 133 | err = ext3_get_blocks_handle(NULL, inode, blk, 1, &map_bh, 0); |
134 | &map_bh, 0, 0); | ||
135 | if (err > 0) { | 134 | if (err > 0) { |
136 | pgoff_t index = map_bh.b_blocknr >> | 135 | pgoff_t index = map_bh.b_blocknr >> |
137 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | 136 | (PAGE_CACHE_SHIFT - inode->i_blkbits); |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b0248c6d5d4c..b49908a167ae 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -788,7 +788,7 @@ err_out: | |||
788 | int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, | 788 | int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, |
789 | sector_t iblock, unsigned long maxblocks, | 789 | sector_t iblock, unsigned long maxblocks, |
790 | struct buffer_head *bh_result, | 790 | struct buffer_head *bh_result, |
791 | int create, int extend_disksize) | 791 | int create) |
792 | { | 792 | { |
793 | int err = -EIO; | 793 | int err = -EIO; |
794 | int offsets[4]; | 794 | int offsets[4]; |
@@ -820,7 +820,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, | |||
820 | while (count < maxblocks && count <= blocks_to_boundary) { | 820 | while (count < maxblocks && count <= blocks_to_boundary) { |
821 | ext3_fsblk_t blk; | 821 | ext3_fsblk_t blk; |
822 | 822 | ||
823 | if (!verify_chain(chain, partial)) { | 823 | if (!verify_chain(chain, chain + depth - 1)) { |
824 | /* | 824 | /* |
825 | * Indirect block might be removed by | 825 | * Indirect block might be removed by |
826 | * truncate while we were reading it. | 826 | * truncate while we were reading it. |
@@ -911,13 +911,6 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, | |||
911 | if (!err) | 911 | if (!err) |
912 | err = ext3_splice_branch(handle, inode, iblock, | 912 | err = ext3_splice_branch(handle, inode, iblock, |
913 | partial, indirect_blks, count); | 913 | partial, indirect_blks, count); |
914 | /* | ||
915 | * i_disksize growing is protected by truncate_mutex. Don't forget to | ||
916 | * protect it if you're about to implement concurrent | ||
917 | * ext3_get_block() -bzzz | ||
918 | */ | ||
919 | if (!err && extend_disksize && inode->i_size > ei->i_disksize) | ||
920 | ei->i_disksize = inode->i_size; | ||
921 | mutex_unlock(&ei->truncate_mutex); | 914 | mutex_unlock(&ei->truncate_mutex); |
922 | if (err) | 915 | if (err) |
923 | goto cleanup; | 916 | goto cleanup; |
@@ -972,7 +965,7 @@ static int ext3_get_block(struct inode *inode, sector_t iblock, | |||
972 | } | 965 | } |
973 | 966 | ||
974 | ret = ext3_get_blocks_handle(handle, inode, iblock, | 967 | ret = ext3_get_blocks_handle(handle, inode, iblock, |
975 | max_blocks, bh_result, create, 0); | 968 | max_blocks, bh_result, create); |
976 | if (ret > 0) { | 969 | if (ret > 0) { |
977 | bh_result->b_size = (ret << inode->i_blkbits); | 970 | bh_result->b_size = (ret << inode->i_blkbits); |
978 | ret = 0; | 971 | ret = 0; |
@@ -1005,7 +998,7 @@ struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, | |||
1005 | dummy.b_blocknr = -1000; | 998 | dummy.b_blocknr = -1000; |
1006 | buffer_trace_init(&dummy.b_history); | 999 | buffer_trace_init(&dummy.b_history); |
1007 | err = ext3_get_blocks_handle(handle, inode, block, 1, | 1000 | err = ext3_get_blocks_handle(handle, inode, block, 1, |
1008 | &dummy, create, 1); | 1001 | &dummy, create); |
1009 | /* | 1002 | /* |
1010 | * ext3_get_blocks_handle() returns number of blocks | 1003 | * ext3_get_blocks_handle() returns number of blocks |
1011 | * mapped. 0 in case of a HOLE. | 1004 | * mapped. 0 in case of a HOLE. |
@@ -1193,15 +1186,16 @@ write_begin_failed: | |||
1193 | * i_size_read because we hold i_mutex. | 1186 | * i_size_read because we hold i_mutex. |
1194 | * | 1187 | * |
1195 | * Add inode to orphan list in case we crash before truncate | 1188 | * Add inode to orphan list in case we crash before truncate |
1196 | * finishes. | 1189 | * finishes. Do this only if ext3_can_truncate() agrees so |
1190 | * that orphan processing code is happy. | ||
1197 | */ | 1191 | */ |
1198 | if (pos + len > inode->i_size) | 1192 | if (pos + len > inode->i_size && ext3_can_truncate(inode)) |
1199 | ext3_orphan_add(handle, inode); | 1193 | ext3_orphan_add(handle, inode); |
1200 | ext3_journal_stop(handle); | 1194 | ext3_journal_stop(handle); |
1201 | unlock_page(page); | 1195 | unlock_page(page); |
1202 | page_cache_release(page); | 1196 | page_cache_release(page); |
1203 | if (pos + len > inode->i_size) | 1197 | if (pos + len > inode->i_size) |
1204 | vmtruncate(inode, inode->i_size); | 1198 | ext3_truncate(inode); |
1205 | } | 1199 | } |
1206 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) | 1200 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) |
1207 | goto retry; | 1201 | goto retry; |
@@ -1287,7 +1281,7 @@ static int ext3_ordered_write_end(struct file *file, | |||
1287 | * There may be allocated blocks outside of i_size because | 1281 | * There may be allocated blocks outside of i_size because |
1288 | * we failed to copy some data. Prepare for truncate. | 1282 | * we failed to copy some data. Prepare for truncate. |
1289 | */ | 1283 | */ |
1290 | if (pos + len > inode->i_size) | 1284 | if (pos + len > inode->i_size && ext3_can_truncate(inode)) |
1291 | ext3_orphan_add(handle, inode); | 1285 | ext3_orphan_add(handle, inode); |
1292 | ret2 = ext3_journal_stop(handle); | 1286 | ret2 = ext3_journal_stop(handle); |
1293 | if (!ret) | 1287 | if (!ret) |
@@ -1296,7 +1290,7 @@ static int ext3_ordered_write_end(struct file *file, | |||
1296 | page_cache_release(page); | 1290 | page_cache_release(page); |
1297 | 1291 | ||
1298 | if (pos + len > inode->i_size) | 1292 | if (pos + len > inode->i_size) |
1299 | vmtruncate(inode, inode->i_size); | 1293 | ext3_truncate(inode); |
1300 | return ret ? ret : copied; | 1294 | return ret ? ret : copied; |
1301 | } | 1295 | } |
1302 | 1296 | ||
@@ -1315,14 +1309,14 @@ static int ext3_writeback_write_end(struct file *file, | |||
1315 | * There may be allocated blocks outside of i_size because | 1309 | * There may be allocated blocks outside of i_size because |
1316 | * we failed to copy some data. Prepare for truncate. | 1310 | * we failed to copy some data. Prepare for truncate. |
1317 | */ | 1311 | */ |
1318 | if (pos + len > inode->i_size) | 1312 | if (pos + len > inode->i_size && ext3_can_truncate(inode)) |
1319 | ext3_orphan_add(handle, inode); | 1313 | ext3_orphan_add(handle, inode); |
1320 | ret = ext3_journal_stop(handle); | 1314 | ret = ext3_journal_stop(handle); |
1321 | unlock_page(page); | 1315 | unlock_page(page); |
1322 | page_cache_release(page); | 1316 | page_cache_release(page); |
1323 | 1317 | ||
1324 | if (pos + len > inode->i_size) | 1318 | if (pos + len > inode->i_size) |
1325 | vmtruncate(inode, inode->i_size); | 1319 | ext3_truncate(inode); |
1326 | return ret ? ret : copied; | 1320 | return ret ? ret : copied; |
1327 | } | 1321 | } |
1328 | 1322 | ||
@@ -1358,7 +1352,7 @@ static int ext3_journalled_write_end(struct file *file, | |||
1358 | * There may be allocated blocks outside of i_size because | 1352 | * There may be allocated blocks outside of i_size because |
1359 | * we failed to copy some data. Prepare for truncate. | 1353 | * we failed to copy some data. Prepare for truncate. |
1360 | */ | 1354 | */ |
1361 | if (pos + len > inode->i_size) | 1355 | if (pos + len > inode->i_size && ext3_can_truncate(inode)) |
1362 | ext3_orphan_add(handle, inode); | 1356 | ext3_orphan_add(handle, inode); |
1363 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; | 1357 | EXT3_I(inode)->i_state |= EXT3_STATE_JDATA; |
1364 | if (inode->i_size > EXT3_I(inode)->i_disksize) { | 1358 | if (inode->i_size > EXT3_I(inode)->i_disksize) { |
@@ -1375,7 +1369,7 @@ static int ext3_journalled_write_end(struct file *file, | |||
1375 | page_cache_release(page); | 1369 | page_cache_release(page); |
1376 | 1370 | ||
1377 | if (pos + len > inode->i_size) | 1371 | if (pos + len > inode->i_size) |
1378 | vmtruncate(inode, inode->i_size); | 1372 | ext3_truncate(inode); |
1379 | return ret ? ret : copied; | 1373 | return ret ? ret : copied; |
1380 | } | 1374 | } |
1381 | 1375 | ||
@@ -2374,7 +2368,7 @@ void ext3_truncate(struct inode *inode) | |||
2374 | struct page *page; | 2368 | struct page *page; |
2375 | 2369 | ||
2376 | if (!ext3_can_truncate(inode)) | 2370 | if (!ext3_can_truncate(inode)) |
2377 | return; | 2371 | goto out_notrans; |
2378 | 2372 | ||
2379 | if (inode->i_size == 0 && ext3_should_writeback_data(inode)) | 2373 | if (inode->i_size == 0 && ext3_should_writeback_data(inode)) |
2380 | ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE; | 2374 | ei->i_state |= EXT3_STATE_FLUSH_ON_CLOSE; |
@@ -2390,7 +2384,7 @@ void ext3_truncate(struct inode *inode) | |||
2390 | page = grab_cache_page(mapping, | 2384 | page = grab_cache_page(mapping, |
2391 | inode->i_size >> PAGE_CACHE_SHIFT); | 2385 | inode->i_size >> PAGE_CACHE_SHIFT); |
2392 | if (!page) | 2386 | if (!page) |
2393 | return; | 2387 | goto out_notrans; |
2394 | } | 2388 | } |
2395 | 2389 | ||
2396 | handle = start_transaction(inode); | 2390 | handle = start_transaction(inode); |
@@ -2401,7 +2395,7 @@ void ext3_truncate(struct inode *inode) | |||
2401 | unlock_page(page); | 2395 | unlock_page(page); |
2402 | page_cache_release(page); | 2396 | page_cache_release(page); |
2403 | } | 2397 | } |
2404 | return; /* AKPM: return what? */ | 2398 | goto out_notrans; |
2405 | } | 2399 | } |
2406 | 2400 | ||
2407 | last_block = (inode->i_size + blocksize-1) | 2401 | last_block = (inode->i_size + blocksize-1) |
@@ -2525,6 +2519,14 @@ out_stop: | |||
2525 | ext3_orphan_del(handle, inode); | 2519 | ext3_orphan_del(handle, inode); |
2526 | 2520 | ||
2527 | ext3_journal_stop(handle); | 2521 | ext3_journal_stop(handle); |
2522 | return; | ||
2523 | out_notrans: | ||
2524 | /* | ||
2525 | * Delete the inode from orphan list so that it doesn't stay there | ||
2526 | * forever and trigger assertion on umount. | ||
2527 | */ | ||
2528 | if (inode->i_nlink) | ||
2529 | ext3_orphan_del(NULL, inode); | ||
2528 | } | 2530 | } |
2529 | 2531 | ||
2530 | static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, | 2532 | static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, |
@@ -2744,10 +2746,6 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino) | |||
2744 | return inode; | 2746 | return inode; |
2745 | 2747 | ||
2746 | ei = EXT3_I(inode); | 2748 | ei = EXT3_I(inode); |
2747 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | ||
2748 | ei->i_acl = EXT3_ACL_NOT_CACHED; | ||
2749 | ei->i_default_acl = EXT3_ACL_NOT_CACHED; | ||
2750 | #endif | ||
2751 | ei->i_block_alloc_info = NULL; | 2749 | ei->i_block_alloc_info = NULL; |
2752 | 2750 | ||
2753 | ret = __ext3_get_inode_loc(inode, &iloc, 0); | 2751 | ret = __ext3_get_inode_loc(inode, &iloc, 0); |
@@ -3122,12 +3120,6 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) | |||
3122 | 3120 | ||
3123 | rc = inode_setattr(inode, attr); | 3121 | rc = inode_setattr(inode, attr); |
3124 | 3122 | ||
3125 | /* If inode_setattr's call to ext3_truncate failed to get a | ||
3126 | * transaction handle at all, we need to clean up the in-core | ||
3127 | * orphan list manually. */ | ||
3128 | if (inode->i_nlink) | ||
3129 | ext3_orphan_del(NULL, inode); | ||
3130 | |||
3131 | if (!rc && (ia_valid & ATTR_MODE)) | 3123 | if (!rc && (ia_valid & ATTR_MODE)) |
3132 | rc = ext3_acl_chmod(inode); | 3124 | rc = ext3_acl_chmod(inode); |
3133 | 3125 | ||
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 8a0b26340b54..8359e7b3dc89 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c | |||
@@ -990,7 +990,7 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, | |||
990 | sb->s_id, n_blocks_count); | 990 | sb->s_id, n_blocks_count); |
991 | if (sizeof(sector_t) < 8) | 991 | if (sizeof(sector_t) < 8) |
992 | ext3_warning(sb, __func__, | 992 | ext3_warning(sb, __func__, |
993 | "CONFIG_LBD not enabled\n"); | 993 | "CONFIG_LBDAF not enabled\n"); |
994 | return -EINVAL; | 994 | return -EINVAL; |
995 | } | 995 | } |
996 | 996 | ||
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 26aa64dee6aa..524b349c6299 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -464,10 +464,6 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) | |||
464 | ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS); | 464 | ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS); |
465 | if (!ei) | 465 | if (!ei) |
466 | return NULL; | 466 | return NULL; |
467 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | ||
468 | ei->i_acl = EXT3_ACL_NOT_CACHED; | ||
469 | ei->i_default_acl = EXT3_ACL_NOT_CACHED; | ||
470 | #endif | ||
471 | ei->i_block_alloc_info = NULL; | 467 | ei->i_block_alloc_info = NULL; |
472 | ei->vfs_inode.i_version = 1; | 468 | ei->vfs_inode.i_version = 1; |
473 | return &ei->vfs_inode; | 469 | return &ei->vfs_inode; |
@@ -518,18 +514,6 @@ static void destroy_inodecache(void) | |||
518 | static void ext3_clear_inode(struct inode *inode) | 514 | static void ext3_clear_inode(struct inode *inode) |
519 | { | 515 | { |
520 | struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; | 516 | struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; |
521 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | ||
522 | if (EXT3_I(inode)->i_acl && | ||
523 | EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) { | ||
524 | posix_acl_release(EXT3_I(inode)->i_acl); | ||
525 | EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED; | ||
526 | } | ||
527 | if (EXT3_I(inode)->i_default_acl && | ||
528 | EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) { | ||
529 | posix_acl_release(EXT3_I(inode)->i_default_acl); | ||
530 | EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED; | ||
531 | } | ||
532 | #endif | ||
533 | ext3_discard_reservation(inode); | 517 | ext3_discard_reservation(inode); |
534 | EXT3_I(inode)->i_block_alloc_info = NULL; | 518 | EXT3_I(inode)->i_block_alloc_info = NULL; |
535 | if (unlikely(rsv)) | 519 | if (unlikely(rsv)) |
@@ -1812,7 +1796,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
1812 | printk(KERN_ERR "EXT3-fs: filesystem on %s:" | 1796 | printk(KERN_ERR "EXT3-fs: filesystem on %s:" |
1813 | " too large to mount safely\n", sb->s_id); | 1797 | " too large to mount safely\n", sb->s_id); |
1814 | if (sizeof(sector_t) < 8) | 1798 | if (sizeof(sector_t) < 8) |
1815 | printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not " | 1799 | printk(KERN_WARNING "EXT3-fs: CONFIG_LBDAF not " |
1816 | "enabled\n"); | 1800 | "enabled\n"); |
1817 | goto failed_mount; | 1801 | goto failed_mount; |
1818 | } | 1802 | } |
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 8a34710ecf40..8867b2a1e5fe 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile | |||
@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o | |||
6 | 6 | ||
7 | ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ | 7 | ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ |
8 | ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ | 8 | ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ |
9 | ext4_jbd2.o migrate.o mballoc.o block_validity.o | 9 | ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o |
10 | 10 | ||
11 | ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o | 11 | ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o |
12 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o | 12 | ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o |
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 647e0d65a284..f6d8967149ca 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
@@ -126,30 +126,6 @@ fail: | |||
126 | return ERR_PTR(-EINVAL); | 126 | return ERR_PTR(-EINVAL); |
127 | } | 127 | } |
128 | 128 | ||
129 | static inline struct posix_acl * | ||
130 | ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
131 | { | ||
132 | struct posix_acl *acl = EXT4_ACL_NOT_CACHED; | ||
133 | |||
134 | spin_lock(&inode->i_lock); | ||
135 | if (*i_acl != EXT4_ACL_NOT_CACHED) | ||
136 | acl = posix_acl_dup(*i_acl); | ||
137 | spin_unlock(&inode->i_lock); | ||
138 | |||
139 | return acl; | ||
140 | } | ||
141 | |||
142 | static inline void | ||
143 | ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
144 | struct posix_acl *acl) | ||
145 | { | ||
146 | spin_lock(&inode->i_lock); | ||
147 | if (*i_acl != EXT4_ACL_NOT_CACHED) | ||
148 | posix_acl_release(*i_acl); | ||
149 | *i_acl = posix_acl_dup(acl); | ||
150 | spin_unlock(&inode->i_lock); | ||
151 | } | ||
152 | |||
153 | /* | 129 | /* |
154 | * Inode operation get_posix_acl(). | 130 | * Inode operation get_posix_acl(). |
155 | * | 131 | * |
@@ -158,7 +134,6 @@ ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl, | |||
158 | static struct posix_acl * | 134 | static struct posix_acl * |
159 | ext4_get_acl(struct inode *inode, int type) | 135 | ext4_get_acl(struct inode *inode, int type) |
160 | { | 136 | { |
161 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
162 | int name_index; | 137 | int name_index; |
163 | char *value = NULL; | 138 | char *value = NULL; |
164 | struct posix_acl *acl; | 139 | struct posix_acl *acl; |
@@ -167,23 +142,19 @@ ext4_get_acl(struct inode *inode, int type) | |||
167 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 142 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
168 | return NULL; | 143 | return NULL; |
169 | 144 | ||
145 | acl = get_cached_acl(inode, type); | ||
146 | if (acl != ACL_NOT_CACHED) | ||
147 | return acl; | ||
148 | |||
170 | switch (type) { | 149 | switch (type) { |
171 | case ACL_TYPE_ACCESS: | 150 | case ACL_TYPE_ACCESS: |
172 | acl = ext4_iget_acl(inode, &ei->i_acl); | ||
173 | if (acl != EXT4_ACL_NOT_CACHED) | ||
174 | return acl; | ||
175 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; | 151 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; |
176 | break; | 152 | break; |
177 | |||
178 | case ACL_TYPE_DEFAULT: | 153 | case ACL_TYPE_DEFAULT: |
179 | acl = ext4_iget_acl(inode, &ei->i_default_acl); | ||
180 | if (acl != EXT4_ACL_NOT_CACHED) | ||
181 | return acl; | ||
182 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; | 154 | name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; |
183 | break; | 155 | break; |
184 | |||
185 | default: | 156 | default: |
186 | return ERR_PTR(-EINVAL); | 157 | BUG(); |
187 | } | 158 | } |
188 | retval = ext4_xattr_get(inode, name_index, "", NULL, 0); | 159 | retval = ext4_xattr_get(inode, name_index, "", NULL, 0); |
189 | if (retval > 0) { | 160 | if (retval > 0) { |
@@ -200,17 +171,9 @@ ext4_get_acl(struct inode *inode, int type) | |||
200 | acl = ERR_PTR(retval); | 171 | acl = ERR_PTR(retval); |
201 | kfree(value); | 172 | kfree(value); |
202 | 173 | ||
203 | if (!IS_ERR(acl)) { | 174 | if (!IS_ERR(acl)) |
204 | switch (type) { | 175 | set_cached_acl(inode, type, acl); |
205 | case ACL_TYPE_ACCESS: | ||
206 | ext4_iset_acl(inode, &ei->i_acl, acl); | ||
207 | break; | ||
208 | 176 | ||
209 | case ACL_TYPE_DEFAULT: | ||
210 | ext4_iset_acl(inode, &ei->i_default_acl, acl); | ||
211 | break; | ||
212 | } | ||
213 | } | ||
214 | return acl; | 177 | return acl; |
215 | } | 178 | } |
216 | 179 | ||
@@ -223,7 +186,6 @@ static int | |||
223 | ext4_set_acl(handle_t *handle, struct inode *inode, int type, | 186 | ext4_set_acl(handle_t *handle, struct inode *inode, int type, |
224 | struct posix_acl *acl) | 187 | struct posix_acl *acl) |
225 | { | 188 | { |
226 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
227 | int name_index; | 189 | int name_index; |
228 | void *value = NULL; | 190 | void *value = NULL; |
229 | size_t size = 0; | 191 | size_t size = 0; |
@@ -268,17 +230,9 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, | |||
268 | value, size, 0); | 230 | value, size, 0); |
269 | 231 | ||
270 | kfree(value); | 232 | kfree(value); |
271 | if (!error) { | 233 | if (!error) |
272 | switch (type) { | 234 | set_cached_acl(inode, type, acl); |
273 | case ACL_TYPE_ACCESS: | ||
274 | ext4_iset_acl(inode, &ei->i_acl, acl); | ||
275 | break; | ||
276 | 235 | ||
277 | case ACL_TYPE_DEFAULT: | ||
278 | ext4_iset_acl(inode, &ei->i_default_acl, acl); | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | return error; | 236 | return error; |
283 | } | 237 | } |
284 | 238 | ||
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index cb45257a246e..949789d2bba6 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h | |||
@@ -53,10 +53,6 @@ static inline int ext4_acl_count(size_t size) | |||
53 | 53 | ||
54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
55 | 55 | ||
56 | /* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl | ||
57 | if the ACL has not been cached */ | ||
58 | #define EXT4_ACL_NOT_CACHED ((void *)-1) | ||
59 | |||
60 | /* acl.c */ | 56 | /* acl.c */ |
61 | extern int ext4_permission(struct inode *, int); | 57 | extern int ext4_permission(struct inode *, int); |
62 | extern int ext4_acl_chmod(struct inode *); | 58 | extern int ext4_acl_chmod(struct inode *); |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index cc7d5edc38c9..9714db393efe 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -93,20 +93,20 @@ typedef unsigned int ext4_group_t; | |||
93 | struct ext4_allocation_request { | 93 | struct ext4_allocation_request { |
94 | /* target inode for block we're allocating */ | 94 | /* target inode for block we're allocating */ |
95 | struct inode *inode; | 95 | struct inode *inode; |
96 | /* how many blocks we want to allocate */ | ||
97 | unsigned int len; | ||
96 | /* logical block in target inode */ | 98 | /* logical block in target inode */ |
97 | ext4_lblk_t logical; | 99 | ext4_lblk_t logical; |
98 | /* phys. target (a hint) */ | ||
99 | ext4_fsblk_t goal; | ||
100 | /* the closest logical allocated block to the left */ | 100 | /* the closest logical allocated block to the left */ |
101 | ext4_lblk_t lleft; | 101 | ext4_lblk_t lleft; |
102 | /* phys. block for ^^^ */ | ||
103 | ext4_fsblk_t pleft; | ||
104 | /* the closest logical allocated block to the right */ | 102 | /* the closest logical allocated block to the right */ |
105 | ext4_lblk_t lright; | 103 | ext4_lblk_t lright; |
106 | /* phys. block for ^^^ */ | 104 | /* phys. target (a hint) */ |
105 | ext4_fsblk_t goal; | ||
106 | /* phys. block for the closest logical allocated block to the left */ | ||
107 | ext4_fsblk_t pleft; | ||
108 | /* phys. block for the closest logical allocated block to the right */ | ||
107 | ext4_fsblk_t pright; | 109 | ext4_fsblk_t pright; |
108 | /* how many blocks we want to allocate */ | ||
109 | unsigned int len; | ||
110 | /* flags. see above EXT4_MB_HINT_* */ | 110 | /* flags. see above EXT4_MB_HINT_* */ |
111 | unsigned int flags; | 111 | unsigned int flags; |
112 | }; | 112 | }; |
@@ -352,6 +352,7 @@ struct ext4_new_group_data { | |||
352 | /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ | 352 | /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ |
353 | /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ | 353 | /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ |
354 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) | 354 | #define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) |
355 | #define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent) | ||
355 | 356 | ||
356 | /* | 357 | /* |
357 | * ioctl commands in 32 bit emulation | 358 | * ioctl commands in 32 bit emulation |
@@ -447,6 +448,15 @@ struct ext4_inode { | |||
447 | __le32 i_version_hi; /* high 32 bits for 64-bit version */ | 448 | __le32 i_version_hi; /* high 32 bits for 64-bit version */ |
448 | }; | 449 | }; |
449 | 450 | ||
451 | struct move_extent { | ||
452 | __u32 reserved; /* should be zero */ | ||
453 | __u32 donor_fd; /* donor file descriptor */ | ||
454 | __u64 orig_start; /* logical start offset in block for orig */ | ||
455 | __u64 donor_start; /* logical start offset in block for donor */ | ||
456 | __u64 len; /* block length to be moved */ | ||
457 | __u64 moved_len; /* moved block length */ | ||
458 | }; | ||
459 | #define MAX_DEFRAG_SIZE ((1UL<<31) - 1) | ||
450 | 460 | ||
451 | #define EXT4_EPOCH_BITS 2 | 461 | #define EXT4_EPOCH_BITS 2 |
452 | #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) | 462 | #define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) |
@@ -585,10 +595,6 @@ struct ext4_inode_info { | |||
585 | */ | 595 | */ |
586 | struct rw_semaphore xattr_sem; | 596 | struct rw_semaphore xattr_sem; |
587 | #endif | 597 | #endif |
588 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
589 | struct posix_acl *i_acl; | ||
590 | struct posix_acl *i_default_acl; | ||
591 | #endif | ||
592 | 598 | ||
593 | struct list_head i_orphan; /* unlinked but open inodes */ | 599 | struct list_head i_orphan; /* unlinked but open inodes */ |
594 | 600 | ||
@@ -674,7 +680,6 @@ struct ext4_inode_info { | |||
674 | #define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ | 680 | #define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ |
675 | #define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ | 681 | #define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ |
676 | #define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ | 682 | #define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ |
677 | #define EXT4_MOUNT_ABORT 0x00200 /* Fatal error detected */ | ||
678 | #define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ | 683 | #define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ |
679 | #define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ | 684 | #define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ |
680 | #define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ | 685 | #define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ |
@@ -696,17 +701,10 @@ struct ext4_inode_info { | |||
696 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ | 701 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ |
697 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ | 702 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ |
698 | 703 | ||
699 | /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ | ||
700 | #ifndef _LINUX_EXT2_FS_H | ||
701 | #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt | 704 | #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt |
702 | #define set_opt(o, opt) o |= EXT4_MOUNT_##opt | 705 | #define set_opt(o, opt) o |= EXT4_MOUNT_##opt |
703 | #define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \ | 706 | #define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \ |
704 | EXT4_MOUNT_##opt) | 707 | EXT4_MOUNT_##opt) |
705 | #else | ||
706 | #define EXT2_MOUNT_NOLOAD EXT4_MOUNT_NOLOAD | ||
707 | #define EXT2_MOUNT_ABORT EXT4_MOUNT_ABORT | ||
708 | #define EXT2_MOUNT_DATA_FLAGS EXT4_MOUNT_DATA_FLAGS | ||
709 | #endif | ||
710 | 708 | ||
711 | #define ext4_set_bit ext2_set_bit | 709 | #define ext4_set_bit ext2_set_bit |
712 | #define ext4_set_bit_atomic ext2_set_bit_atomic | 710 | #define ext4_set_bit_atomic ext2_set_bit_atomic |
@@ -824,6 +822,13 @@ struct ext4_super_block { | |||
824 | }; | 822 | }; |
825 | 823 | ||
826 | #ifdef __KERNEL__ | 824 | #ifdef __KERNEL__ |
825 | |||
826 | /* | ||
827 | * run-time mount flags | ||
828 | */ | ||
829 | #define EXT4_MF_MNTDIR_SAMPLED 0x0001 | ||
830 | #define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ | ||
831 | |||
827 | /* | 832 | /* |
828 | * fourth extended-fs super-block data in memory | 833 | * fourth extended-fs super-block data in memory |
829 | */ | 834 | */ |
@@ -842,7 +847,8 @@ struct ext4_sb_info { | |||
842 | struct buffer_head * s_sbh; /* Buffer containing the super block */ | 847 | struct buffer_head * s_sbh; /* Buffer containing the super block */ |
843 | struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ | 848 | struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ |
844 | struct buffer_head **s_group_desc; | 849 | struct buffer_head **s_group_desc; |
845 | unsigned long s_mount_opt; | 850 | unsigned int s_mount_opt; |
851 | unsigned int s_mount_flags; | ||
846 | ext4_fsblk_t s_sb_block; | 852 | ext4_fsblk_t s_sb_block; |
847 | uid_t s_resuid; | 853 | uid_t s_resuid; |
848 | gid_t s_resgid; | 854 | gid_t s_resgid; |
@@ -853,6 +859,7 @@ struct ext4_sb_info { | |||
853 | int s_inode_size; | 859 | int s_inode_size; |
854 | int s_first_ino; | 860 | int s_first_ino; |
855 | unsigned int s_inode_readahead_blks; | 861 | unsigned int s_inode_readahead_blks; |
862 | unsigned int s_inode_goal; | ||
856 | spinlock_t s_next_gen_lock; | 863 | spinlock_t s_next_gen_lock; |
857 | u32 s_next_generation; | 864 | u32 s_next_generation; |
858 | u32 s_hash_seed[4]; | 865 | u32 s_hash_seed[4]; |
@@ -1305,7 +1312,8 @@ extern int ext4fs_dirhash(const char *name, int len, struct | |||
1305 | dx_hash_info *hinfo); | 1312 | dx_hash_info *hinfo); |
1306 | 1313 | ||
1307 | /* ialloc.c */ | 1314 | /* ialloc.c */ |
1308 | extern struct inode * ext4_new_inode(handle_t *, struct inode *, int); | 1315 | extern struct inode *ext4_new_inode(handle_t *, struct inode *, int, |
1316 | const struct qstr *qstr, __u32 goal); | ||
1309 | extern void ext4_free_inode(handle_t *, struct inode *); | 1317 | extern void ext4_free_inode(handle_t *, struct inode *); |
1310 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); | 1318 | extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); |
1311 | extern unsigned long ext4_count_free_inodes(struct super_block *); | 1319 | extern unsigned long ext4_count_free_inodes(struct super_block *); |
@@ -1329,7 +1337,7 @@ extern void ext4_discard_preallocations(struct inode *); | |||
1329 | extern int __init init_ext4_mballoc(void); | 1337 | extern int __init init_ext4_mballoc(void); |
1330 | extern void exit_ext4_mballoc(void); | 1338 | extern void exit_ext4_mballoc(void); |
1331 | extern void ext4_mb_free_blocks(handle_t *, struct inode *, | 1339 | extern void ext4_mb_free_blocks(handle_t *, struct inode *, |
1332 | unsigned long, unsigned long, int, unsigned long *); | 1340 | ext4_fsblk_t, unsigned long, int, unsigned long *); |
1333 | extern int ext4_mb_add_groupinfo(struct super_block *sb, | 1341 | extern int ext4_mb_add_groupinfo(struct super_block *sb, |
1334 | ext4_group_t i, struct ext4_group_desc *desc); | 1342 | ext4_group_t i, struct ext4_group_desc *desc); |
1335 | extern void ext4_mb_update_group_info(struct ext4_group_info *grp, | 1343 | extern void ext4_mb_update_group_info(struct ext4_group_info *grp, |
@@ -1647,6 +1655,11 @@ extern int ext4_get_blocks(handle_t *handle, struct inode *inode, | |||
1647 | struct buffer_head *bh, int flags); | 1655 | struct buffer_head *bh, int flags); |
1648 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 1656 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
1649 | __u64 start, __u64 len); | 1657 | __u64 start, __u64 len); |
1658 | /* move_extent.c */ | ||
1659 | extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, | ||
1660 | __u64 start_orig, __u64 start_donor, | ||
1661 | __u64 len, __u64 *moved_len); | ||
1662 | |||
1650 | 1663 | ||
1651 | /* | 1664 | /* |
1652 | * Add new method to test wether block and inode bitmaps are properly | 1665 | * Add new method to test wether block and inode bitmaps are properly |
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index f0c3ec85bd48..20a84105a10b 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
@@ -221,12 +221,16 @@ static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) | |||
221 | } | 221 | } |
222 | 222 | ||
223 | extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks); | 223 | extern int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks); |
224 | extern ext4_fsblk_t ext_pblock(struct ext4_extent *ex); | ||
224 | extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); | 225 | extern ext4_fsblk_t idx_pblock(struct ext4_extent_idx *); |
225 | extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t); | 226 | extern void ext4_ext_store_pblock(struct ext4_extent *, ext4_fsblk_t); |
226 | extern int ext4_extent_tree_init(handle_t *, struct inode *); | 227 | extern int ext4_extent_tree_init(handle_t *, struct inode *); |
227 | extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, | 228 | extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, |
228 | int num, | 229 | int num, |
229 | struct ext4_ext_path *path); | 230 | struct ext4_ext_path *path); |
231 | extern int ext4_can_extents_be_merged(struct inode *inode, | ||
232 | struct ext4_extent *ex1, | ||
233 | struct ext4_extent *ex2); | ||
230 | extern int ext4_ext_try_to_merge(struct inode *inode, | 234 | extern int ext4_ext_try_to_merge(struct inode *inode, |
231 | struct ext4_ext_path *path, | 235 | struct ext4_ext_path *path, |
232 | struct ext4_extent *); | 236 | struct ext4_extent *); |
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index ad13a84644e1..eb27fd0f2ee8 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c | |||
@@ -43,6 +43,8 @@ int __ext4_journal_forget(const char *where, handle_t *handle, | |||
43 | ext4_journal_abort_handle(where, __func__, bh, | 43 | ext4_journal_abort_handle(where, __func__, bh, |
44 | handle, err); | 44 | handle, err); |
45 | } | 45 | } |
46 | else | ||
47 | brelse(bh); | ||
46 | return err; | 48 | return err; |
47 | } | 49 | } |
48 | 50 | ||
@@ -57,6 +59,8 @@ int __ext4_journal_revoke(const char *where, handle_t *handle, | |||
57 | ext4_journal_abort_handle(where, __func__, bh, | 59 | ext4_journal_abort_handle(where, __func__, bh, |
58 | handle, err); | 60 | handle, err); |
59 | } | 61 | } |
62 | else | ||
63 | brelse(bh); | ||
60 | return err; | 64 | return err; |
61 | } | 65 | } |
62 | 66 | ||
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index be2f426f6805..139fb8cb87e4 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -131,9 +131,11 @@ int __ext4_journal_get_undo_access(const char *where, handle_t *handle, | |||
131 | int __ext4_journal_get_write_access(const char *where, handle_t *handle, | 131 | int __ext4_journal_get_write_access(const char *where, handle_t *handle, |
132 | struct buffer_head *bh); | 132 | struct buffer_head *bh); |
133 | 133 | ||
134 | /* When called with an invalid handle, this will still do a put on the BH */ | ||
134 | int __ext4_journal_forget(const char *where, handle_t *handle, | 135 | int __ext4_journal_forget(const char *where, handle_t *handle, |
135 | struct buffer_head *bh); | 136 | struct buffer_head *bh); |
136 | 137 | ||
138 | /* When called with an invalid handle, this will still do a put on the BH */ | ||
137 | int __ext4_journal_revoke(const char *where, handle_t *handle, | 139 | int __ext4_journal_revoke(const char *where, handle_t *handle, |
138 | ext4_fsblk_t blocknr, struct buffer_head *bh); | 140 | ext4_fsblk_t blocknr, struct buffer_head *bh); |
139 | 141 | ||
@@ -281,10 +283,10 @@ static inline int ext4_should_order_data(struct inode *inode) | |||
281 | 283 | ||
282 | static inline int ext4_should_writeback_data(struct inode *inode) | 284 | static inline int ext4_should_writeback_data(struct inode *inode) |
283 | { | 285 | { |
284 | if (EXT4_JOURNAL(inode) == NULL) | ||
285 | return 0; | ||
286 | if (!S_ISREG(inode->i_mode)) | 286 | if (!S_ISREG(inode->i_mode)) |
287 | return 0; | 287 | return 0; |
288 | if (EXT4_JOURNAL(inode) == NULL) | ||
289 | return 1; | ||
288 | if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) | 290 | if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL) |
289 | return 0; | 291 | return 0; |
290 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) | 292 | if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 2593f748c3a4..73ebfb44ad75 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -49,7 +49,7 @@ | |||
49 | * ext_pblock: | 49 | * ext_pblock: |
50 | * combine low and high parts of physical block number into ext4_fsblk_t | 50 | * combine low and high parts of physical block number into ext4_fsblk_t |
51 | */ | 51 | */ |
52 | static ext4_fsblk_t ext_pblock(struct ext4_extent *ex) | 52 | ext4_fsblk_t ext_pblock(struct ext4_extent *ex) |
53 | { | 53 | { |
54 | ext4_fsblk_t block; | 54 | ext4_fsblk_t block; |
55 | 55 | ||
@@ -1417,7 +1417,7 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, | |||
1417 | return err; | 1417 | return err; |
1418 | } | 1418 | } |
1419 | 1419 | ||
1420 | static int | 1420 | int |
1421 | ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | 1421 | ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, |
1422 | struct ext4_extent *ex2) | 1422 | struct ext4_extent *ex2) |
1423 | { | 1423 | { |
@@ -1977,6 +1977,7 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks, | |||
1977 | */ | 1977 | */ |
1978 | /* 1 bitmap, 1 block group descriptor */ | 1978 | /* 1 bitmap, 1 block group descriptor */ |
1979 | ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb); | 1979 | ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb); |
1980 | return ret; | ||
1980 | } | 1981 | } |
1981 | } | 1982 | } |
1982 | 1983 | ||
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 588af8c77246..3f1873fef1c6 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <linux/time.h> | 21 | #include <linux/time.h> |
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/jbd2.h> | 23 | #include <linux/jbd2.h> |
24 | #include <linux/mount.h> | ||
25 | #include <linux/path.h> | ||
24 | #include "ext4.h" | 26 | #include "ext4.h" |
25 | #include "ext4_jbd2.h" | 27 | #include "ext4_jbd2.h" |
26 | #include "xattr.h" | 28 | #include "xattr.h" |
@@ -145,6 +147,38 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) | |||
145 | return 0; | 147 | return 0; |
146 | } | 148 | } |
147 | 149 | ||
150 | static int ext4_file_open(struct inode * inode, struct file * filp) | ||
151 | { | ||
152 | struct super_block *sb = inode->i_sb; | ||
153 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
154 | struct vfsmount *mnt = filp->f_path.mnt; | ||
155 | struct path path; | ||
156 | char buf[64], *cp; | ||
157 | |||
158 | if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) && | ||
159 | !(sb->s_flags & MS_RDONLY))) { | ||
160 | sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED; | ||
161 | /* | ||
162 | * Sample where the filesystem has been mounted and | ||
163 | * store it in the superblock for sysadmin convenience | ||
164 | * when trying to sort through large numbers of block | ||
165 | * devices or filesystem images. | ||
166 | */ | ||
167 | memset(buf, 0, sizeof(buf)); | ||
168 | path.mnt = mnt->mnt_parent; | ||
169 | path.dentry = mnt->mnt_mountpoint; | ||
170 | path_get(&path); | ||
171 | cp = d_path(&path, buf, sizeof(buf)); | ||
172 | path_put(&path); | ||
173 | if (!IS_ERR(cp)) { | ||
174 | memcpy(sbi->s_es->s_last_mounted, cp, | ||
175 | sizeof(sbi->s_es->s_last_mounted)); | ||
176 | sb->s_dirt = 1; | ||
177 | } | ||
178 | } | ||
179 | return generic_file_open(inode, filp); | ||
180 | } | ||
181 | |||
148 | const struct file_operations ext4_file_operations = { | 182 | const struct file_operations ext4_file_operations = { |
149 | .llseek = generic_file_llseek, | 183 | .llseek = generic_file_llseek, |
150 | .read = do_sync_read, | 184 | .read = do_sync_read, |
@@ -156,7 +190,7 @@ const struct file_operations ext4_file_operations = { | |||
156 | .compat_ioctl = ext4_compat_ioctl, | 190 | .compat_ioctl = ext4_compat_ioctl, |
157 | #endif | 191 | #endif |
158 | .mmap = ext4_file_mmap, | 192 | .mmap = ext4_file_mmap, |
159 | .open = generic_file_open, | 193 | .open = ext4_file_open, |
160 | .release = ext4_release_file, | 194 | .release = ext4_release_file, |
161 | .fsync = ext4_sync_file, | 195 | .fsync = ext4_sync_file, |
162 | .splice_read = generic_file_splice_read, | 196 | .splice_read = generic_file_splice_read, |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 5afe4370840b..83cf6415f599 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -28,10 +28,12 @@ | |||
28 | #include <linux/writeback.h> | 28 | #include <linux/writeback.h> |
29 | #include <linux/jbd2.h> | 29 | #include <linux/jbd2.h> |
30 | #include <linux/blkdev.h> | 30 | #include <linux/blkdev.h> |
31 | #include <linux/marker.h> | 31 | |
32 | #include "ext4.h" | 32 | #include "ext4.h" |
33 | #include "ext4_jbd2.h" | 33 | #include "ext4_jbd2.h" |
34 | 34 | ||
35 | #include <trace/events/ext4.h> | ||
36 | |||
35 | /* | 37 | /* |
36 | * akpm: A new design for ext4_sync_file(). | 38 | * akpm: A new design for ext4_sync_file(). |
37 | * | 39 | * |
@@ -52,9 +54,7 @@ int ext4_sync_file(struct file *file, struct dentry *dentry, int datasync) | |||
52 | 54 | ||
53 | J_ASSERT(ext4_journal_current_handle() == NULL); | 55 | J_ASSERT(ext4_journal_current_handle() == NULL); |
54 | 56 | ||
55 | trace_mark(ext4_sync_file, "dev %s datasync %d ino %ld parent %ld", | 57 | trace_ext4_sync_file(file, dentry, datasync); |
56 | inode->i_sb->s_id, datasync, inode->i_ino, | ||
57 | dentry->d_parent->d_inode->i_ino); | ||
58 | 58 | ||
59 | /* | 59 | /* |
60 | * data=writeback: | 60 | * data=writeback: |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 3743bd849bce..29e6dc7299b8 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -23,11 +23,14 @@ | |||
23 | #include <linux/bitops.h> | 23 | #include <linux/bitops.h> |
24 | #include <linux/blkdev.h> | 24 | #include <linux/blkdev.h> |
25 | #include <asm/byteorder.h> | 25 | #include <asm/byteorder.h> |
26 | |||
26 | #include "ext4.h" | 27 | #include "ext4.h" |
27 | #include "ext4_jbd2.h" | 28 | #include "ext4_jbd2.h" |
28 | #include "xattr.h" | 29 | #include "xattr.h" |
29 | #include "acl.h" | 30 | #include "acl.h" |
30 | 31 | ||
32 | #include <trace/events/ext4.h> | ||
33 | |||
31 | /* | 34 | /* |
32 | * ialloc.c contains the inodes allocation and deallocation routines | 35 | * ialloc.c contains the inodes allocation and deallocation routines |
33 | */ | 36 | */ |
@@ -208,11 +211,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
208 | 211 | ||
209 | ino = inode->i_ino; | 212 | ino = inode->i_ino; |
210 | ext4_debug("freeing inode %lu\n", ino); | 213 | ext4_debug("freeing inode %lu\n", ino); |
211 | trace_mark(ext4_free_inode, | 214 | trace_ext4_free_inode(inode); |
212 | "dev %s ino %lu mode %d uid %lu gid %lu bocks %llu", | ||
213 | sb->s_id, inode->i_ino, inode->i_mode, | ||
214 | (unsigned long) inode->i_uid, (unsigned long) inode->i_gid, | ||
215 | (unsigned long long) inode->i_blocks); | ||
216 | 215 | ||
217 | /* | 216 | /* |
218 | * Note: we must free any quota before locking the superblock, | 217 | * Note: we must free any quota before locking the superblock, |
@@ -471,7 +470,8 @@ void get_orlov_stats(struct super_block *sb, ext4_group_t g, | |||
471 | */ | 470 | */ |
472 | 471 | ||
473 | static int find_group_orlov(struct super_block *sb, struct inode *parent, | 472 | static int find_group_orlov(struct super_block *sb, struct inode *parent, |
474 | ext4_group_t *group, int mode) | 473 | ext4_group_t *group, int mode, |
474 | const struct qstr *qstr) | ||
475 | { | 475 | { |
476 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; | 476 | ext4_group_t parent_group = EXT4_I(parent)->i_block_group; |
477 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 477 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
@@ -486,6 +486,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, | |||
486 | struct ext4_group_desc *desc; | 486 | struct ext4_group_desc *desc; |
487 | struct orlov_stats stats; | 487 | struct orlov_stats stats; |
488 | int flex_size = ext4_flex_bg_size(sbi); | 488 | int flex_size = ext4_flex_bg_size(sbi); |
489 | struct dx_hash_info hinfo; | ||
489 | 490 | ||
490 | ngroups = real_ngroups; | 491 | ngroups = real_ngroups; |
491 | if (flex_size > 1) { | 492 | if (flex_size > 1) { |
@@ -507,7 +508,13 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent, | |||
507 | int best_ndir = inodes_per_group; | 508 | int best_ndir = inodes_per_group; |
508 | int ret = -1; | 509 | int ret = -1; |
509 | 510 | ||
510 | get_random_bytes(&grp, sizeof(grp)); | 511 | if (qstr) { |
512 | hinfo.hash_version = DX_HASH_HALF_MD4; | ||
513 | hinfo.seed = sbi->s_hash_seed; | ||
514 | ext4fs_dirhash(qstr->name, qstr->len, &hinfo); | ||
515 | grp = hinfo.hash; | ||
516 | } else | ||
517 | get_random_bytes(&grp, sizeof(grp)); | ||
511 | parent_group = (unsigned)grp % ngroups; | 518 | parent_group = (unsigned)grp % ngroups; |
512 | for (i = 0; i < ngroups; i++) { | 519 | for (i = 0; i < ngroups; i++) { |
513 | g = (parent_group + i) % ngroups; | 520 | g = (parent_group + i) % ngroups; |
@@ -650,7 +657,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent, | |||
650 | *group = parent_group + flex_size; | 657 | *group = parent_group + flex_size; |
651 | if (*group > ngroups) | 658 | if (*group > ngroups) |
652 | *group = 0; | 659 | *group = 0; |
653 | return find_group_orlov(sb, parent, group, mode); | 660 | return find_group_orlov(sb, parent, group, mode, 0); |
654 | } | 661 | } |
655 | 662 | ||
656 | /* | 663 | /* |
@@ -791,7 +798,8 @@ err_ret: | |||
791 | * For other inodes, search forward from the parent directory's block | 798 | * For other inodes, search forward from the parent directory's block |
792 | * group to find a free inode. | 799 | * group to find a free inode. |
793 | */ | 800 | */ |
794 | struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) | 801 | struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode, |
802 | const struct qstr *qstr, __u32 goal) | ||
795 | { | 803 | { |
796 | struct super_block *sb; | 804 | struct super_block *sb; |
797 | struct buffer_head *inode_bitmap_bh = NULL; | 805 | struct buffer_head *inode_bitmap_bh = NULL; |
@@ -815,14 +823,23 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) | |||
815 | 823 | ||
816 | sb = dir->i_sb; | 824 | sb = dir->i_sb; |
817 | ngroups = ext4_get_groups_count(sb); | 825 | ngroups = ext4_get_groups_count(sb); |
818 | trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id, | 826 | trace_ext4_request_inode(dir, mode); |
819 | dir->i_ino, mode); | ||
820 | inode = new_inode(sb); | 827 | inode = new_inode(sb); |
821 | if (!inode) | 828 | if (!inode) |
822 | return ERR_PTR(-ENOMEM); | 829 | return ERR_PTR(-ENOMEM); |
823 | ei = EXT4_I(inode); | 830 | ei = EXT4_I(inode); |
824 | sbi = EXT4_SB(sb); | 831 | sbi = EXT4_SB(sb); |
825 | 832 | ||
833 | if (!goal) | ||
834 | goal = sbi->s_inode_goal; | ||
835 | |||
836 | if (goal && goal <= le32_to_cpu(sbi->s_es->s_inodes_count)) { | ||
837 | group = (goal - 1) / EXT4_INODES_PER_GROUP(sb); | ||
838 | ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb); | ||
839 | ret2 = 0; | ||
840 | goto got_group; | ||
841 | } | ||
842 | |||
826 | if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) { | 843 | if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) { |
827 | ret2 = find_group_flex(sb, dir, &group); | 844 | ret2 = find_group_flex(sb, dir, &group); |
828 | if (ret2 == -1) { | 845 | if (ret2 == -1) { |
@@ -841,7 +858,7 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode) | |||
841 | if (test_opt(sb, OLDALLOC)) | 858 | if (test_opt(sb, OLDALLOC)) |
842 | ret2 = find_group_dir(sb, dir, &group); | 859 | ret2 = find_group_dir(sb, dir, &group); |
843 | else | 860 | else |
844 | ret2 = find_group_orlov(sb, dir, &group, mode); | 861 | ret2 = find_group_orlov(sb, dir, &group, mode, qstr); |
845 | } else | 862 | } else |
846 | ret2 = find_group_other(sb, dir, &group, mode); | 863 | ret2 = find_group_other(sb, dir, &group, mode); |
847 | 864 | ||
@@ -851,7 +868,7 @@ got_group: | |||
851 | if (ret2 == -1) | 868 | if (ret2 == -1) |
852 | goto out; | 869 | goto out; |
853 | 870 | ||
854 | for (i = 0; i < ngroups; i++) { | 871 | for (i = 0; i < ngroups; i++, ino = 0) { |
855 | err = -EIO; | 872 | err = -EIO; |
856 | 873 | ||
857 | gdp = ext4_get_group_desc(sb, group, &group_desc_bh); | 874 | gdp = ext4_get_group_desc(sb, group, &group_desc_bh); |
@@ -863,8 +880,6 @@ got_group: | |||
863 | if (!inode_bitmap_bh) | 880 | if (!inode_bitmap_bh) |
864 | goto fail; | 881 | goto fail; |
865 | 882 | ||
866 | ino = 0; | ||
867 | |||
868 | repeat_in_this_group: | 883 | repeat_in_this_group: |
869 | ino = ext4_find_next_zero_bit((unsigned long *) | 884 | ino = ext4_find_next_zero_bit((unsigned long *) |
870 | inode_bitmap_bh->b_data, | 885 | inode_bitmap_bh->b_data, |
@@ -1047,8 +1062,7 @@ got: | |||
1047 | } | 1062 | } |
1048 | 1063 | ||
1049 | ext4_debug("allocating inode %lu\n", inode->i_ino); | 1064 | ext4_debug("allocating inode %lu\n", inode->i_ino); |
1050 | trace_mark(ext4_allocate_inode, "dev %s ino %lu dir %lu mode %d", | 1065 | trace_ext4_allocate_inode(inode, dir, mode); |
1051 | sb->s_id, inode->i_ino, dir->i_ino, mode); | ||
1052 | goto really_out; | 1066 | goto really_out; |
1053 | fail: | 1067 | fail: |
1054 | ext4_std_error(sb, err); | 1068 | ext4_std_error(sb, err); |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 875db944b22f..f9c642b22efa 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -37,11 +37,14 @@ | |||
37 | #include <linux/namei.h> | 37 | #include <linux/namei.h> |
38 | #include <linux/uio.h> | 38 | #include <linux/uio.h> |
39 | #include <linux/bio.h> | 39 | #include <linux/bio.h> |
40 | |||
40 | #include "ext4_jbd2.h" | 41 | #include "ext4_jbd2.h" |
41 | #include "xattr.h" | 42 | #include "xattr.h" |
42 | #include "acl.h" | 43 | #include "acl.h" |
43 | #include "ext4_extents.h" | 44 | #include "ext4_extents.h" |
44 | 45 | ||
46 | #include <trace/events/ext4.h> | ||
47 | |||
45 | #define MPAGE_DA_EXTENT_TAIL 0x01 | 48 | #define MPAGE_DA_EXTENT_TAIL 0x01 |
46 | 49 | ||
47 | static inline int ext4_begin_ordered_truncate(struct inode *inode, | 50 | static inline int ext4_begin_ordered_truncate(struct inode *inode, |
@@ -75,22 +78,20 @@ static int ext4_inode_is_fast_symlink(struct inode *inode) | |||
75 | * but there may still be a record of it in the journal, and that record | 78 | * but there may still be a record of it in the journal, and that record |
76 | * still needs to be revoked. | 79 | * still needs to be revoked. |
77 | * | 80 | * |
78 | * If the handle isn't valid we're not journaling so there's nothing to do. | 81 | * If the handle isn't valid we're not journaling, but we still need to |
82 | * call into ext4_journal_revoke() to put the buffer head. | ||
79 | */ | 83 | */ |
80 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, | 84 | int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode, |
81 | struct buffer_head *bh, ext4_fsblk_t blocknr) | 85 | struct buffer_head *bh, ext4_fsblk_t blocknr) |
82 | { | 86 | { |
83 | int err; | 87 | int err; |
84 | 88 | ||
85 | if (!ext4_handle_valid(handle)) | ||
86 | return 0; | ||
87 | |||
88 | might_sleep(); | 89 | might_sleep(); |
89 | 90 | ||
90 | BUFFER_TRACE(bh, "enter"); | 91 | BUFFER_TRACE(bh, "enter"); |
91 | 92 | ||
92 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " | 93 | jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " |
93 | "data mode %lx\n", | 94 | "data mode %x\n", |
94 | bh, is_metadata, inode->i_mode, | 95 | bh, is_metadata, inode->i_mode, |
95 | test_opt(inode->i_sb, DATA_FLAGS)); | 96 | test_opt(inode->i_sb, DATA_FLAGS)); |
96 | 97 | ||
@@ -329,8 +330,8 @@ static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) | |||
329 | */ | 330 | */ |
330 | 331 | ||
331 | static int ext4_block_to_path(struct inode *inode, | 332 | static int ext4_block_to_path(struct inode *inode, |
332 | ext4_lblk_t i_block, | 333 | ext4_lblk_t i_block, |
333 | ext4_lblk_t offsets[4], int *boundary) | 334 | ext4_lblk_t offsets[4], int *boundary) |
334 | { | 335 | { |
335 | int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); | 336 | int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); |
336 | int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); | 337 | int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); |
@@ -362,9 +363,9 @@ static int ext4_block_to_path(struct inode *inode, | |||
362 | final = ptrs; | 363 | final = ptrs; |
363 | } else { | 364 | } else { |
364 | ext4_warning(inode->i_sb, "ext4_block_to_path", | 365 | ext4_warning(inode->i_sb, "ext4_block_to_path", |
365 | "block %lu > max in inode %lu", | 366 | "block %lu > max in inode %lu", |
366 | i_block + direct_blocks + | 367 | i_block + direct_blocks + |
367 | indirect_blocks + double_blocks, inode->i_ino); | 368 | indirect_blocks + double_blocks, inode->i_ino); |
368 | } | 369 | } |
369 | if (boundary) | 370 | if (boundary) |
370 | *boundary = final - 1 - (i_block & (ptrs - 1)); | 371 | *boundary = final - 1 - (i_block & (ptrs - 1)); |
@@ -379,25 +380,25 @@ static int __ext4_check_blockref(const char *function, struct inode *inode, | |||
379 | 380 | ||
380 | while (bref < p+max) { | 381 | while (bref < p+max) { |
381 | blk = le32_to_cpu(*bref++); | 382 | blk = le32_to_cpu(*bref++); |
382 | if (blk && | 383 | if (blk && |
383 | unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), | 384 | unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), |
384 | blk, 1))) { | 385 | blk, 1))) { |
385 | ext4_error(inode->i_sb, function, | 386 | ext4_error(inode->i_sb, function, |
386 | "invalid block reference %u " | 387 | "invalid block reference %u " |
387 | "in inode #%lu", blk, inode->i_ino); | 388 | "in inode #%lu", blk, inode->i_ino); |
388 | return -EIO; | 389 | return -EIO; |
389 | } | 390 | } |
390 | } | 391 | } |
391 | return 0; | 392 | return 0; |
392 | } | 393 | } |
393 | 394 | ||
394 | 395 | ||
395 | #define ext4_check_indirect_blockref(inode, bh) \ | 396 | #define ext4_check_indirect_blockref(inode, bh) \ |
396 | __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \ | 397 | __ext4_check_blockref(__func__, inode, (__le32 *)(bh)->b_data, \ |
397 | EXT4_ADDR_PER_BLOCK((inode)->i_sb)) | 398 | EXT4_ADDR_PER_BLOCK((inode)->i_sb)) |
398 | 399 | ||
399 | #define ext4_check_inode_blockref(inode) \ | 400 | #define ext4_check_inode_blockref(inode) \ |
400 | __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \ | 401 | __ext4_check_blockref(__func__, inode, EXT4_I(inode)->i_data, \ |
401 | EXT4_NDIR_BLOCKS) | 402 | EXT4_NDIR_BLOCKS) |
402 | 403 | ||
403 | /** | 404 | /** |
@@ -447,7 +448,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, | |||
447 | bh = sb_getblk(sb, le32_to_cpu(p->key)); | 448 | bh = sb_getblk(sb, le32_to_cpu(p->key)); |
448 | if (unlikely(!bh)) | 449 | if (unlikely(!bh)) |
449 | goto failure; | 450 | goto failure; |
450 | 451 | ||
451 | if (!bh_uptodate_or_lock(bh)) { | 452 | if (!bh_uptodate_or_lock(bh)) { |
452 | if (bh_submit_read(bh) < 0) { | 453 | if (bh_submit_read(bh) < 0) { |
453 | put_bh(bh); | 454 | put_bh(bh); |
@@ -459,7 +460,7 @@ static Indirect *ext4_get_branch(struct inode *inode, int depth, | |||
459 | goto failure; | 460 | goto failure; |
460 | } | 461 | } |
461 | } | 462 | } |
462 | 463 | ||
463 | add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); | 464 | add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); |
464 | /* Reader: end */ | 465 | /* Reader: end */ |
465 | if (!p->key) | 466 | if (!p->key) |
@@ -552,7 +553,7 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) | |||
552 | * returns it. | 553 | * returns it. |
553 | */ | 554 | */ |
554 | static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, | 555 | static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, |
555 | Indirect *partial) | 556 | Indirect *partial) |
556 | { | 557 | { |
557 | /* | 558 | /* |
558 | * XXX need to get goal block from mballoc's data structures | 559 | * XXX need to get goal block from mballoc's data structures |
@@ -574,7 +575,7 @@ static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, | |||
574 | * direct and indirect blocks. | 575 | * direct and indirect blocks. |
575 | */ | 576 | */ |
576 | static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, | 577 | static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, |
577 | int blocks_to_boundary) | 578 | int blocks_to_boundary) |
578 | { | 579 | { |
579 | unsigned int count = 0; | 580 | unsigned int count = 0; |
580 | 581 | ||
@@ -610,9 +611,9 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, | |||
610 | * direct blocks | 611 | * direct blocks |
611 | */ | 612 | */ |
612 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | 613 | static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, |
613 | ext4_lblk_t iblock, ext4_fsblk_t goal, | 614 | ext4_lblk_t iblock, ext4_fsblk_t goal, |
614 | int indirect_blks, int blks, | 615 | int indirect_blks, int blks, |
615 | ext4_fsblk_t new_blocks[4], int *err) | 616 | ext4_fsblk_t new_blocks[4], int *err) |
616 | { | 617 | { |
617 | struct ext4_allocation_request ar; | 618 | struct ext4_allocation_request ar; |
618 | int target, i; | 619 | int target, i; |
@@ -683,10 +684,10 @@ static int ext4_alloc_blocks(handle_t *handle, struct inode *inode, | |||
683 | } | 684 | } |
684 | if (!*err) { | 685 | if (!*err) { |
685 | if (target == blks) { | 686 | if (target == blks) { |
686 | /* | 687 | /* |
687 | * save the new block number | 688 | * save the new block number |
688 | * for the first direct block | 689 | * for the first direct block |
689 | */ | 690 | */ |
690 | new_blocks[index] = current_block; | 691 | new_blocks[index] = current_block; |
691 | } | 692 | } |
692 | blk_allocated += ar.len; | 693 | blk_allocated += ar.len; |
@@ -728,9 +729,9 @@ failed_out: | |||
728 | * as described above and return 0. | 729 | * as described above and return 0. |
729 | */ | 730 | */ |
730 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | 731 | static int ext4_alloc_branch(handle_t *handle, struct inode *inode, |
731 | ext4_lblk_t iblock, int indirect_blks, | 732 | ext4_lblk_t iblock, int indirect_blks, |
732 | int *blks, ext4_fsblk_t goal, | 733 | int *blks, ext4_fsblk_t goal, |
733 | ext4_lblk_t *offsets, Indirect *branch) | 734 | ext4_lblk_t *offsets, Indirect *branch) |
734 | { | 735 | { |
735 | int blocksize = inode->i_sb->s_blocksize; | 736 | int blocksize = inode->i_sb->s_blocksize; |
736 | int i, n = 0; | 737 | int i, n = 0; |
@@ -777,7 +778,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, | |||
777 | * the chain to point to the new allocated | 778 | * the chain to point to the new allocated |
778 | * data blocks numbers | 779 | * data blocks numbers |
779 | */ | 780 | */ |
780 | for (i=1; i < num; i++) | 781 | for (i = 1; i < num; i++) |
781 | *(branch[n].p + i) = cpu_to_le32(++current_block); | 782 | *(branch[n].p + i) = cpu_to_le32(++current_block); |
782 | } | 783 | } |
783 | BUFFER_TRACE(bh, "marking uptodate"); | 784 | BUFFER_TRACE(bh, "marking uptodate"); |
@@ -820,7 +821,8 @@ failed: | |||
820 | * chain to new block and return 0. | 821 | * chain to new block and return 0. |
821 | */ | 822 | */ |
822 | static int ext4_splice_branch(handle_t *handle, struct inode *inode, | 823 | static int ext4_splice_branch(handle_t *handle, struct inode *inode, |
823 | ext4_lblk_t block, Indirect *where, int num, int blks) | 824 | ext4_lblk_t block, Indirect *where, int num, |
825 | int blks) | ||
824 | { | 826 | { |
825 | int i; | 827 | int i; |
826 | int err = 0; | 828 | int err = 0; |
@@ -852,10 +854,6 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, | |||
852 | } | 854 | } |
853 | 855 | ||
854 | /* We are done with atomic stuff, now do the rest of housekeeping */ | 856 | /* We are done with atomic stuff, now do the rest of housekeeping */ |
855 | |||
856 | inode->i_ctime = ext4_current_time(inode); | ||
857 | ext4_mark_inode_dirty(handle, inode); | ||
858 | |||
859 | /* had we spliced it onto indirect block? */ | 857 | /* had we spliced it onto indirect block? */ |
860 | if (where->bh) { | 858 | if (where->bh) { |
861 | /* | 859 | /* |
@@ -874,8 +872,8 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode, | |||
874 | } else { | 872 | } else { |
875 | /* | 873 | /* |
876 | * OK, we spliced it into the inode itself on a direct block. | 874 | * OK, we spliced it into the inode itself on a direct block. |
877 | * Inode was dirtied above. | ||
878 | */ | 875 | */ |
876 | ext4_mark_inode_dirty(handle, inode); | ||
879 | jbd_debug(5, "splicing direct\n"); | 877 | jbd_debug(5, "splicing direct\n"); |
880 | } | 878 | } |
881 | return err; | 879 | return err; |
@@ -921,9 +919,9 @@ err_out: | |||
921 | * blocks. | 919 | * blocks. |
922 | */ | 920 | */ |
923 | static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | 921 | static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, |
924 | ext4_lblk_t iblock, unsigned int maxblocks, | 922 | ext4_lblk_t iblock, unsigned int maxblocks, |
925 | struct buffer_head *bh_result, | 923 | struct buffer_head *bh_result, |
926 | int flags) | 924 | int flags) |
927 | { | 925 | { |
928 | int err = -EIO; | 926 | int err = -EIO; |
929 | ext4_lblk_t offsets[4]; | 927 | ext4_lblk_t offsets[4]; |
@@ -939,7 +937,7 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
939 | J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)); | 937 | J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)); |
940 | J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); | 938 | J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); |
941 | depth = ext4_block_to_path(inode, iblock, offsets, | 939 | depth = ext4_block_to_path(inode, iblock, offsets, |
942 | &blocks_to_boundary); | 940 | &blocks_to_boundary); |
943 | 941 | ||
944 | if (depth == 0) | 942 | if (depth == 0) |
945 | goto out; | 943 | goto out; |
@@ -987,8 +985,8 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
987 | * Block out ext4_truncate while we alter the tree | 985 | * Block out ext4_truncate while we alter the tree |
988 | */ | 986 | */ |
989 | err = ext4_alloc_branch(handle, inode, iblock, indirect_blks, | 987 | err = ext4_alloc_branch(handle, inode, iblock, indirect_blks, |
990 | &count, goal, | 988 | &count, goal, |
991 | offsets + (partial - chain), partial); | 989 | offsets + (partial - chain), partial); |
992 | 990 | ||
993 | /* | 991 | /* |
994 | * The ext4_splice_branch call will free and forget any buffers | 992 | * The ext4_splice_branch call will free and forget any buffers |
@@ -999,8 +997,8 @@ static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode, | |||
999 | */ | 997 | */ |
1000 | if (!err) | 998 | if (!err) |
1001 | err = ext4_splice_branch(handle, inode, iblock, | 999 | err = ext4_splice_branch(handle, inode, iblock, |
1002 | partial, indirect_blks, count); | 1000 | partial, indirect_blks, count); |
1003 | else | 1001 | else |
1004 | goto cleanup; | 1002 | goto cleanup; |
1005 | 1003 | ||
1006 | set_buffer_new(bh_result); | 1004 | set_buffer_new(bh_result); |
@@ -1172,7 +1170,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
1172 | up_read((&EXT4_I(inode)->i_data_sem)); | 1170 | up_read((&EXT4_I(inode)->i_data_sem)); |
1173 | 1171 | ||
1174 | if (retval > 0 && buffer_mapped(bh)) { | 1172 | if (retval > 0 && buffer_mapped(bh)) { |
1175 | int ret = check_block_validity(inode, block, | 1173 | int ret = check_block_validity(inode, block, |
1176 | bh->b_blocknr, retval); | 1174 | bh->b_blocknr, retval); |
1177 | if (ret != 0) | 1175 | if (ret != 0) |
1178 | return ret; | 1176 | return ret; |
@@ -1254,7 +1252,7 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block, | |||
1254 | 1252 | ||
1255 | up_write((&EXT4_I(inode)->i_data_sem)); | 1253 | up_write((&EXT4_I(inode)->i_data_sem)); |
1256 | if (retval > 0 && buffer_mapped(bh)) { | 1254 | if (retval > 0 && buffer_mapped(bh)) { |
1257 | int ret = check_block_validity(inode, block, | 1255 | int ret = check_block_validity(inode, block, |
1258 | bh->b_blocknr, retval); | 1256 | bh->b_blocknr, retval); |
1259 | if (ret != 0) | 1257 | if (ret != 0) |
1260 | return ret; | 1258 | return ret; |
@@ -1405,8 +1403,7 @@ static int walk_page_buffers(handle_t *handle, | |||
1405 | 1403 | ||
1406 | for (bh = head, block_start = 0; | 1404 | for (bh = head, block_start = 0; |
1407 | ret == 0 && (bh != head || !block_start); | 1405 | ret == 0 && (bh != head || !block_start); |
1408 | block_start = block_end, bh = next) | 1406 | block_start = block_end, bh = next) { |
1409 | { | ||
1410 | next = bh->b_this_page; | 1407 | next = bh->b_this_page; |
1411 | block_end = block_start + blocksize; | 1408 | block_end = block_start + blocksize; |
1412 | if (block_end <= from || block_start >= to) { | 1409 | if (block_end <= from || block_start >= to) { |
@@ -1447,7 +1444,7 @@ static int walk_page_buffers(handle_t *handle, | |||
1447 | * write. | 1444 | * write. |
1448 | */ | 1445 | */ |
1449 | static int do_journal_get_write_access(handle_t *handle, | 1446 | static int do_journal_get_write_access(handle_t *handle, |
1450 | struct buffer_head *bh) | 1447 | struct buffer_head *bh) |
1451 | { | 1448 | { |
1452 | if (!buffer_mapped(bh) || buffer_freed(bh)) | 1449 | if (!buffer_mapped(bh) || buffer_freed(bh)) |
1453 | return 0; | 1450 | return 0; |
@@ -1455,27 +1452,24 @@ static int do_journal_get_write_access(handle_t *handle, | |||
1455 | } | 1452 | } |
1456 | 1453 | ||
1457 | static int ext4_write_begin(struct file *file, struct address_space *mapping, | 1454 | static int ext4_write_begin(struct file *file, struct address_space *mapping, |
1458 | loff_t pos, unsigned len, unsigned flags, | 1455 | loff_t pos, unsigned len, unsigned flags, |
1459 | struct page **pagep, void **fsdata) | 1456 | struct page **pagep, void **fsdata) |
1460 | { | 1457 | { |
1461 | struct inode *inode = mapping->host; | 1458 | struct inode *inode = mapping->host; |
1462 | int ret, needed_blocks; | 1459 | int ret, needed_blocks; |
1463 | handle_t *handle; | 1460 | handle_t *handle; |
1464 | int retries = 0; | 1461 | int retries = 0; |
1465 | struct page *page; | 1462 | struct page *page; |
1466 | pgoff_t index; | 1463 | pgoff_t index; |
1467 | unsigned from, to; | 1464 | unsigned from, to; |
1468 | 1465 | ||
1469 | trace_mark(ext4_write_begin, | 1466 | trace_ext4_write_begin(inode, pos, len, flags); |
1470 | "dev %s ino %lu pos %llu len %u flags %u", | ||
1471 | inode->i_sb->s_id, inode->i_ino, | ||
1472 | (unsigned long long) pos, len, flags); | ||
1473 | /* | 1467 | /* |
1474 | * Reserve one block more for addition to orphan list in case | 1468 | * Reserve one block more for addition to orphan list in case |
1475 | * we allocate blocks but write fails for some reason | 1469 | * we allocate blocks but write fails for some reason |
1476 | */ | 1470 | */ |
1477 | needed_blocks = ext4_writepage_trans_blocks(inode) + 1; | 1471 | needed_blocks = ext4_writepage_trans_blocks(inode) + 1; |
1478 | index = pos >> PAGE_CACHE_SHIFT; | 1472 | index = pos >> PAGE_CACHE_SHIFT; |
1479 | from = pos & (PAGE_CACHE_SIZE - 1); | 1473 | from = pos & (PAGE_CACHE_SIZE - 1); |
1480 | to = from + len; | 1474 | to = from + len; |
1481 | 1475 | ||
@@ -1517,14 +1511,14 @@ retry: | |||
1517 | * Add inode to orphan list in case we crash before | 1511 | * Add inode to orphan list in case we crash before |
1518 | * truncate finishes | 1512 | * truncate finishes |
1519 | */ | 1513 | */ |
1520 | if (pos + len > inode->i_size) | 1514 | if (pos + len > inode->i_size && ext4_can_truncate(inode)) |
1521 | ext4_orphan_add(handle, inode); | 1515 | ext4_orphan_add(handle, inode); |
1522 | 1516 | ||
1523 | ext4_journal_stop(handle); | 1517 | ext4_journal_stop(handle); |
1524 | if (pos + len > inode->i_size) { | 1518 | if (pos + len > inode->i_size) { |
1525 | vmtruncate(inode, inode->i_size); | 1519 | ext4_truncate(inode); |
1526 | /* | 1520 | /* |
1527 | * If vmtruncate failed early the inode might | 1521 | * If truncate failed early the inode might |
1528 | * still be on the orphan list; we need to | 1522 | * still be on the orphan list; we need to |
1529 | * make sure the inode is removed from the | 1523 | * make sure the inode is removed from the |
1530 | * orphan list in that case. | 1524 | * orphan list in that case. |
@@ -1550,9 +1544,9 @@ static int write_end_fn(handle_t *handle, struct buffer_head *bh) | |||
1550 | } | 1544 | } |
1551 | 1545 | ||
1552 | static int ext4_generic_write_end(struct file *file, | 1546 | static int ext4_generic_write_end(struct file *file, |
1553 | struct address_space *mapping, | 1547 | struct address_space *mapping, |
1554 | loff_t pos, unsigned len, unsigned copied, | 1548 | loff_t pos, unsigned len, unsigned copied, |
1555 | struct page *page, void *fsdata) | 1549 | struct page *page, void *fsdata) |
1556 | { | 1550 | { |
1557 | int i_size_changed = 0; | 1551 | int i_size_changed = 0; |
1558 | struct inode *inode = mapping->host; | 1552 | struct inode *inode = mapping->host; |
@@ -1603,25 +1597,22 @@ static int ext4_generic_write_end(struct file *file, | |||
1603 | * buffers are managed internally. | 1597 | * buffers are managed internally. |
1604 | */ | 1598 | */ |
1605 | static int ext4_ordered_write_end(struct file *file, | 1599 | static int ext4_ordered_write_end(struct file *file, |
1606 | struct address_space *mapping, | 1600 | struct address_space *mapping, |
1607 | loff_t pos, unsigned len, unsigned copied, | 1601 | loff_t pos, unsigned len, unsigned copied, |
1608 | struct page *page, void *fsdata) | 1602 | struct page *page, void *fsdata) |
1609 | { | 1603 | { |
1610 | handle_t *handle = ext4_journal_current_handle(); | 1604 | handle_t *handle = ext4_journal_current_handle(); |
1611 | struct inode *inode = mapping->host; | 1605 | struct inode *inode = mapping->host; |
1612 | int ret = 0, ret2; | 1606 | int ret = 0, ret2; |
1613 | 1607 | ||
1614 | trace_mark(ext4_ordered_write_end, | 1608 | trace_ext4_ordered_write_end(inode, pos, len, copied); |
1615 | "dev %s ino %lu pos %llu len %u copied %u", | ||
1616 | inode->i_sb->s_id, inode->i_ino, | ||
1617 | (unsigned long long) pos, len, copied); | ||
1618 | ret = ext4_jbd2_file_inode(handle, inode); | 1609 | ret = ext4_jbd2_file_inode(handle, inode); |
1619 | 1610 | ||
1620 | if (ret == 0) { | 1611 | if (ret == 0) { |
1621 | ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, | 1612 | ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, |
1622 | page, fsdata); | 1613 | page, fsdata); |
1623 | copied = ret2; | 1614 | copied = ret2; |
1624 | if (pos + len > inode->i_size) | 1615 | if (pos + len > inode->i_size && ext4_can_truncate(inode)) |
1625 | /* if we have allocated more blocks and copied | 1616 | /* if we have allocated more blocks and copied |
1626 | * less. We will have blocks allocated outside | 1617 | * less. We will have blocks allocated outside |
1627 | * inode->i_size. So truncate them | 1618 | * inode->i_size. So truncate them |
@@ -1635,9 +1626,9 @@ static int ext4_ordered_write_end(struct file *file, | |||
1635 | ret = ret2; | 1626 | ret = ret2; |
1636 | 1627 | ||
1637 | if (pos + len > inode->i_size) { | 1628 | if (pos + len > inode->i_size) { |
1638 | vmtruncate(inode, inode->i_size); | 1629 | ext4_truncate(inode); |
1639 | /* | 1630 | /* |
1640 | * If vmtruncate failed early the inode might still be | 1631 | * If truncate failed early the inode might still be |
1641 | * on the orphan list; we need to make sure the inode | 1632 | * on the orphan list; we need to make sure the inode |
1642 | * is removed from the orphan list in that case. | 1633 | * is removed from the orphan list in that case. |
1643 | */ | 1634 | */ |
@@ -1650,22 +1641,19 @@ static int ext4_ordered_write_end(struct file *file, | |||
1650 | } | 1641 | } |
1651 | 1642 | ||
1652 | static int ext4_writeback_write_end(struct file *file, | 1643 | static int ext4_writeback_write_end(struct file *file, |
1653 | struct address_space *mapping, | 1644 | struct address_space *mapping, |
1654 | loff_t pos, unsigned len, unsigned copied, | 1645 | loff_t pos, unsigned len, unsigned copied, |
1655 | struct page *page, void *fsdata) | 1646 | struct page *page, void *fsdata) |
1656 | { | 1647 | { |
1657 | handle_t *handle = ext4_journal_current_handle(); | 1648 | handle_t *handle = ext4_journal_current_handle(); |
1658 | struct inode *inode = mapping->host; | 1649 | struct inode *inode = mapping->host; |
1659 | int ret = 0, ret2; | 1650 | int ret = 0, ret2; |
1660 | 1651 | ||
1661 | trace_mark(ext4_writeback_write_end, | 1652 | trace_ext4_writeback_write_end(inode, pos, len, copied); |
1662 | "dev %s ino %lu pos %llu len %u copied %u", | ||
1663 | inode->i_sb->s_id, inode->i_ino, | ||
1664 | (unsigned long long) pos, len, copied); | ||
1665 | ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, | 1653 | ret2 = ext4_generic_write_end(file, mapping, pos, len, copied, |
1666 | page, fsdata); | 1654 | page, fsdata); |
1667 | copied = ret2; | 1655 | copied = ret2; |
1668 | if (pos + len > inode->i_size) | 1656 | if (pos + len > inode->i_size && ext4_can_truncate(inode)) |
1669 | /* if we have allocated more blocks and copied | 1657 | /* if we have allocated more blocks and copied |
1670 | * less. We will have blocks allocated outside | 1658 | * less. We will have blocks allocated outside |
1671 | * inode->i_size. So truncate them | 1659 | * inode->i_size. So truncate them |
@@ -1680,9 +1668,9 @@ static int ext4_writeback_write_end(struct file *file, | |||
1680 | ret = ret2; | 1668 | ret = ret2; |
1681 | 1669 | ||
1682 | if (pos + len > inode->i_size) { | 1670 | if (pos + len > inode->i_size) { |
1683 | vmtruncate(inode, inode->i_size); | 1671 | ext4_truncate(inode); |
1684 | /* | 1672 | /* |
1685 | * If vmtruncate failed early the inode might still be | 1673 | * If truncate failed early the inode might still be |
1686 | * on the orphan list; we need to make sure the inode | 1674 | * on the orphan list; we need to make sure the inode |
1687 | * is removed from the orphan list in that case. | 1675 | * is removed from the orphan list in that case. |
1688 | */ | 1676 | */ |
@@ -1694,9 +1682,9 @@ static int ext4_writeback_write_end(struct file *file, | |||
1694 | } | 1682 | } |
1695 | 1683 | ||
1696 | static int ext4_journalled_write_end(struct file *file, | 1684 | static int ext4_journalled_write_end(struct file *file, |
1697 | struct address_space *mapping, | 1685 | struct address_space *mapping, |
1698 | loff_t pos, unsigned len, unsigned copied, | 1686 | loff_t pos, unsigned len, unsigned copied, |
1699 | struct page *page, void *fsdata) | 1687 | struct page *page, void *fsdata) |
1700 | { | 1688 | { |
1701 | handle_t *handle = ext4_journal_current_handle(); | 1689 | handle_t *handle = ext4_journal_current_handle(); |
1702 | struct inode *inode = mapping->host; | 1690 | struct inode *inode = mapping->host; |
@@ -1705,10 +1693,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1705 | unsigned from, to; | 1693 | unsigned from, to; |
1706 | loff_t new_i_size; | 1694 | loff_t new_i_size; |
1707 | 1695 | ||
1708 | trace_mark(ext4_journalled_write_end, | 1696 | trace_ext4_journalled_write_end(inode, pos, len, copied); |
1709 | "dev %s ino %lu pos %llu len %u copied %u", | ||
1710 | inode->i_sb->s_id, inode->i_ino, | ||
1711 | (unsigned long long) pos, len, copied); | ||
1712 | from = pos & (PAGE_CACHE_SIZE - 1); | 1697 | from = pos & (PAGE_CACHE_SIZE - 1); |
1713 | to = from + len; | 1698 | to = from + len; |
1714 | 1699 | ||
@@ -1735,7 +1720,7 @@ static int ext4_journalled_write_end(struct file *file, | |||
1735 | 1720 | ||
1736 | unlock_page(page); | 1721 | unlock_page(page); |
1737 | page_cache_release(page); | 1722 | page_cache_release(page); |
1738 | if (pos + len > inode->i_size) | 1723 | if (pos + len > inode->i_size && ext4_can_truncate(inode)) |
1739 | /* if we have allocated more blocks and copied | 1724 | /* if we have allocated more blocks and copied |
1740 | * less. We will have blocks allocated outside | 1725 | * less. We will have blocks allocated outside |
1741 | * inode->i_size. So truncate them | 1726 | * inode->i_size. So truncate them |
@@ -1746,9 +1731,9 @@ static int ext4_journalled_write_end(struct file *file, | |||
1746 | if (!ret) | 1731 | if (!ret) |
1747 | ret = ret2; | 1732 | ret = ret2; |
1748 | if (pos + len > inode->i_size) { | 1733 | if (pos + len > inode->i_size) { |
1749 | vmtruncate(inode, inode->i_size); | 1734 | ext4_truncate(inode); |
1750 | /* | 1735 | /* |
1751 | * If vmtruncate failed early the inode might still be | 1736 | * If truncate failed early the inode might still be |
1752 | * on the orphan list; we need to make sure the inode | 1737 | * on the orphan list; we need to make sure the inode |
1753 | * is removed from the orphan list in that case. | 1738 | * is removed from the orphan list in that case. |
1754 | */ | 1739 | */ |
@@ -1854,7 +1839,7 @@ static void ext4_da_release_space(struct inode *inode, int to_free) | |||
1854 | } | 1839 | } |
1855 | 1840 | ||
1856 | static void ext4_da_page_release_reservation(struct page *page, | 1841 | static void ext4_da_page_release_reservation(struct page *page, |
1857 | unsigned long offset) | 1842 | unsigned long offset) |
1858 | { | 1843 | { |
1859 | int to_release = 0; | 1844 | int to_release = 0; |
1860 | struct buffer_head *head, *bh; | 1845 | struct buffer_head *head, *bh; |
@@ -2318,15 +2303,9 @@ flush_it: | |||
2318 | return; | 2303 | return; |
2319 | } | 2304 | } |
2320 | 2305 | ||
2321 | static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh) | 2306 | static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh) |
2322 | { | 2307 | { |
2323 | /* | 2308 | return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh); |
2324 | * unmapped buffer is possible for holes. | ||
2325 | * delay buffer is possible with delayed allocation. | ||
2326 | * We also need to consider unwritten buffer as unmapped. | ||
2327 | */ | ||
2328 | return (!buffer_mapped(bh) || buffer_delay(bh) || | ||
2329 | buffer_unwritten(bh)) && buffer_dirty(bh); | ||
2330 | } | 2309 | } |
2331 | 2310 | ||
2332 | /* | 2311 | /* |
@@ -2411,9 +2390,9 @@ static int __mpage_da_writepage(struct page *page, | |||
2411 | * We need to try to allocate | 2390 | * We need to try to allocate |
2412 | * unmapped blocks in the same page. | 2391 | * unmapped blocks in the same page. |
2413 | * Otherwise we won't make progress | 2392 | * Otherwise we won't make progress |
2414 | * with the page in ext4_da_writepage | 2393 | * with the page in ext4_writepage |
2415 | */ | 2394 | */ |
2416 | if (ext4_bh_unmapped_or_delay(NULL, bh)) { | 2395 | if (ext4_bh_delay_or_unwritten(NULL, bh)) { |
2417 | mpage_add_bh_to_extent(mpd, logical, | 2396 | mpage_add_bh_to_extent(mpd, logical, |
2418 | bh->b_size, | 2397 | bh->b_size, |
2419 | bh->b_state); | 2398 | bh->b_state); |
@@ -2530,7 +2509,6 @@ static int noalloc_get_block_write(struct inode *inode, sector_t iblock, | |||
2530 | * so call get_block_wrap with create = 0 | 2509 | * so call get_block_wrap with create = 0 |
2531 | */ | 2510 | */ |
2532 | ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0); | 2511 | ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0); |
2533 | BUG_ON(create && ret == 0); | ||
2534 | if (ret > 0) { | 2512 | if (ret > 0) { |
2535 | bh_result->b_size = (ret << inode->i_blkbits); | 2513 | bh_result->b_size = (ret << inode->i_blkbits); |
2536 | ret = 0; | 2514 | ret = 0; |
@@ -2538,15 +2516,102 @@ static int noalloc_get_block_write(struct inode *inode, sector_t iblock, | |||
2538 | return ret; | 2516 | return ret; |
2539 | } | 2517 | } |
2540 | 2518 | ||
2519 | static int bget_one(handle_t *handle, struct buffer_head *bh) | ||
2520 | { | ||
2521 | get_bh(bh); | ||
2522 | return 0; | ||
2523 | } | ||
2524 | |||
2525 | static int bput_one(handle_t *handle, struct buffer_head *bh) | ||
2526 | { | ||
2527 | put_bh(bh); | ||
2528 | return 0; | ||
2529 | } | ||
2530 | |||
2531 | static int __ext4_journalled_writepage(struct page *page, | ||
2532 | struct writeback_control *wbc, | ||
2533 | unsigned int len) | ||
2534 | { | ||
2535 | struct address_space *mapping = page->mapping; | ||
2536 | struct inode *inode = mapping->host; | ||
2537 | struct buffer_head *page_bufs; | ||
2538 | handle_t *handle = NULL; | ||
2539 | int ret = 0; | ||
2540 | int err; | ||
2541 | |||
2542 | page_bufs = page_buffers(page); | ||
2543 | BUG_ON(!page_bufs); | ||
2544 | walk_page_buffers(handle, page_bufs, 0, len, NULL, bget_one); | ||
2545 | /* As soon as we unlock the page, it can go away, but we have | ||
2546 | * references to buffers so we are safe */ | ||
2547 | unlock_page(page); | ||
2548 | |||
2549 | handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); | ||
2550 | if (IS_ERR(handle)) { | ||
2551 | ret = PTR_ERR(handle); | ||
2552 | goto out; | ||
2553 | } | ||
2554 | |||
2555 | ret = walk_page_buffers(handle, page_bufs, 0, len, NULL, | ||
2556 | do_journal_get_write_access); | ||
2557 | |||
2558 | err = walk_page_buffers(handle, page_bufs, 0, len, NULL, | ||
2559 | write_end_fn); | ||
2560 | if (ret == 0) | ||
2561 | ret = err; | ||
2562 | err = ext4_journal_stop(handle); | ||
2563 | if (!ret) | ||
2564 | ret = err; | ||
2565 | |||
2566 | walk_page_buffers(handle, page_bufs, 0, len, NULL, bput_one); | ||
2567 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; | ||
2568 | out: | ||
2569 | return ret; | ||
2570 | } | ||
2571 | |||
2541 | /* | 2572 | /* |
2573 | * Note that we don't need to start a transaction unless we're journaling data | ||
2574 | * because we should have holes filled from ext4_page_mkwrite(). We even don't | ||
2575 | * need to file the inode to the transaction's list in ordered mode because if | ||
2576 | * we are writing back data added by write(), the inode is already there and if | ||
2577 | * we are writing back data modified via mmap(), noone guarantees in which | ||
2578 | * transaction the data will hit the disk. In case we are journaling data, we | ||
2579 | * cannot start transaction directly because transaction start ranks above page | ||
2580 | * lock so we have to do some magic. | ||
2581 | * | ||
2542 | * This function can get called via... | 2582 | * This function can get called via... |
2543 | * - ext4_da_writepages after taking page lock (have journal handle) | 2583 | * - ext4_da_writepages after taking page lock (have journal handle) |
2544 | * - journal_submit_inode_data_buffers (no journal handle) | 2584 | * - journal_submit_inode_data_buffers (no journal handle) |
2545 | * - shrink_page_list via pdflush (no journal handle) | 2585 | * - shrink_page_list via pdflush (no journal handle) |
2546 | * - grab_page_cache when doing write_begin (have journal handle) | 2586 | * - grab_page_cache when doing write_begin (have journal handle) |
2587 | * | ||
2588 | * We don't do any block allocation in this function. If we have page with | ||
2589 | * multiple blocks we need to write those buffer_heads that are mapped. This | ||
2590 | * is important for mmaped based write. So if we do with blocksize 1K | ||
2591 | * truncate(f, 1024); | ||
2592 | * a = mmap(f, 0, 4096); | ||
2593 | * a[0] = 'a'; | ||
2594 | * truncate(f, 4096); | ||
2595 | * we have in the page first buffer_head mapped via page_mkwrite call back | ||
2596 | * but other bufer_heads would be unmapped but dirty(dirty done via the | ||
2597 | * do_wp_page). So writepage should write the first block. If we modify | ||
2598 | * the mmap area beyond 1024 we will again get a page_fault and the | ||
2599 | * page_mkwrite callback will do the block allocation and mark the | ||
2600 | * buffer_heads mapped. | ||
2601 | * | ||
2602 | * We redirty the page if we have any buffer_heads that is either delay or | ||
2603 | * unwritten in the page. | ||
2604 | * | ||
2605 | * We can get recursively called as show below. | ||
2606 | * | ||
2607 | * ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> | ||
2608 | * ext4_writepage() | ||
2609 | * | ||
2610 | * But since we don't do any block allocation we should not deadlock. | ||
2611 | * Page also have the dirty flag cleared so we don't get recurive page_lock. | ||
2547 | */ | 2612 | */ |
2548 | static int ext4_da_writepage(struct page *page, | 2613 | static int ext4_writepage(struct page *page, |
2549 | struct writeback_control *wbc) | 2614 | struct writeback_control *wbc) |
2550 | { | 2615 | { |
2551 | int ret = 0; | 2616 | int ret = 0; |
2552 | loff_t size; | 2617 | loff_t size; |
@@ -2554,9 +2619,7 @@ static int ext4_da_writepage(struct page *page, | |||
2554 | struct buffer_head *page_bufs; | 2619 | struct buffer_head *page_bufs; |
2555 | struct inode *inode = page->mapping->host; | 2620 | struct inode *inode = page->mapping->host; |
2556 | 2621 | ||
2557 | trace_mark(ext4_da_writepage, | 2622 | trace_ext4_writepage(inode, page); |
2558 | "dev %s ino %lu page_index %lu", | ||
2559 | inode->i_sb->s_id, inode->i_ino, page->index); | ||
2560 | size = i_size_read(inode); | 2623 | size = i_size_read(inode); |
2561 | if (page->index == size >> PAGE_CACHE_SHIFT) | 2624 | if (page->index == size >> PAGE_CACHE_SHIFT) |
2562 | len = size & ~PAGE_CACHE_MASK; | 2625 | len = size & ~PAGE_CACHE_MASK; |
@@ -2566,7 +2629,7 @@ static int ext4_da_writepage(struct page *page, | |||
2566 | if (page_has_buffers(page)) { | 2629 | if (page_has_buffers(page)) { |
2567 | page_bufs = page_buffers(page); | 2630 | page_bufs = page_buffers(page); |
2568 | if (walk_page_buffers(NULL, page_bufs, 0, len, NULL, | 2631 | if (walk_page_buffers(NULL, page_bufs, 0, len, NULL, |
2569 | ext4_bh_unmapped_or_delay)) { | 2632 | ext4_bh_delay_or_unwritten)) { |
2570 | /* | 2633 | /* |
2571 | * We don't want to do block allocation | 2634 | * We don't want to do block allocation |
2572 | * So redirty the page and return | 2635 | * So redirty the page and return |
@@ -2593,13 +2656,13 @@ static int ext4_da_writepage(struct page *page, | |||
2593 | * all are mapped and non delay. We don't want to | 2656 | * all are mapped and non delay. We don't want to |
2594 | * do block allocation here. | 2657 | * do block allocation here. |
2595 | */ | 2658 | */ |
2596 | ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, | 2659 | ret = block_prepare_write(page, 0, len, |
2597 | noalloc_get_block_write); | 2660 | noalloc_get_block_write); |
2598 | if (!ret) { | 2661 | if (!ret) { |
2599 | page_bufs = page_buffers(page); | 2662 | page_bufs = page_buffers(page); |
2600 | /* check whether all are mapped and non delay */ | 2663 | /* check whether all are mapped and non delay */ |
2601 | if (walk_page_buffers(NULL, page_bufs, 0, len, NULL, | 2664 | if (walk_page_buffers(NULL, page_bufs, 0, len, NULL, |
2602 | ext4_bh_unmapped_or_delay)) { | 2665 | ext4_bh_delay_or_unwritten)) { |
2603 | redirty_page_for_writepage(wbc, page); | 2666 | redirty_page_for_writepage(wbc, page); |
2604 | unlock_page(page); | 2667 | unlock_page(page); |
2605 | return 0; | 2668 | return 0; |
@@ -2615,7 +2678,16 @@ static int ext4_da_writepage(struct page *page, | |||
2615 | return 0; | 2678 | return 0; |
2616 | } | 2679 | } |
2617 | /* now mark the buffer_heads as dirty and uptodate */ | 2680 | /* now mark the buffer_heads as dirty and uptodate */ |
2618 | block_commit_write(page, 0, PAGE_CACHE_SIZE); | 2681 | block_commit_write(page, 0, len); |
2682 | } | ||
2683 | |||
2684 | if (PageChecked(page) && ext4_should_journal_data(inode)) { | ||
2685 | /* | ||
2686 | * It's mmapped pagecache. Add buffers and journal it. There | ||
2687 | * doesn't seem much point in redirtying the page here. | ||
2688 | */ | ||
2689 | ClearPageChecked(page); | ||
2690 | return __ext4_journalled_writepage(page, wbc, len); | ||
2619 | } | 2691 | } |
2620 | 2692 | ||
2621 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) | 2693 | if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode)) |
@@ -2667,19 +2739,7 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
2667 | int needed_blocks, ret = 0, nr_to_writebump = 0; | 2739 | int needed_blocks, ret = 0, nr_to_writebump = 0; |
2668 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); | 2740 | struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); |
2669 | 2741 | ||
2670 | trace_mark(ext4_da_writepages, | 2742 | trace_ext4_da_writepages(inode, wbc); |
2671 | "dev %s ino %lu nr_t_write %ld " | ||
2672 | "pages_skipped %ld range_start %llu " | ||
2673 | "range_end %llu nonblocking %d " | ||
2674 | "for_kupdate %d for_reclaim %d " | ||
2675 | "for_writepages %d range_cyclic %d", | ||
2676 | inode->i_sb->s_id, inode->i_ino, | ||
2677 | wbc->nr_to_write, wbc->pages_skipped, | ||
2678 | (unsigned long long) wbc->range_start, | ||
2679 | (unsigned long long) wbc->range_end, | ||
2680 | wbc->nonblocking, wbc->for_kupdate, | ||
2681 | wbc->for_reclaim, wbc->for_writepages, | ||
2682 | wbc->range_cyclic); | ||
2683 | 2743 | ||
2684 | /* | 2744 | /* |
2685 | * No pages to write? This is mainly a kludge to avoid starting | 2745 | * No pages to write? This is mainly a kludge to avoid starting |
@@ -2693,13 +2753,13 @@ static int ext4_da_writepages(struct address_space *mapping, | |||
2693 | * If the filesystem has aborted, it is read-only, so return | 2753 | * If the filesystem has aborted, it is read-only, so return |
2694 | * right away instead of dumping stack traces later on that | 2754 | * right away instead of dumping stack traces later on that |
2695 | * will obscure the real source of the problem. We test | 2755 | * will obscure the real source of the problem. We test |
2696 | * EXT4_MOUNT_ABORT instead of sb->s_flag's MS_RDONLY because | 2756 | * EXT4_MF_FS_ABORTED instead of sb->s_flag's MS_RDONLY because |
2697 | * the latter could be true if the filesystem is mounted | 2757 | * the latter could be true if the filesystem is mounted |
2698 | * read-only, and in that case, ext4_da_writepages should | 2758 | * read-only, and in that case, ext4_da_writepages should |
2699 | * *never* be called, so if that ever happens, we would want | 2759 | * *never* be called, so if that ever happens, we would want |
2700 | * the stack trace. | 2760 | * the stack trace. |
2701 | */ | 2761 | */ |
2702 | if (unlikely(sbi->s_mount_opt & EXT4_MOUNT_ABORT)) | 2762 | if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) |
2703 | return -EROFS; | 2763 | return -EROFS; |
2704 | 2764 | ||
2705 | /* | 2765 | /* |
@@ -2845,14 +2905,7 @@ out_writepages: | |||
2845 | if (!no_nrwrite_index_update) | 2905 | if (!no_nrwrite_index_update) |
2846 | wbc->no_nrwrite_index_update = 0; | 2906 | wbc->no_nrwrite_index_update = 0; |
2847 | wbc->nr_to_write -= nr_to_writebump; | 2907 | wbc->nr_to_write -= nr_to_writebump; |
2848 | trace_mark(ext4_da_writepage_result, | 2908 | trace_ext4_da_writepages_result(inode, wbc, ret, pages_written); |
2849 | "dev %s ino %lu ret %d pages_written %d " | ||
2850 | "pages_skipped %ld congestion %d " | ||
2851 | "more_io %d no_nrwrite_index_update %d", | ||
2852 | inode->i_sb->s_id, inode->i_ino, ret, | ||
2853 | pages_written, wbc->pages_skipped, | ||
2854 | wbc->encountered_congestion, wbc->more_io, | ||
2855 | wbc->no_nrwrite_index_update); | ||
2856 | return ret; | 2909 | return ret; |
2857 | } | 2910 | } |
2858 | 2911 | ||
@@ -2884,8 +2937,8 @@ static int ext4_nonda_switch(struct super_block *sb) | |||
2884 | } | 2937 | } |
2885 | 2938 | ||
2886 | static int ext4_da_write_begin(struct file *file, struct address_space *mapping, | 2939 | static int ext4_da_write_begin(struct file *file, struct address_space *mapping, |
2887 | loff_t pos, unsigned len, unsigned flags, | 2940 | loff_t pos, unsigned len, unsigned flags, |
2888 | struct page **pagep, void **fsdata) | 2941 | struct page **pagep, void **fsdata) |
2889 | { | 2942 | { |
2890 | int ret, retries = 0; | 2943 | int ret, retries = 0; |
2891 | struct page *page; | 2944 | struct page *page; |
@@ -2904,11 +2957,7 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping, | |||
2904 | len, flags, pagep, fsdata); | 2957 | len, flags, pagep, fsdata); |
2905 | } | 2958 | } |
2906 | *fsdata = (void *)0; | 2959 | *fsdata = (void *)0; |
2907 | 2960 | trace_ext4_da_write_begin(inode, pos, len, flags); | |
2908 | trace_mark(ext4_da_write_begin, | ||
2909 | "dev %s ino %lu pos %llu len %u flags %u", | ||
2910 | inode->i_sb->s_id, inode->i_ino, | ||
2911 | (unsigned long long) pos, len, flags); | ||
2912 | retry: | 2961 | retry: |
2913 | /* | 2962 | /* |
2914 | * With delayed allocation, we don't log the i_disksize update | 2963 | * With delayed allocation, we don't log the i_disksize update |
@@ -2945,7 +2994,7 @@ retry: | |||
2945 | * i_size_read because we hold i_mutex. | 2994 | * i_size_read because we hold i_mutex. |
2946 | */ | 2995 | */ |
2947 | if (pos + len > inode->i_size) | 2996 | if (pos + len > inode->i_size) |
2948 | vmtruncate(inode, inode->i_size); | 2997 | ext4_truncate(inode); |
2949 | } | 2998 | } |
2950 | 2999 | ||
2951 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | 3000 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) |
@@ -2959,7 +3008,7 @@ out: | |||
2959 | * when write to the end of file but not require block allocation | 3008 | * when write to the end of file but not require block allocation |
2960 | */ | 3009 | */ |
2961 | static int ext4_da_should_update_i_disksize(struct page *page, | 3010 | static int ext4_da_should_update_i_disksize(struct page *page, |
2962 | unsigned long offset) | 3011 | unsigned long offset) |
2963 | { | 3012 | { |
2964 | struct buffer_head *bh; | 3013 | struct buffer_head *bh; |
2965 | struct inode *inode = page->mapping->host; | 3014 | struct inode *inode = page->mapping->host; |
@@ -2978,9 +3027,9 @@ static int ext4_da_should_update_i_disksize(struct page *page, | |||
2978 | } | 3027 | } |
2979 | 3028 | ||
2980 | static int ext4_da_write_end(struct file *file, | 3029 | static int ext4_da_write_end(struct file *file, |
2981 | struct address_space *mapping, | 3030 | struct address_space *mapping, |
2982 | loff_t pos, unsigned len, unsigned copied, | 3031 | loff_t pos, unsigned len, unsigned copied, |
2983 | struct page *page, void *fsdata) | 3032 | struct page *page, void *fsdata) |
2984 | { | 3033 | { |
2985 | struct inode *inode = mapping->host; | 3034 | struct inode *inode = mapping->host; |
2986 | int ret = 0, ret2; | 3035 | int ret = 0, ret2; |
@@ -3001,10 +3050,7 @@ static int ext4_da_write_end(struct file *file, | |||
3001 | } | 3050 | } |
3002 | } | 3051 | } |
3003 | 3052 | ||
3004 | trace_mark(ext4_da_write_end, | 3053 | trace_ext4_da_write_end(inode, pos, len, copied); |
3005 | "dev %s ino %lu pos %llu len %u copied %u", | ||
3006 | inode->i_sb->s_id, inode->i_ino, | ||
3007 | (unsigned long long) pos, len, copied); | ||
3008 | start = pos & (PAGE_CACHE_SIZE - 1); | 3054 | start = pos & (PAGE_CACHE_SIZE - 1); |
3009 | end = start + copied - 1; | 3055 | end = start + copied - 1; |
3010 | 3056 | ||
@@ -3081,7 +3127,7 @@ int ext4_alloc_da_blocks(struct inode *inode) | |||
3081 | * not strictly speaking necessary (and for users of | 3127 | * not strictly speaking necessary (and for users of |
3082 | * laptop_mode, not even desirable). However, to do otherwise | 3128 | * laptop_mode, not even desirable). However, to do otherwise |
3083 | * would require replicating code paths in: | 3129 | * would require replicating code paths in: |
3084 | * | 3130 | * |
3085 | * ext4_da_writepages() -> | 3131 | * ext4_da_writepages() -> |
3086 | * write_cache_pages() ---> (via passed in callback function) | 3132 | * write_cache_pages() ---> (via passed in callback function) |
3087 | * __mpage_da_writepage() --> | 3133 | * __mpage_da_writepage() --> |
@@ -3101,7 +3147,7 @@ int ext4_alloc_da_blocks(struct inode *inode) | |||
3101 | * write out the pages, but rather only collect contiguous | 3147 | * write out the pages, but rather only collect contiguous |
3102 | * logical block extents, call the multi-block allocator, and | 3148 | * logical block extents, call the multi-block allocator, and |
3103 | * then update the buffer heads with the block allocations. | 3149 | * then update the buffer heads with the block allocations. |
3104 | * | 3150 | * |
3105 | * For now, though, we'll cheat by calling filemap_flush(), | 3151 | * For now, though, we'll cheat by calling filemap_flush(), |
3106 | * which will map the blocks, and start the I/O, but not | 3152 | * which will map the blocks, and start the I/O, but not |
3107 | * actually wait for the I/O to complete. | 3153 | * actually wait for the I/O to complete. |
@@ -3171,226 +3217,6 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) | |||
3171 | return generic_block_bmap(mapping, block, ext4_get_block); | 3217 | return generic_block_bmap(mapping, block, ext4_get_block); |
3172 | } | 3218 | } |
3173 | 3219 | ||
3174 | static int bget_one(handle_t *handle, struct buffer_head *bh) | ||
3175 | { | ||
3176 | get_bh(bh); | ||
3177 | return 0; | ||
3178 | } | ||
3179 | |||
3180 | static int bput_one(handle_t *handle, struct buffer_head *bh) | ||
3181 | { | ||
3182 | put_bh(bh); | ||
3183 | return 0; | ||
3184 | } | ||
3185 | |||
3186 | /* | ||
3187 | * Note that we don't need to start a transaction unless we're journaling data | ||
3188 | * because we should have holes filled from ext4_page_mkwrite(). We even don't | ||
3189 | * need to file the inode to the transaction's list in ordered mode because if | ||
3190 | * we are writing back data added by write(), the inode is already there and if | ||
3191 | * we are writing back data modified via mmap(), noone guarantees in which | ||
3192 | * transaction the data will hit the disk. In case we are journaling data, we | ||
3193 | * cannot start transaction directly because transaction start ranks above page | ||
3194 | * lock so we have to do some magic. | ||
3195 | * | ||
3196 | * In all journaling modes block_write_full_page() will start the I/O. | ||
3197 | * | ||
3198 | * Problem: | ||
3199 | * | ||
3200 | * ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> | ||
3201 | * ext4_writepage() | ||
3202 | * | ||
3203 | * Similar for: | ||
3204 | * | ||
3205 | * ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ... | ||
3206 | * | ||
3207 | * Same applies to ext4_get_block(). We will deadlock on various things like | ||
3208 | * lock_journal and i_data_sem | ||
3209 | * | ||
3210 | * Setting PF_MEMALLOC here doesn't work - too many internal memory | ||
3211 | * allocations fail. | ||
3212 | * | ||
3213 | * 16May01: If we're reentered then journal_current_handle() will be | ||
3214 | * non-zero. We simply *return*. | ||
3215 | * | ||
3216 | * 1 July 2001: @@@ FIXME: | ||
3217 | * In journalled data mode, a data buffer may be metadata against the | ||
3218 | * current transaction. But the same file is part of a shared mapping | ||
3219 | * and someone does a writepage() on it. | ||
3220 | * | ||
3221 | * We will move the buffer onto the async_data list, but *after* it has | ||
3222 | * been dirtied. So there's a small window where we have dirty data on | ||
3223 | * BJ_Metadata. | ||
3224 | * | ||
3225 | * Note that this only applies to the last partial page in the file. The | ||
3226 | * bit which block_write_full_page() uses prepare/commit for. (That's | ||
3227 | * broken code anyway: it's wrong for msync()). | ||
3228 | * | ||
3229 | * It's a rare case: affects the final partial page, for journalled data | ||
3230 | * where the file is subject to bith write() and writepage() in the same | ||
3231 | * transction. To fix it we'll need a custom block_write_full_page(). | ||
3232 | * We'll probably need that anyway for journalling writepage() output. | ||
3233 | * | ||
3234 | * We don't honour synchronous mounts for writepage(). That would be | ||
3235 | * disastrous. Any write() or metadata operation will sync the fs for | ||
3236 | * us. | ||
3237 | * | ||
3238 | */ | ||
3239 | static int __ext4_normal_writepage(struct page *page, | ||
3240 | struct writeback_control *wbc) | ||
3241 | { | ||
3242 | struct inode *inode = page->mapping->host; | ||
3243 | |||
3244 | if (test_opt(inode->i_sb, NOBH)) | ||
3245 | return nobh_writepage(page, noalloc_get_block_write, wbc); | ||
3246 | else | ||
3247 | return block_write_full_page(page, noalloc_get_block_write, | ||
3248 | wbc); | ||
3249 | } | ||
3250 | |||
3251 | static int ext4_normal_writepage(struct page *page, | ||
3252 | struct writeback_control *wbc) | ||
3253 | { | ||
3254 | struct inode *inode = page->mapping->host; | ||
3255 | loff_t size = i_size_read(inode); | ||
3256 | loff_t len; | ||
3257 | |||
3258 | trace_mark(ext4_normal_writepage, | ||
3259 | "dev %s ino %lu page_index %lu", | ||
3260 | inode->i_sb->s_id, inode->i_ino, page->index); | ||
3261 | J_ASSERT(PageLocked(page)); | ||
3262 | if (page->index == size >> PAGE_CACHE_SHIFT) | ||
3263 | len = size & ~PAGE_CACHE_MASK; | ||
3264 | else | ||
3265 | len = PAGE_CACHE_SIZE; | ||
3266 | |||
3267 | if (page_has_buffers(page)) { | ||
3268 | /* if page has buffers it should all be mapped | ||
3269 | * and allocated. If there are not buffers attached | ||
3270 | * to the page we know the page is dirty but it lost | ||
3271 | * buffers. That means that at some moment in time | ||
3272 | * after write_begin() / write_end() has been called | ||
3273 | * all buffers have been clean and thus they must have been | ||
3274 | * written at least once. So they are all mapped and we can | ||
3275 | * happily proceed with mapping them and writing the page. | ||
3276 | */ | ||
3277 | BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, | ||
3278 | ext4_bh_unmapped_or_delay)); | ||
3279 | } | ||
3280 | |||
3281 | if (!ext4_journal_current_handle()) | ||
3282 | return __ext4_normal_writepage(page, wbc); | ||
3283 | |||
3284 | redirty_page_for_writepage(wbc, page); | ||
3285 | unlock_page(page); | ||
3286 | return 0; | ||
3287 | } | ||
3288 | |||
3289 | static int __ext4_journalled_writepage(struct page *page, | ||
3290 | struct writeback_control *wbc) | ||
3291 | { | ||
3292 | struct address_space *mapping = page->mapping; | ||
3293 | struct inode *inode = mapping->host; | ||
3294 | struct buffer_head *page_bufs; | ||
3295 | handle_t *handle = NULL; | ||
3296 | int ret = 0; | ||
3297 | int err; | ||
3298 | |||
3299 | ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE, | ||
3300 | noalloc_get_block_write); | ||
3301 | if (ret != 0) | ||
3302 | goto out_unlock; | ||
3303 | |||
3304 | page_bufs = page_buffers(page); | ||
3305 | walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL, | ||
3306 | bget_one); | ||
3307 | /* As soon as we unlock the page, it can go away, but we have | ||
3308 | * references to buffers so we are safe */ | ||
3309 | unlock_page(page); | ||
3310 | |||
3311 | handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode)); | ||
3312 | if (IS_ERR(handle)) { | ||
3313 | ret = PTR_ERR(handle); | ||
3314 | goto out; | ||
3315 | } | ||
3316 | |||
3317 | ret = walk_page_buffers(handle, page_bufs, 0, | ||
3318 | PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); | ||
3319 | |||
3320 | err = walk_page_buffers(handle, page_bufs, 0, | ||
3321 | PAGE_CACHE_SIZE, NULL, write_end_fn); | ||
3322 | if (ret == 0) | ||
3323 | ret = err; | ||
3324 | err = ext4_journal_stop(handle); | ||
3325 | if (!ret) | ||
3326 | ret = err; | ||
3327 | |||
3328 | walk_page_buffers(handle, page_bufs, 0, | ||
3329 | PAGE_CACHE_SIZE, NULL, bput_one); | ||
3330 | EXT4_I(inode)->i_state |= EXT4_STATE_JDATA; | ||
3331 | goto out; | ||
3332 | |||
3333 | out_unlock: | ||
3334 | unlock_page(page); | ||
3335 | out: | ||
3336 | return ret; | ||
3337 | } | ||
3338 | |||
3339 | static int ext4_journalled_writepage(struct page *page, | ||
3340 | struct writeback_control *wbc) | ||
3341 | { | ||
3342 | struct inode *inode = page->mapping->host; | ||
3343 | loff_t size = i_size_read(inode); | ||
3344 | loff_t len; | ||
3345 | |||
3346 | trace_mark(ext4_journalled_writepage, | ||
3347 | "dev %s ino %lu page_index %lu", | ||
3348 | inode->i_sb->s_id, inode->i_ino, page->index); | ||
3349 | J_ASSERT(PageLocked(page)); | ||
3350 | if (page->index == size >> PAGE_CACHE_SHIFT) | ||
3351 | len = size & ~PAGE_CACHE_MASK; | ||
3352 | else | ||
3353 | len = PAGE_CACHE_SIZE; | ||
3354 | |||
3355 | if (page_has_buffers(page)) { | ||
3356 | /* if page has buffers it should all be mapped | ||
3357 | * and allocated. If there are not buffers attached | ||
3358 | * to the page we know the page is dirty but it lost | ||
3359 | * buffers. That means that at some moment in time | ||
3360 | * after write_begin() / write_end() has been called | ||
3361 | * all buffers have been clean and thus they must have been | ||
3362 | * written at least once. So they are all mapped and we can | ||
3363 | * happily proceed with mapping them and writing the page. | ||
3364 | */ | ||
3365 | BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, | ||
3366 | ext4_bh_unmapped_or_delay)); | ||
3367 | } | ||
3368 | |||
3369 | if (ext4_journal_current_handle()) | ||
3370 | goto no_write; | ||
3371 | |||
3372 | if (PageChecked(page)) { | ||
3373 | /* | ||
3374 | * It's mmapped pagecache. Add buffers and journal it. There | ||
3375 | * doesn't seem much point in redirtying the page here. | ||
3376 | */ | ||
3377 | ClearPageChecked(page); | ||
3378 | return __ext4_journalled_writepage(page, wbc); | ||
3379 | } else { | ||
3380 | /* | ||
3381 | * It may be a page full of checkpoint-mode buffers. We don't | ||
3382 | * really know unless we go poke around in the buffer_heads. | ||
3383 | * But block_write_full_page will do the right thing. | ||
3384 | */ | ||
3385 | return block_write_full_page(page, noalloc_get_block_write, | ||
3386 | wbc); | ||
3387 | } | ||
3388 | no_write: | ||
3389 | redirty_page_for_writepage(wbc, page); | ||
3390 | unlock_page(page); | ||
3391 | return 0; | ||
3392 | } | ||
3393 | |||
3394 | static int ext4_readpage(struct file *file, struct page *page) | 3220 | static int ext4_readpage(struct file *file, struct page *page) |
3395 | { | 3221 | { |
3396 | return mpage_readpage(page, ext4_get_block); | 3222 | return mpage_readpage(page, ext4_get_block); |
@@ -3442,8 +3268,8 @@ static int ext4_releasepage(struct page *page, gfp_t wait) | |||
3442 | * VFS code falls back into buffered path in that case so we are safe. | 3268 | * VFS code falls back into buffered path in that case so we are safe. |
3443 | */ | 3269 | */ |
3444 | static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, | 3270 | static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, |
3445 | const struct iovec *iov, loff_t offset, | 3271 | const struct iovec *iov, loff_t offset, |
3446 | unsigned long nr_segs) | 3272 | unsigned long nr_segs) |
3447 | { | 3273 | { |
3448 | struct file *file = iocb->ki_filp; | 3274 | struct file *file = iocb->ki_filp; |
3449 | struct inode *inode = file->f_mapping->host; | 3275 | struct inode *inode = file->f_mapping->host; |
@@ -3537,7 +3363,7 @@ static int ext4_journalled_set_page_dirty(struct page *page) | |||
3537 | static const struct address_space_operations ext4_ordered_aops = { | 3363 | static const struct address_space_operations ext4_ordered_aops = { |
3538 | .readpage = ext4_readpage, | 3364 | .readpage = ext4_readpage, |
3539 | .readpages = ext4_readpages, | 3365 | .readpages = ext4_readpages, |
3540 | .writepage = ext4_normal_writepage, | 3366 | .writepage = ext4_writepage, |
3541 | .sync_page = block_sync_page, | 3367 | .sync_page = block_sync_page, |
3542 | .write_begin = ext4_write_begin, | 3368 | .write_begin = ext4_write_begin, |
3543 | .write_end = ext4_ordered_write_end, | 3369 | .write_end = ext4_ordered_write_end, |
@@ -3552,7 +3378,7 @@ static const struct address_space_operations ext4_ordered_aops = { | |||
3552 | static const struct address_space_operations ext4_writeback_aops = { | 3378 | static const struct address_space_operations ext4_writeback_aops = { |
3553 | .readpage = ext4_readpage, | 3379 | .readpage = ext4_readpage, |
3554 | .readpages = ext4_readpages, | 3380 | .readpages = ext4_readpages, |
3555 | .writepage = ext4_normal_writepage, | 3381 | .writepage = ext4_writepage, |
3556 | .sync_page = block_sync_page, | 3382 | .sync_page = block_sync_page, |
3557 | .write_begin = ext4_write_begin, | 3383 | .write_begin = ext4_write_begin, |
3558 | .write_end = ext4_writeback_write_end, | 3384 | .write_end = ext4_writeback_write_end, |
@@ -3567,7 +3393,7 @@ static const struct address_space_operations ext4_writeback_aops = { | |||
3567 | static const struct address_space_operations ext4_journalled_aops = { | 3393 | static const struct address_space_operations ext4_journalled_aops = { |
3568 | .readpage = ext4_readpage, | 3394 | .readpage = ext4_readpage, |
3569 | .readpages = ext4_readpages, | 3395 | .readpages = ext4_readpages, |
3570 | .writepage = ext4_journalled_writepage, | 3396 | .writepage = ext4_writepage, |
3571 | .sync_page = block_sync_page, | 3397 | .sync_page = block_sync_page, |
3572 | .write_begin = ext4_write_begin, | 3398 | .write_begin = ext4_write_begin, |
3573 | .write_end = ext4_journalled_write_end, | 3399 | .write_end = ext4_journalled_write_end, |
@@ -3581,7 +3407,7 @@ static const struct address_space_operations ext4_journalled_aops = { | |||
3581 | static const struct address_space_operations ext4_da_aops = { | 3407 | static const struct address_space_operations ext4_da_aops = { |
3582 | .readpage = ext4_readpage, | 3408 | .readpage = ext4_readpage, |
3583 | .readpages = ext4_readpages, | 3409 | .readpages = ext4_readpages, |
3584 | .writepage = ext4_da_writepage, | 3410 | .writepage = ext4_writepage, |
3585 | .writepages = ext4_da_writepages, | 3411 | .writepages = ext4_da_writepages, |
3586 | .sync_page = block_sync_page, | 3412 | .sync_page = block_sync_page, |
3587 | .write_begin = ext4_da_write_begin, | 3413 | .write_begin = ext4_da_write_begin, |
@@ -3628,7 +3454,8 @@ int ext4_block_truncate_page(handle_t *handle, | |||
3628 | struct page *page; | 3454 | struct page *page; |
3629 | int err = 0; | 3455 | int err = 0; |
3630 | 3456 | ||
3631 | page = grab_cache_page(mapping, from >> PAGE_CACHE_SHIFT); | 3457 | page = find_or_create_page(mapping, from >> PAGE_CACHE_SHIFT, |
3458 | mapping_gfp_mask(mapping) & ~__GFP_FS); | ||
3632 | if (!page) | 3459 | if (!page) |
3633 | return -EINVAL; | 3460 | return -EINVAL; |
3634 | 3461 | ||
@@ -3763,7 +3590,8 @@ static inline int all_zeroes(__le32 *p, __le32 *q) | |||
3763 | * (no partially truncated stuff there). */ | 3590 | * (no partially truncated stuff there). */ |
3764 | 3591 | ||
3765 | static Indirect *ext4_find_shared(struct inode *inode, int depth, | 3592 | static Indirect *ext4_find_shared(struct inode *inode, int depth, |
3766 | ext4_lblk_t offsets[4], Indirect chain[4], __le32 *top) | 3593 | ext4_lblk_t offsets[4], Indirect chain[4], |
3594 | __le32 *top) | ||
3767 | { | 3595 | { |
3768 | Indirect *partial, *p; | 3596 | Indirect *partial, *p; |
3769 | int k, err; | 3597 | int k, err; |
@@ -3819,8 +3647,10 @@ no_top: | |||
3819 | * than `count' because there can be holes in there. | 3647 | * than `count' because there can be holes in there. |
3820 | */ | 3648 | */ |
3821 | static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | 3649 | static void ext4_clear_blocks(handle_t *handle, struct inode *inode, |
3822 | struct buffer_head *bh, ext4_fsblk_t block_to_free, | 3650 | struct buffer_head *bh, |
3823 | unsigned long count, __le32 *first, __le32 *last) | 3651 | ext4_fsblk_t block_to_free, |
3652 | unsigned long count, __le32 *first, | ||
3653 | __le32 *last) | ||
3824 | { | 3654 | { |
3825 | __le32 *p; | 3655 | __le32 *p; |
3826 | if (try_to_extend_transaction(handle, inode)) { | 3656 | if (try_to_extend_transaction(handle, inode)) { |
@@ -3837,10 +3667,11 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode, | |||
3837 | } | 3667 | } |
3838 | 3668 | ||
3839 | /* | 3669 | /* |
3840 | * Any buffers which are on the journal will be in memory. We find | 3670 | * Any buffers which are on the journal will be in memory. We |
3841 | * them on the hash table so jbd2_journal_revoke() will run jbd2_journal_forget() | 3671 | * find them on the hash table so jbd2_journal_revoke() will |
3842 | * on them. We've already detached each block from the file, so | 3672 | * run jbd2_journal_forget() on them. We've already detached |
3843 | * bforget() in jbd2_journal_forget() should be safe. | 3673 | * each block from the file, so bforget() in |
3674 | * jbd2_journal_forget() should be safe. | ||
3844 | * | 3675 | * |
3845 | * AKPM: turn on bforget in jbd2_journal_forget()!!! | 3676 | * AKPM: turn on bforget in jbd2_journal_forget()!!! |
3846 | */ | 3677 | */ |
@@ -4212,7 +4043,7 @@ void ext4_truncate(struct inode *inode) | |||
4212 | (__le32*)partial->bh->b_data+addr_per_block, | 4043 | (__le32*)partial->bh->b_data+addr_per_block, |
4213 | (chain+n-1) - partial); | 4044 | (chain+n-1) - partial); |
4214 | BUFFER_TRACE(partial->bh, "call brelse"); | 4045 | BUFFER_TRACE(partial->bh, "call brelse"); |
4215 | brelse (partial->bh); | 4046 | brelse(partial->bh); |
4216 | partial--; | 4047 | partial--; |
4217 | } | 4048 | } |
4218 | do_indirects: | 4049 | do_indirects: |
@@ -4453,8 +4284,9 @@ void ext4_get_inode_flags(struct ext4_inode_info *ei) | |||
4453 | if (flags & S_DIRSYNC) | 4284 | if (flags & S_DIRSYNC) |
4454 | ei->i_flags |= EXT4_DIRSYNC_FL; | 4285 | ei->i_flags |= EXT4_DIRSYNC_FL; |
4455 | } | 4286 | } |
4287 | |||
4456 | static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, | 4288 | static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, |
4457 | struct ext4_inode_info *ei) | 4289 | struct ext4_inode_info *ei) |
4458 | { | 4290 | { |
4459 | blkcnt_t i_blocks ; | 4291 | blkcnt_t i_blocks ; |
4460 | struct inode *inode = &(ei->vfs_inode); | 4292 | struct inode *inode = &(ei->vfs_inode); |
@@ -4493,10 +4325,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4493 | return inode; | 4325 | return inode; |
4494 | 4326 | ||
4495 | ei = EXT4_I(inode); | 4327 | ei = EXT4_I(inode); |
4496 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
4497 | ei->i_acl = EXT4_ACL_NOT_CACHED; | ||
4498 | ei->i_default_acl = EXT4_ACL_NOT_CACHED; | ||
4499 | #endif | ||
4500 | 4328 | ||
4501 | ret = __ext4_get_inode_loc(inode, &iloc, 0); | 4329 | ret = __ext4_get_inode_loc(inode, &iloc, 0); |
4502 | if (ret < 0) | 4330 | if (ret < 0) |
@@ -4569,7 +4397,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4569 | EXT4_GOOD_OLD_INODE_SIZE + | 4397 | EXT4_GOOD_OLD_INODE_SIZE + |
4570 | ei->i_extra_isize; | 4398 | ei->i_extra_isize; |
4571 | if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) | 4399 | if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) |
4572 | ei->i_state |= EXT4_STATE_XATTR; | 4400 | ei->i_state |= EXT4_STATE_XATTR; |
4573 | } | 4401 | } |
4574 | } else | 4402 | } else |
4575 | ei->i_extra_isize = 0; | 4403 | ei->i_extra_isize = 0; |
@@ -4588,7 +4416,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4588 | 4416 | ||
4589 | ret = 0; | 4417 | ret = 0; |
4590 | if (ei->i_file_acl && | 4418 | if (ei->i_file_acl && |
4591 | ((ei->i_file_acl < | 4419 | ((ei->i_file_acl < |
4592 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + | 4420 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + |
4593 | EXT4_SB(sb)->s_gdb_count)) || | 4421 | EXT4_SB(sb)->s_gdb_count)) || |
4594 | (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { | 4422 | (ei->i_file_acl >= ext4_blocks_count(EXT4_SB(sb)->s_es)))) { |
@@ -4603,15 +4431,15 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4603 | !ext4_inode_is_fast_symlink(inode))) | 4431 | !ext4_inode_is_fast_symlink(inode))) |
4604 | /* Validate extent which is part of inode */ | 4432 | /* Validate extent which is part of inode */ |
4605 | ret = ext4_ext_check_inode(inode); | 4433 | ret = ext4_ext_check_inode(inode); |
4606 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 4434 | } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
4607 | (S_ISLNK(inode->i_mode) && | 4435 | (S_ISLNK(inode->i_mode) && |
4608 | !ext4_inode_is_fast_symlink(inode))) { | 4436 | !ext4_inode_is_fast_symlink(inode))) { |
4609 | /* Validate block references which are part of inode */ | 4437 | /* Validate block references which are part of inode */ |
4610 | ret = ext4_check_inode_blockref(inode); | 4438 | ret = ext4_check_inode_blockref(inode); |
4611 | } | 4439 | } |
4612 | if (ret) { | 4440 | if (ret) { |
4613 | brelse(bh); | 4441 | brelse(bh); |
4614 | goto bad_inode; | 4442 | goto bad_inode; |
4615 | } | 4443 | } |
4616 | 4444 | ||
4617 | if (S_ISREG(inode->i_mode)) { | 4445 | if (S_ISREG(inode->i_mode)) { |
@@ -4642,7 +4470,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4642 | } else { | 4470 | } else { |
4643 | brelse(bh); | 4471 | brelse(bh); |
4644 | ret = -EIO; | 4472 | ret = -EIO; |
4645 | ext4_error(inode->i_sb, __func__, | 4473 | ext4_error(inode->i_sb, __func__, |
4646 | "bogus i_mode (%o) for inode=%lu", | 4474 | "bogus i_mode (%o) for inode=%lu", |
4647 | inode->i_mode, inode->i_ino); | 4475 | inode->i_mode, inode->i_ino); |
4648 | goto bad_inode; | 4476 | goto bad_inode; |
@@ -4795,8 +4623,9 @@ static int ext4_do_update_inode(handle_t *handle, | |||
4795 | cpu_to_le32(new_encode_dev(inode->i_rdev)); | 4623 | cpu_to_le32(new_encode_dev(inode->i_rdev)); |
4796 | raw_inode->i_block[2] = 0; | 4624 | raw_inode->i_block[2] = 0; |
4797 | } | 4625 | } |
4798 | } else for (block = 0; block < EXT4_N_BLOCKS; block++) | 4626 | } else |
4799 | raw_inode->i_block[block] = ei->i_data[block]; | 4627 | for (block = 0; block < EXT4_N_BLOCKS; block++) |
4628 | raw_inode->i_block[block] = ei->i_data[block]; | ||
4800 | 4629 | ||
4801 | raw_inode->i_disk_version = cpu_to_le32(inode->i_version); | 4630 | raw_inode->i_disk_version = cpu_to_le32(inode->i_version); |
4802 | if (ei->i_extra_isize) { | 4631 | if (ei->i_extra_isize) { |
@@ -5150,7 +4979,7 @@ int ext4_chunk_trans_blocks(struct inode *inode, int nrblocks) | |||
5150 | * Give this, we know that the caller already has write access to iloc->bh. | 4979 | * Give this, we know that the caller already has write access to iloc->bh. |
5151 | */ | 4980 | */ |
5152 | int ext4_mark_iloc_dirty(handle_t *handle, | 4981 | int ext4_mark_iloc_dirty(handle_t *handle, |
5153 | struct inode *inode, struct ext4_iloc *iloc) | 4982 | struct inode *inode, struct ext4_iloc *iloc) |
5154 | { | 4983 | { |
5155 | int err = 0; | 4984 | int err = 0; |
5156 | 4985 | ||
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 91e75f7a9e73..7050a9cd04a4 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -12,8 +12,8 @@ | |||
12 | #include <linux/capability.h> | 12 | #include <linux/capability.h> |
13 | #include <linux/time.h> | 13 | #include <linux/time.h> |
14 | #include <linux/compat.h> | 14 | #include <linux/compat.h> |
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/mount.h> | 15 | #include <linux/mount.h> |
16 | #include <linux/file.h> | ||
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include "ext4_jbd2.h" | 18 | #include "ext4_jbd2.h" |
19 | #include "ext4.h" | 19 | #include "ext4.h" |
@@ -191,7 +191,7 @@ setversion_out: | |||
191 | case EXT4_IOC_GROUP_EXTEND: { | 191 | case EXT4_IOC_GROUP_EXTEND: { |
192 | ext4_fsblk_t n_blocks_count; | 192 | ext4_fsblk_t n_blocks_count; |
193 | struct super_block *sb = inode->i_sb; | 193 | struct super_block *sb = inode->i_sb; |
194 | int err, err2; | 194 | int err, err2=0; |
195 | 195 | ||
196 | if (!capable(CAP_SYS_RESOURCE)) | 196 | if (!capable(CAP_SYS_RESOURCE)) |
197 | return -EPERM; | 197 | return -EPERM; |
@@ -204,19 +204,56 @@ setversion_out: | |||
204 | return err; | 204 | return err; |
205 | 205 | ||
206 | err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); | 206 | err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); |
207 | jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); | 207 | if (EXT4_SB(sb)->s_journal) { |
208 | err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); | 208 | jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); |
209 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 209 | err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); |
210 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | ||
211 | } | ||
210 | if (err == 0) | 212 | if (err == 0) |
211 | err = err2; | 213 | err = err2; |
212 | mnt_drop_write(filp->f_path.mnt); | 214 | mnt_drop_write(filp->f_path.mnt); |
213 | 215 | ||
214 | return err; | 216 | return err; |
215 | } | 217 | } |
218 | |||
219 | case EXT4_IOC_MOVE_EXT: { | ||
220 | struct move_extent me; | ||
221 | struct file *donor_filp; | ||
222 | int err; | ||
223 | |||
224 | if (copy_from_user(&me, | ||
225 | (struct move_extent __user *)arg, sizeof(me))) | ||
226 | return -EFAULT; | ||
227 | |||
228 | donor_filp = fget(me.donor_fd); | ||
229 | if (!donor_filp) | ||
230 | return -EBADF; | ||
231 | |||
232 | if (!capable(CAP_DAC_OVERRIDE)) { | ||
233 | if ((current->real_cred->fsuid != inode->i_uid) || | ||
234 | !(inode->i_mode & S_IRUSR) || | ||
235 | !(donor_filp->f_dentry->d_inode->i_mode & | ||
236 | S_IRUSR)) { | ||
237 | fput(donor_filp); | ||
238 | return -EACCES; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | err = ext4_move_extents(filp, donor_filp, me.orig_start, | ||
243 | me.donor_start, me.len, &me.moved_len); | ||
244 | fput(donor_filp); | ||
245 | |||
246 | if (!err) | ||
247 | if (copy_to_user((struct move_extent *)arg, | ||
248 | &me, sizeof(me))) | ||
249 | return -EFAULT; | ||
250 | return err; | ||
251 | } | ||
252 | |||
216 | case EXT4_IOC_GROUP_ADD: { | 253 | case EXT4_IOC_GROUP_ADD: { |
217 | struct ext4_new_group_data input; | 254 | struct ext4_new_group_data input; |
218 | struct super_block *sb = inode->i_sb; | 255 | struct super_block *sb = inode->i_sb; |
219 | int err, err2; | 256 | int err, err2=0; |
220 | 257 | ||
221 | if (!capable(CAP_SYS_RESOURCE)) | 258 | if (!capable(CAP_SYS_RESOURCE)) |
222 | return -EPERM; | 259 | return -EPERM; |
@@ -230,9 +267,11 @@ setversion_out: | |||
230 | return err; | 267 | return err; |
231 | 268 | ||
232 | err = ext4_group_add(sb, &input); | 269 | err = ext4_group_add(sb, &input); |
233 | jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); | 270 | if (EXT4_SB(sb)->s_journal) { |
234 | err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); | 271 | jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); |
235 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 272 | err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); |
273 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | ||
274 | } | ||
236 | if (err == 0) | 275 | if (err == 0) |
237 | err = err2; | 276 | err = err2; |
238 | mnt_drop_write(filp->f_path.mnt); | 277 | mnt_drop_write(filp->f_path.mnt); |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index ed8482e22c0e..cd258463e2a9 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -22,6 +22,8 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include "mballoc.h" | 24 | #include "mballoc.h" |
25 | #include <trace/events/ext4.h> | ||
26 | |||
25 | /* | 27 | /* |
26 | * MUSTDO: | 28 | * MUSTDO: |
27 | * - test ext4_ext_search_left() and ext4_ext_search_right() | 29 | * - test ext4_ext_search_left() and ext4_ext_search_right() |
@@ -340,8 +342,6 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, | |||
340 | ext4_group_t group); | 342 | ext4_group_t group); |
341 | static void release_blocks_on_commit(journal_t *journal, transaction_t *txn); | 343 | static void release_blocks_on_commit(journal_t *journal, transaction_t *txn); |
342 | 344 | ||
343 | |||
344 | |||
345 | static inline void *mb_correct_addr_and_bit(int *bit, void *addr) | 345 | static inline void *mb_correct_addr_and_bit(int *bit, void *addr) |
346 | { | 346 | { |
347 | #if BITS_PER_LONG == 64 | 347 | #if BITS_PER_LONG == 64 |
@@ -657,7 +657,8 @@ static void ext4_mb_mark_free_simple(struct super_block *sb, | |||
657 | } | 657 | } |
658 | } | 658 | } |
659 | 659 | ||
660 | static void ext4_mb_generate_buddy(struct super_block *sb, | 660 | static noinline_for_stack |
661 | void ext4_mb_generate_buddy(struct super_block *sb, | ||
661 | void *buddy, void *bitmap, ext4_group_t group) | 662 | void *buddy, void *bitmap, ext4_group_t group) |
662 | { | 663 | { |
663 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | 664 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); |
@@ -1480,7 +1481,8 @@ static void ext4_mb_measure_extent(struct ext4_allocation_context *ac, | |||
1480 | ext4_mb_check_limits(ac, e4b, 0); | 1481 | ext4_mb_check_limits(ac, e4b, 0); |
1481 | } | 1482 | } |
1482 | 1483 | ||
1483 | static int ext4_mb_try_best_found(struct ext4_allocation_context *ac, | 1484 | static noinline_for_stack |
1485 | int ext4_mb_try_best_found(struct ext4_allocation_context *ac, | ||
1484 | struct ext4_buddy *e4b) | 1486 | struct ext4_buddy *e4b) |
1485 | { | 1487 | { |
1486 | struct ext4_free_extent ex = ac->ac_b_ex; | 1488 | struct ext4_free_extent ex = ac->ac_b_ex; |
@@ -1507,7 +1509,8 @@ static int ext4_mb_try_best_found(struct ext4_allocation_context *ac, | |||
1507 | return 0; | 1509 | return 0; |
1508 | } | 1510 | } |
1509 | 1511 | ||
1510 | static int ext4_mb_find_by_goal(struct ext4_allocation_context *ac, | 1512 | static noinline_for_stack |
1513 | int ext4_mb_find_by_goal(struct ext4_allocation_context *ac, | ||
1511 | struct ext4_buddy *e4b) | 1514 | struct ext4_buddy *e4b) |
1512 | { | 1515 | { |
1513 | ext4_group_t group = ac->ac_g_ex.fe_group; | 1516 | ext4_group_t group = ac->ac_g_ex.fe_group; |
@@ -1566,7 +1569,8 @@ static int ext4_mb_find_by_goal(struct ext4_allocation_context *ac, | |||
1566 | * The routine scans buddy structures (not bitmap!) from given order | 1569 | * The routine scans buddy structures (not bitmap!) from given order |
1567 | * to max order and tries to find big enough chunk to satisfy the req | 1570 | * to max order and tries to find big enough chunk to satisfy the req |
1568 | */ | 1571 | */ |
1569 | static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac, | 1572 | static noinline_for_stack |
1573 | void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac, | ||
1570 | struct ext4_buddy *e4b) | 1574 | struct ext4_buddy *e4b) |
1571 | { | 1575 | { |
1572 | struct super_block *sb = ac->ac_sb; | 1576 | struct super_block *sb = ac->ac_sb; |
@@ -1609,7 +1613,8 @@ static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac, | |||
1609 | * In order to optimize scanning, caller must pass number of | 1613 | * In order to optimize scanning, caller must pass number of |
1610 | * free blocks in the group, so the routine can know upper limit. | 1614 | * free blocks in the group, so the routine can know upper limit. |
1611 | */ | 1615 | */ |
1612 | static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, | 1616 | static noinline_for_stack |
1617 | void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, | ||
1613 | struct ext4_buddy *e4b) | 1618 | struct ext4_buddy *e4b) |
1614 | { | 1619 | { |
1615 | struct super_block *sb = ac->ac_sb; | 1620 | struct super_block *sb = ac->ac_sb; |
@@ -1668,7 +1673,8 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, | |||
1668 | * we try to find stripe-aligned chunks for stripe-size requests | 1673 | * we try to find stripe-aligned chunks for stripe-size requests |
1669 | * XXX should do so at least for multiples of stripe size as well | 1674 | * XXX should do so at least for multiples of stripe size as well |
1670 | */ | 1675 | */ |
1671 | static void ext4_mb_scan_aligned(struct ext4_allocation_context *ac, | 1676 | static noinline_for_stack |
1677 | void ext4_mb_scan_aligned(struct ext4_allocation_context *ac, | ||
1672 | struct ext4_buddy *e4b) | 1678 | struct ext4_buddy *e4b) |
1673 | { | 1679 | { |
1674 | struct super_block *sb = ac->ac_sb; | 1680 | struct super_block *sb = ac->ac_sb; |
@@ -1831,7 +1837,8 @@ void ext4_mb_put_buddy_cache_lock(struct super_block *sb, | |||
1831 | 1837 | ||
1832 | } | 1838 | } |
1833 | 1839 | ||
1834 | static int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) | 1840 | static noinline_for_stack |
1841 | int ext4_mb_init_group(struct super_block *sb, ext4_group_t group) | ||
1835 | { | 1842 | { |
1836 | 1843 | ||
1837 | int ret; | 1844 | int ret; |
@@ -2859,9 +2866,8 @@ static void release_blocks_on_commit(journal_t *journal, transaction_t *txn) | |||
2859 | discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) | 2866 | discard_block = (ext4_fsblk_t) entry->group * EXT4_BLOCKS_PER_GROUP(sb) |
2860 | + entry->start_blk | 2867 | + entry->start_blk |
2861 | + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); | 2868 | + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); |
2862 | trace_mark(ext4_discard_blocks, "dev %s blk %llu count %u", | 2869 | trace_ext4_discard_blocks(sb, (unsigned long long)discard_block, |
2863 | sb->s_id, (unsigned long long) discard_block, | 2870 | entry->count); |
2864 | entry->count); | ||
2865 | sb_issue_discard(sb, discard_block, entry->count); | 2871 | sb_issue_discard(sb, discard_block, entry->count); |
2866 | 2872 | ||
2867 | kmem_cache_free(ext4_free_ext_cachep, entry); | 2873 | kmem_cache_free(ext4_free_ext_cachep, entry); |
@@ -2903,7 +2909,11 @@ int __init init_ext4_mballoc(void) | |||
2903 | 2909 | ||
2904 | void exit_ext4_mballoc(void) | 2910 | void exit_ext4_mballoc(void) |
2905 | { | 2911 | { |
2906 | /* XXX: synchronize_rcu(); */ | 2912 | /* |
2913 | * Wait for completion of call_rcu()'s on ext4_pspace_cachep | ||
2914 | * before destroying the slab cache. | ||
2915 | */ | ||
2916 | rcu_barrier(); | ||
2907 | kmem_cache_destroy(ext4_pspace_cachep); | 2917 | kmem_cache_destroy(ext4_pspace_cachep); |
2908 | kmem_cache_destroy(ext4_ac_cachep); | 2918 | kmem_cache_destroy(ext4_ac_cachep); |
2909 | kmem_cache_destroy(ext4_free_ext_cachep); | 2919 | kmem_cache_destroy(ext4_free_ext_cachep); |
@@ -3458,7 +3468,8 @@ static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, | |||
3458 | * used in in-core bitmap. buddy must be generated from this bitmap | 3468 | * used in in-core bitmap. buddy must be generated from this bitmap |
3459 | * Need to be called with ext4 group lock held | 3469 | * Need to be called with ext4 group lock held |
3460 | */ | 3470 | */ |
3461 | static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, | 3471 | static noinline_for_stack |
3472 | void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, | ||
3462 | ext4_group_t group) | 3473 | ext4_group_t group) |
3463 | { | 3474 | { |
3464 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | 3475 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); |
@@ -3629,10 +3640,7 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) | |||
3629 | 3640 | ||
3630 | mb_debug("new inode pa %p: %llu/%u for %u\n", pa, | 3641 | mb_debug("new inode pa %p: %llu/%u for %u\n", pa, |
3631 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | 3642 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); |
3632 | trace_mark(ext4_mb_new_inode_pa, | 3643 | trace_ext4_mb_new_inode_pa(ac, pa); |
3633 | "dev %s ino %lu pstart %llu len %u lstart %u", | ||
3634 | sb->s_id, ac->ac_inode->i_ino, | ||
3635 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | ||
3636 | 3644 | ||
3637 | ext4_mb_use_inode_pa(ac, pa); | 3645 | ext4_mb_use_inode_pa(ac, pa); |
3638 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); | 3646 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); |
@@ -3691,9 +3699,8 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac) | |||
3691 | pa->pa_type = MB_GROUP_PA; | 3699 | pa->pa_type = MB_GROUP_PA; |
3692 | 3700 | ||
3693 | mb_debug("new group pa %p: %llu/%u for %u\n", pa, | 3701 | mb_debug("new group pa %p: %llu/%u for %u\n", pa, |
3694 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); | 3702 | pa->pa_pstart, pa->pa_len, pa->pa_lstart); |
3695 | trace_mark(ext4_mb_new_group_pa, "dev %s pstart %llu len %u lstart %u", | 3703 | trace_ext4_mb_new_group_pa(ac, pa); |
3696 | sb->s_id, pa->pa_pstart, pa->pa_len, pa->pa_lstart); | ||
3697 | 3704 | ||
3698 | ext4_mb_use_group_pa(ac, pa); | 3705 | ext4_mb_use_group_pa(ac, pa); |
3699 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); | 3706 | atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); |
@@ -3783,10 +3790,8 @@ ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, | |||
3783 | ext4_mb_store_history(ac); | 3790 | ext4_mb_store_history(ac); |
3784 | } | 3791 | } |
3785 | 3792 | ||
3786 | trace_mark(ext4_mb_release_inode_pa, | 3793 | trace_ext4_mb_release_inode_pa(ac, pa, grp_blk_start + bit, |
3787 | "dev %s ino %lu block %llu count %u", | 3794 | next - bit); |
3788 | sb->s_id, pa->pa_inode->i_ino, grp_blk_start + bit, | ||
3789 | next - bit); | ||
3790 | mb_free_blocks(pa->pa_inode, e4b, bit, next - bit); | 3795 | mb_free_blocks(pa->pa_inode, e4b, bit, next - bit); |
3791 | bit = next + 1; | 3796 | bit = next + 1; |
3792 | } | 3797 | } |
@@ -3820,8 +3825,7 @@ ext4_mb_release_group_pa(struct ext4_buddy *e4b, | |||
3820 | if (ac) | 3825 | if (ac) |
3821 | ac->ac_op = EXT4_MB_HISTORY_DISCARD; | 3826 | ac->ac_op = EXT4_MB_HISTORY_DISCARD; |
3822 | 3827 | ||
3823 | trace_mark(ext4_mb_release_group_pa, "dev %s pstart %llu len %d", | 3828 | trace_ext4_mb_release_group_pa(ac, pa); |
3824 | sb->s_id, pa->pa_pstart, pa->pa_len); | ||
3825 | BUG_ON(pa->pa_deleted == 0); | 3829 | BUG_ON(pa->pa_deleted == 0); |
3826 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); | 3830 | ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); |
3827 | BUG_ON(group != e4b->bd_group && pa->pa_len != 0); | 3831 | BUG_ON(group != e4b->bd_group && pa->pa_len != 0); |
@@ -3889,6 +3893,8 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, | |||
3889 | 3893 | ||
3890 | INIT_LIST_HEAD(&list); | 3894 | INIT_LIST_HEAD(&list); |
3891 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 3895 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
3896 | if (ac) | ||
3897 | ac->ac_sb = sb; | ||
3892 | repeat: | 3898 | repeat: |
3893 | ext4_lock_group(sb, group); | 3899 | ext4_lock_group(sb, group); |
3894 | list_for_each_entry_safe(pa, tmp, | 3900 | list_for_each_entry_safe(pa, tmp, |
@@ -3987,12 +3993,15 @@ void ext4_discard_preallocations(struct inode *inode) | |||
3987 | } | 3993 | } |
3988 | 3994 | ||
3989 | mb_debug("discard preallocation for inode %lu\n", inode->i_ino); | 3995 | mb_debug("discard preallocation for inode %lu\n", inode->i_ino); |
3990 | trace_mark(ext4_discard_preallocations, "dev %s ino %lu", sb->s_id, | 3996 | trace_ext4_discard_preallocations(inode); |
3991 | inode->i_ino); | ||
3992 | 3997 | ||
3993 | INIT_LIST_HEAD(&list); | 3998 | INIT_LIST_HEAD(&list); |
3994 | 3999 | ||
3995 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4000 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4001 | if (ac) { | ||
4002 | ac->ac_sb = sb; | ||
4003 | ac->ac_inode = inode; | ||
4004 | } | ||
3996 | repeat: | 4005 | repeat: |
3997 | /* first, collect all pa's in the inode */ | 4006 | /* first, collect all pa's in the inode */ |
3998 | spin_lock(&ei->i_prealloc_lock); | 4007 | spin_lock(&ei->i_prealloc_lock); |
@@ -4218,14 +4227,9 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac, | |||
4218 | ext4_get_group_no_and_offset(sb, goal, &group, &block); | 4227 | ext4_get_group_no_and_offset(sb, goal, &group, &block); |
4219 | 4228 | ||
4220 | /* set up allocation goals */ | 4229 | /* set up allocation goals */ |
4230 | memset(ac, 0, sizeof(struct ext4_allocation_context)); | ||
4221 | ac->ac_b_ex.fe_logical = ar->logical; | 4231 | ac->ac_b_ex.fe_logical = ar->logical; |
4222 | ac->ac_b_ex.fe_group = 0; | ||
4223 | ac->ac_b_ex.fe_start = 0; | ||
4224 | ac->ac_b_ex.fe_len = 0; | ||
4225 | ac->ac_status = AC_STATUS_CONTINUE; | 4232 | ac->ac_status = AC_STATUS_CONTINUE; |
4226 | ac->ac_groups_scanned = 0; | ||
4227 | ac->ac_ex_scanned = 0; | ||
4228 | ac->ac_found = 0; | ||
4229 | ac->ac_sb = sb; | 4233 | ac->ac_sb = sb; |
4230 | ac->ac_inode = ar->inode; | 4234 | ac->ac_inode = ar->inode; |
4231 | ac->ac_o_ex.fe_logical = ar->logical; | 4235 | ac->ac_o_ex.fe_logical = ar->logical; |
@@ -4236,15 +4240,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac, | |||
4236 | ac->ac_g_ex.fe_group = group; | 4240 | ac->ac_g_ex.fe_group = group; |
4237 | ac->ac_g_ex.fe_start = block; | 4241 | ac->ac_g_ex.fe_start = block; |
4238 | ac->ac_g_ex.fe_len = len; | 4242 | ac->ac_g_ex.fe_len = len; |
4239 | ac->ac_f_ex.fe_len = 0; | ||
4240 | ac->ac_flags = ar->flags; | 4243 | ac->ac_flags = ar->flags; |
4241 | ac->ac_2order = 0; | ||
4242 | ac->ac_criteria = 0; | ||
4243 | ac->ac_pa = NULL; | ||
4244 | ac->ac_bitmap_page = NULL; | ||
4245 | ac->ac_buddy_page = NULL; | ||
4246 | ac->alloc_semp = NULL; | ||
4247 | ac->ac_lg = NULL; | ||
4248 | 4244 | ||
4249 | /* we have to define context: we'll we work with a file or | 4245 | /* we have to define context: we'll we work with a file or |
4250 | * locality group. this is a policy, actually */ | 4246 | * locality group. this is a policy, actually */ |
@@ -4276,6 +4272,8 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb, | |||
4276 | 4272 | ||
4277 | INIT_LIST_HEAD(&discard_list); | 4273 | INIT_LIST_HEAD(&discard_list); |
4278 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4274 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4275 | if (ac) | ||
4276 | ac->ac_sb = sb; | ||
4279 | 4277 | ||
4280 | spin_lock(&lg->lg_prealloc_lock); | 4278 | spin_lock(&lg->lg_prealloc_lock); |
4281 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], | 4279 | list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], |
@@ -4445,8 +4443,7 @@ static int ext4_mb_discard_preallocations(struct super_block *sb, int needed) | |||
4445 | int ret; | 4443 | int ret; |
4446 | int freed = 0; | 4444 | int freed = 0; |
4447 | 4445 | ||
4448 | trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d", | 4446 | trace_ext4_mb_discard_preallocations(sb, needed); |
4449 | sb->s_id, needed); | ||
4450 | for (i = 0; i < ngroups && needed > 0; i++) { | 4447 | for (i = 0; i < ngroups && needed > 0; i++) { |
4451 | ret = ext4_mb_discard_group_preallocations(sb, i, needed); | 4448 | ret = ext4_mb_discard_group_preallocations(sb, i, needed); |
4452 | freed += ret; | 4449 | freed += ret; |
@@ -4475,17 +4472,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, | |||
4475 | sb = ar->inode->i_sb; | 4472 | sb = ar->inode->i_sb; |
4476 | sbi = EXT4_SB(sb); | 4473 | sbi = EXT4_SB(sb); |
4477 | 4474 | ||
4478 | trace_mark(ext4_request_blocks, "dev %s flags %u len %u ino %lu " | 4475 | trace_ext4_request_blocks(ar); |
4479 | "lblk %llu goal %llu lleft %llu lright %llu " | ||
4480 | "pleft %llu pright %llu ", | ||
4481 | sb->s_id, ar->flags, ar->len, | ||
4482 | ar->inode ? ar->inode->i_ino : 0, | ||
4483 | (unsigned long long) ar->logical, | ||
4484 | (unsigned long long) ar->goal, | ||
4485 | (unsigned long long) ar->lleft, | ||
4486 | (unsigned long long) ar->lright, | ||
4487 | (unsigned long long) ar->pleft, | ||
4488 | (unsigned long long) ar->pright); | ||
4489 | 4476 | ||
4490 | /* | 4477 | /* |
4491 | * For delayed allocation, we could skip the ENOSPC and | 4478 | * For delayed allocation, we could skip the ENOSPC and |
@@ -4594,18 +4581,7 @@ out3: | |||
4594 | reserv_blks); | 4581 | reserv_blks); |
4595 | } | 4582 | } |
4596 | 4583 | ||
4597 | trace_mark(ext4_allocate_blocks, | 4584 | trace_ext4_allocate_blocks(ar, (unsigned long long)block); |
4598 | "dev %s block %llu flags %u len %u ino %lu " | ||
4599 | "logical %llu goal %llu lleft %llu lright %llu " | ||
4600 | "pleft %llu pright %llu ", | ||
4601 | sb->s_id, (unsigned long long) block, | ||
4602 | ar->flags, ar->len, ar->inode ? ar->inode->i_ino : 0, | ||
4603 | (unsigned long long) ar->logical, | ||
4604 | (unsigned long long) ar->goal, | ||
4605 | (unsigned long long) ar->lleft, | ||
4606 | (unsigned long long) ar->lright, | ||
4607 | (unsigned long long) ar->pleft, | ||
4608 | (unsigned long long) ar->pright); | ||
4609 | 4585 | ||
4610 | return block; | 4586 | return block; |
4611 | } | 4587 | } |
@@ -4709,7 +4685,7 @@ ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, | |||
4709 | * Main entry point into mballoc to free blocks | 4685 | * Main entry point into mballoc to free blocks |
4710 | */ | 4686 | */ |
4711 | void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | 4687 | void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, |
4712 | unsigned long block, unsigned long count, | 4688 | ext4_fsblk_t block, unsigned long count, |
4713 | int metadata, unsigned long *freed) | 4689 | int metadata, unsigned long *freed) |
4714 | { | 4690 | { |
4715 | struct buffer_head *bitmap_bh = NULL; | 4691 | struct buffer_head *bitmap_bh = NULL; |
@@ -4735,15 +4711,12 @@ void ext4_mb_free_blocks(handle_t *handle, struct inode *inode, | |||
4735 | block + count > ext4_blocks_count(es)) { | 4711 | block + count > ext4_blocks_count(es)) { |
4736 | ext4_error(sb, __func__, | 4712 | ext4_error(sb, __func__, |
4737 | "Freeing blocks not in datazone - " | 4713 | "Freeing blocks not in datazone - " |
4738 | "block = %lu, count = %lu", block, count); | 4714 | "block = %llu, count = %lu", block, count); |
4739 | goto error_return; | 4715 | goto error_return; |
4740 | } | 4716 | } |
4741 | 4717 | ||
4742 | ext4_debug("freeing block %lu\n", block); | 4718 | ext4_debug("freeing block %llu\n", block); |
4743 | trace_mark(ext4_free_blocks, | 4719 | trace_ext4_free_blocks(inode, block, count, metadata); |
4744 | "dev %s block %llu count %lu metadata %d ino %lu", | ||
4745 | sb->s_id, (unsigned long long) block, count, metadata, | ||
4746 | inode ? inode->i_ino : 0); | ||
4747 | 4720 | ||
4748 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); | 4721 | ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS); |
4749 | if (ac) { | 4722 | if (ac) { |
@@ -4784,7 +4757,7 @@ do_more: | |||
4784 | 4757 | ||
4785 | ext4_error(sb, __func__, | 4758 | ext4_error(sb, __func__, |
4786 | "Freeing blocks in system zone - " | 4759 | "Freeing blocks in system zone - " |
4787 | "Block = %lu, count = %lu", block, count); | 4760 | "Block = %llu, count = %lu", block, count); |
4788 | /* err = 0. ext4_std_error should be a no op */ | 4761 | /* err = 0. ext4_std_error should be a no op */ |
4789 | goto error_return; | 4762 | goto error_return; |
4790 | } | 4763 | } |
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h index 75e34f69215b..c96bb19f58f9 100644 --- a/fs/ext4/mballoc.h +++ b/fs/ext4/mballoc.h | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/version.h> | 20 | #include <linux/version.h> |
21 | #include <linux/blkdev.h> | 21 | #include <linux/blkdev.h> |
22 | #include <linux/marker.h> | ||
23 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
24 | #include "ext4_jbd2.h" | 23 | #include "ext4_jbd2.h" |
25 | #include "ext4.h" | 24 | #include "ext4.h" |
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c index fe64d9f79852..313a50b39741 100644 --- a/fs/ext4/migrate.c +++ b/fs/ext4/migrate.c | |||
@@ -458,6 +458,7 @@ int ext4_ext_migrate(struct inode *inode) | |||
458 | struct inode *tmp_inode = NULL; | 458 | struct inode *tmp_inode = NULL; |
459 | struct list_blocks_struct lb; | 459 | struct list_blocks_struct lb; |
460 | unsigned long max_entries; | 460 | unsigned long max_entries; |
461 | __u32 goal; | ||
461 | 462 | ||
462 | /* | 463 | /* |
463 | * If the filesystem does not support extents, or the inode | 464 | * If the filesystem does not support extents, or the inode |
@@ -483,9 +484,10 @@ int ext4_ext_migrate(struct inode *inode) | |||
483 | retval = PTR_ERR(handle); | 484 | retval = PTR_ERR(handle); |
484 | return retval; | 485 | return retval; |
485 | } | 486 | } |
486 | tmp_inode = ext4_new_inode(handle, | 487 | goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * |
487 | inode->i_sb->s_root->d_inode, | 488 | EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; |
488 | S_IFREG); | 489 | tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, |
490 | S_IFREG, 0, goal); | ||
489 | if (IS_ERR(tmp_inode)) { | 491 | if (IS_ERR(tmp_inode)) { |
490 | retval = -ENOMEM; | 492 | retval = -ENOMEM; |
491 | ext4_journal_stop(handle); | 493 | ext4_journal_stop(handle); |
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c new file mode 100644 index 000000000000..bbf2dd9404dc --- /dev/null +++ b/fs/ext4/move_extent.c | |||
@@ -0,0 +1,1320 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008,2009 NEC Software Tohoku, Ltd. | ||
3 | * Written by Takashi Sato <t-sato@yk.jp.nec.com> | ||
4 | * Akira Fujita <a-fujita@rs.jp.nec.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of version 2.1 of the GNU Lesser General Public License | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/fs.h> | ||
17 | #include <linux/quotaops.h> | ||
18 | #include "ext4_jbd2.h" | ||
19 | #include "ext4_extents.h" | ||
20 | #include "ext4.h" | ||
21 | |||
22 | #define get_ext_path(path, inode, block, ret) \ | ||
23 | do { \ | ||
24 | path = ext4_ext_find_extent(inode, block, path); \ | ||
25 | if (IS_ERR(path)) { \ | ||
26 | ret = PTR_ERR(path); \ | ||
27 | path = NULL; \ | ||
28 | } \ | ||
29 | } while (0) | ||
30 | |||
31 | /** | ||
32 | * copy_extent_status - Copy the extent's initialization status | ||
33 | * | ||
34 | * @src: an extent for getting initialize status | ||
35 | * @dest: an extent to be set the status | ||
36 | */ | ||
37 | static void | ||
38 | copy_extent_status(struct ext4_extent *src, struct ext4_extent *dest) | ||
39 | { | ||
40 | if (ext4_ext_is_uninitialized(src)) | ||
41 | ext4_ext_mark_uninitialized(dest); | ||
42 | else | ||
43 | dest->ee_len = cpu_to_le16(ext4_ext_get_actual_len(dest)); | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * mext_next_extent - Search for the next extent and set it to "extent" | ||
48 | * | ||
49 | * @inode: inode which is searched | ||
50 | * @path: this will obtain data for the next extent | ||
51 | * @extent: pointer to the next extent we have just gotten | ||
52 | * | ||
53 | * Search the next extent in the array of ext4_ext_path structure (@path) | ||
54 | * and set it to ext4_extent structure (@extent). In addition, the member of | ||
55 | * @path (->p_ext) also points the next extent. Return 0 on success, 1 if | ||
56 | * ext4_ext_path structure refers to the last extent, or a negative error | ||
57 | * value on failure. | ||
58 | */ | ||
59 | static int | ||
60 | mext_next_extent(struct inode *inode, struct ext4_ext_path *path, | ||
61 | struct ext4_extent **extent) | ||
62 | { | ||
63 | int ppos, leaf_ppos = path->p_depth; | ||
64 | |||
65 | ppos = leaf_ppos; | ||
66 | if (EXT_LAST_EXTENT(path[ppos].p_hdr) > path[ppos].p_ext) { | ||
67 | /* leaf block */ | ||
68 | *extent = ++path[ppos].p_ext; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | while (--ppos >= 0) { | ||
73 | if (EXT_LAST_INDEX(path[ppos].p_hdr) > | ||
74 | path[ppos].p_idx) { | ||
75 | int cur_ppos = ppos; | ||
76 | |||
77 | /* index block */ | ||
78 | path[ppos].p_idx++; | ||
79 | path[ppos].p_block = idx_pblock(path[ppos].p_idx); | ||
80 | if (path[ppos+1].p_bh) | ||
81 | brelse(path[ppos+1].p_bh); | ||
82 | path[ppos+1].p_bh = | ||
83 | sb_bread(inode->i_sb, path[ppos].p_block); | ||
84 | if (!path[ppos+1].p_bh) | ||
85 | return -EIO; | ||
86 | path[ppos+1].p_hdr = | ||
87 | ext_block_hdr(path[ppos+1].p_bh); | ||
88 | |||
89 | /* Halfway index block */ | ||
90 | while (++cur_ppos < leaf_ppos) { | ||
91 | path[cur_ppos].p_idx = | ||
92 | EXT_FIRST_INDEX(path[cur_ppos].p_hdr); | ||
93 | path[cur_ppos].p_block = | ||
94 | idx_pblock(path[cur_ppos].p_idx); | ||
95 | if (path[cur_ppos+1].p_bh) | ||
96 | brelse(path[cur_ppos+1].p_bh); | ||
97 | path[cur_ppos+1].p_bh = sb_bread(inode->i_sb, | ||
98 | path[cur_ppos].p_block); | ||
99 | if (!path[cur_ppos+1].p_bh) | ||
100 | return -EIO; | ||
101 | path[cur_ppos+1].p_hdr = | ||
102 | ext_block_hdr(path[cur_ppos+1].p_bh); | ||
103 | } | ||
104 | |||
105 | /* leaf block */ | ||
106 | path[leaf_ppos].p_ext = *extent = | ||
107 | EXT_FIRST_EXTENT(path[leaf_ppos].p_hdr); | ||
108 | return 0; | ||
109 | } | ||
110 | } | ||
111 | /* We found the last extent */ | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * mext_double_down_read - Acquire two inodes' read semaphore | ||
117 | * | ||
118 | * @orig_inode: original inode structure | ||
119 | * @donor_inode: donor inode structure | ||
120 | * Acquire read semaphore of the two inodes (orig and donor) by i_ino order. | ||
121 | */ | ||
122 | static void | ||
123 | mext_double_down_read(struct inode *orig_inode, struct inode *donor_inode) | ||
124 | { | ||
125 | struct inode *first = orig_inode, *second = donor_inode; | ||
126 | |||
127 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
128 | |||
129 | /* | ||
130 | * Use the inode number to provide the stable locking order instead | ||
131 | * of its address, because the C language doesn't guarantee you can | ||
132 | * compare pointers that don't come from the same array. | ||
133 | */ | ||
134 | if (donor_inode->i_ino < orig_inode->i_ino) { | ||
135 | first = donor_inode; | ||
136 | second = orig_inode; | ||
137 | } | ||
138 | |||
139 | down_read(&EXT4_I(first)->i_data_sem); | ||
140 | down_read(&EXT4_I(second)->i_data_sem); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * mext_double_down_write - Acquire two inodes' write semaphore | ||
145 | * | ||
146 | * @orig_inode: original inode structure | ||
147 | * @donor_inode: donor inode structure | ||
148 | * Acquire write semaphore of the two inodes (orig and donor) by i_ino order. | ||
149 | */ | ||
150 | static void | ||
151 | mext_double_down_write(struct inode *orig_inode, struct inode *donor_inode) | ||
152 | { | ||
153 | struct inode *first = orig_inode, *second = donor_inode; | ||
154 | |||
155 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
156 | |||
157 | /* | ||
158 | * Use the inode number to provide the stable locking order instead | ||
159 | * of its address, because the C language doesn't guarantee you can | ||
160 | * compare pointers that don't come from the same array. | ||
161 | */ | ||
162 | if (donor_inode->i_ino < orig_inode->i_ino) { | ||
163 | first = donor_inode; | ||
164 | second = orig_inode; | ||
165 | } | ||
166 | |||
167 | down_write(&EXT4_I(first)->i_data_sem); | ||
168 | down_write(&EXT4_I(second)->i_data_sem); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * mext_double_up_read - Release two inodes' read semaphore | ||
173 | * | ||
174 | * @orig_inode: original inode structure to be released its lock first | ||
175 | * @donor_inode: donor inode structure to be released its lock second | ||
176 | * Release read semaphore of two inodes (orig and donor). | ||
177 | */ | ||
178 | static void | ||
179 | mext_double_up_read(struct inode *orig_inode, struct inode *donor_inode) | ||
180 | { | ||
181 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
182 | |||
183 | up_read(&EXT4_I(orig_inode)->i_data_sem); | ||
184 | up_read(&EXT4_I(donor_inode)->i_data_sem); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * mext_double_up_write - Release two inodes' write semaphore | ||
189 | * | ||
190 | * @orig_inode: original inode structure to be released its lock first | ||
191 | * @donor_inode: donor inode structure to be released its lock second | ||
192 | * Release write semaphore of two inodes (orig and donor). | ||
193 | */ | ||
194 | static void | ||
195 | mext_double_up_write(struct inode *orig_inode, struct inode *donor_inode) | ||
196 | { | ||
197 | BUG_ON(orig_inode == NULL || donor_inode == NULL); | ||
198 | |||
199 | up_write(&EXT4_I(orig_inode)->i_data_sem); | ||
200 | up_write(&EXT4_I(donor_inode)->i_data_sem); | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * mext_insert_across_blocks - Insert extents across leaf block | ||
205 | * | ||
206 | * @handle: journal handle | ||
207 | * @orig_inode: original inode | ||
208 | * @o_start: first original extent to be changed | ||
209 | * @o_end: last original extent to be changed | ||
210 | * @start_ext: first new extent to be inserted | ||
211 | * @new_ext: middle of new extent to be inserted | ||
212 | * @end_ext: last new extent to be inserted | ||
213 | * | ||
214 | * Allocate a new leaf block and insert extents into it. Return 0 on success, | ||
215 | * or a negative error value on failure. | ||
216 | */ | ||
217 | static int | ||
218 | mext_insert_across_blocks(handle_t *handle, struct inode *orig_inode, | ||
219 | struct ext4_extent *o_start, struct ext4_extent *o_end, | ||
220 | struct ext4_extent *start_ext, struct ext4_extent *new_ext, | ||
221 | struct ext4_extent *end_ext) | ||
222 | { | ||
223 | struct ext4_ext_path *orig_path = NULL; | ||
224 | ext4_lblk_t eblock = 0; | ||
225 | int new_flag = 0; | ||
226 | int end_flag = 0; | ||
227 | int err = 0; | ||
228 | |||
229 | if (start_ext->ee_len && new_ext->ee_len && end_ext->ee_len) { | ||
230 | if (o_start == o_end) { | ||
231 | |||
232 | /* start_ext new_ext end_ext | ||
233 | * donor |---------|-----------|--------| | ||
234 | * orig |------------------------------| | ||
235 | */ | ||
236 | end_flag = 1; | ||
237 | } else { | ||
238 | |||
239 | /* start_ext new_ext end_ext | ||
240 | * donor |---------|----------|---------| | ||
241 | * orig |---------------|--------------| | ||
242 | */ | ||
243 | o_end->ee_block = end_ext->ee_block; | ||
244 | o_end->ee_len = end_ext->ee_len; | ||
245 | ext4_ext_store_pblock(o_end, ext_pblock(end_ext)); | ||
246 | } | ||
247 | |||
248 | o_start->ee_len = start_ext->ee_len; | ||
249 | new_flag = 1; | ||
250 | |||
251 | } else if (start_ext->ee_len && new_ext->ee_len && | ||
252 | !end_ext->ee_len && o_start == o_end) { | ||
253 | |||
254 | /* start_ext new_ext | ||
255 | * donor |--------------|---------------| | ||
256 | * orig |------------------------------| | ||
257 | */ | ||
258 | o_start->ee_len = start_ext->ee_len; | ||
259 | new_flag = 1; | ||
260 | |||
261 | } else if (!start_ext->ee_len && new_ext->ee_len && | ||
262 | end_ext->ee_len && o_start == o_end) { | ||
263 | |||
264 | /* new_ext end_ext | ||
265 | * donor |--------------|---------------| | ||
266 | * orig |------------------------------| | ||
267 | */ | ||
268 | o_end->ee_block = end_ext->ee_block; | ||
269 | o_end->ee_len = end_ext->ee_len; | ||
270 | ext4_ext_store_pblock(o_end, ext_pblock(end_ext)); | ||
271 | |||
272 | /* | ||
273 | * Set 0 to the extent block if new_ext was | ||
274 | * the first block. | ||
275 | */ | ||
276 | if (new_ext->ee_block) | ||
277 | eblock = le32_to_cpu(new_ext->ee_block); | ||
278 | |||
279 | new_flag = 1; | ||
280 | } else { | ||
281 | ext4_debug("ext4 move extent: Unexpected insert case\n"); | ||
282 | return -EIO; | ||
283 | } | ||
284 | |||
285 | if (new_flag) { | ||
286 | get_ext_path(orig_path, orig_inode, eblock, err); | ||
287 | if (orig_path == NULL) | ||
288 | goto out; | ||
289 | |||
290 | if (ext4_ext_insert_extent(handle, orig_inode, | ||
291 | orig_path, new_ext)) | ||
292 | goto out; | ||
293 | } | ||
294 | |||
295 | if (end_flag) { | ||
296 | get_ext_path(orig_path, orig_inode, | ||
297 | le32_to_cpu(end_ext->ee_block) - 1, err); | ||
298 | if (orig_path == NULL) | ||
299 | goto out; | ||
300 | |||
301 | if (ext4_ext_insert_extent(handle, orig_inode, | ||
302 | orig_path, end_ext)) | ||
303 | goto out; | ||
304 | } | ||
305 | out: | ||
306 | if (orig_path) { | ||
307 | ext4_ext_drop_refs(orig_path); | ||
308 | kfree(orig_path); | ||
309 | } | ||
310 | |||
311 | return err; | ||
312 | |||
313 | } | ||
314 | |||
315 | /** | ||
316 | * mext_insert_inside_block - Insert new extent to the extent block | ||
317 | * | ||
318 | * @o_start: first original extent to be moved | ||
319 | * @o_end: last original extent to be moved | ||
320 | * @start_ext: first new extent to be inserted | ||
321 | * @new_ext: middle of new extent to be inserted | ||
322 | * @end_ext: last new extent to be inserted | ||
323 | * @eh: extent header of target leaf block | ||
324 | * @range_to_move: used to decide how to insert extent | ||
325 | * | ||
326 | * Insert extents into the leaf block. The extent (@o_start) is overwritten | ||
327 | * by inserted extents. | ||
328 | */ | ||
329 | static void | ||
330 | mext_insert_inside_block(struct ext4_extent *o_start, | ||
331 | struct ext4_extent *o_end, | ||
332 | struct ext4_extent *start_ext, | ||
333 | struct ext4_extent *new_ext, | ||
334 | struct ext4_extent *end_ext, | ||
335 | struct ext4_extent_header *eh, | ||
336 | int range_to_move) | ||
337 | { | ||
338 | int i = 0; | ||
339 | unsigned long len; | ||
340 | |||
341 | /* Move the existing extents */ | ||
342 | if (range_to_move && o_end < EXT_LAST_EXTENT(eh)) { | ||
343 | len = (unsigned long)(EXT_LAST_EXTENT(eh) + 1) - | ||
344 | (unsigned long)(o_end + 1); | ||
345 | memmove(o_end + 1 + range_to_move, o_end + 1, len); | ||
346 | } | ||
347 | |||
348 | /* Insert start entry */ | ||
349 | if (start_ext->ee_len) | ||
350 | o_start[i++].ee_len = start_ext->ee_len; | ||
351 | |||
352 | /* Insert new entry */ | ||
353 | if (new_ext->ee_len) { | ||
354 | o_start[i] = *new_ext; | ||
355 | ext4_ext_store_pblock(&o_start[i++], ext_pblock(new_ext)); | ||
356 | } | ||
357 | |||
358 | /* Insert end entry */ | ||
359 | if (end_ext->ee_len) | ||
360 | o_start[i] = *end_ext; | ||
361 | |||
362 | /* Increment the total entries counter on the extent block */ | ||
363 | le16_add_cpu(&eh->eh_entries, range_to_move); | ||
364 | } | ||
365 | |||
366 | /** | ||
367 | * mext_insert_extents - Insert new extent | ||
368 | * | ||
369 | * @handle: journal handle | ||
370 | * @orig_inode: original inode | ||
371 | * @orig_path: path indicates first extent to be changed | ||
372 | * @o_start: first original extent to be changed | ||
373 | * @o_end: last original extent to be changed | ||
374 | * @start_ext: first new extent to be inserted | ||
375 | * @new_ext: middle of new extent to be inserted | ||
376 | * @end_ext: last new extent to be inserted | ||
377 | * | ||
378 | * Call the function to insert extents. If we cannot add more extents into | ||
379 | * the leaf block, we call mext_insert_across_blocks() to create a | ||
380 | * new leaf block. Otherwise call mext_insert_inside_block(). Return 0 | ||
381 | * on success, or a negative error value on failure. | ||
382 | */ | ||
383 | static int | ||
384 | mext_insert_extents(handle_t *handle, struct inode *orig_inode, | ||
385 | struct ext4_ext_path *orig_path, | ||
386 | struct ext4_extent *o_start, | ||
387 | struct ext4_extent *o_end, | ||
388 | struct ext4_extent *start_ext, | ||
389 | struct ext4_extent *new_ext, | ||
390 | struct ext4_extent *end_ext) | ||
391 | { | ||
392 | struct ext4_extent_header *eh; | ||
393 | unsigned long need_slots, slots_range; | ||
394 | int range_to_move, depth, ret; | ||
395 | |||
396 | /* | ||
397 | * The extents need to be inserted | ||
398 | * start_extent + new_extent + end_extent. | ||
399 | */ | ||
400 | need_slots = (start_ext->ee_len ? 1 : 0) + (end_ext->ee_len ? 1 : 0) + | ||
401 | (new_ext->ee_len ? 1 : 0); | ||
402 | |||
403 | /* The number of slots between start and end */ | ||
404 | slots_range = ((unsigned long)(o_end + 1) - (unsigned long)o_start + 1) | ||
405 | / sizeof(struct ext4_extent); | ||
406 | |||
407 | /* Range to move the end of extent */ | ||
408 | range_to_move = need_slots - slots_range; | ||
409 | depth = orig_path->p_depth; | ||
410 | orig_path += depth; | ||
411 | eh = orig_path->p_hdr; | ||
412 | |||
413 | if (depth) { | ||
414 | /* Register to journal */ | ||
415 | ret = ext4_journal_get_write_access(handle, orig_path->p_bh); | ||
416 | if (ret) | ||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | /* Expansion */ | ||
421 | if (range_to_move > 0 && | ||
422 | (range_to_move > le16_to_cpu(eh->eh_max) | ||
423 | - le16_to_cpu(eh->eh_entries))) { | ||
424 | |||
425 | ret = mext_insert_across_blocks(handle, orig_inode, o_start, | ||
426 | o_end, start_ext, new_ext, end_ext); | ||
427 | if (ret < 0) | ||
428 | return ret; | ||
429 | } else | ||
430 | mext_insert_inside_block(o_start, o_end, start_ext, new_ext, | ||
431 | end_ext, eh, range_to_move); | ||
432 | |||
433 | if (depth) { | ||
434 | ret = ext4_handle_dirty_metadata(handle, orig_inode, | ||
435 | orig_path->p_bh); | ||
436 | if (ret) | ||
437 | return ret; | ||
438 | } else { | ||
439 | ret = ext4_mark_inode_dirty(handle, orig_inode); | ||
440 | if (ret < 0) | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * mext_leaf_block - Move one leaf extent block into the inode. | ||
449 | * | ||
450 | * @handle: journal handle | ||
451 | * @orig_inode: original inode | ||
452 | * @orig_path: path indicates first extent to be changed | ||
453 | * @dext: donor extent | ||
454 | * @from: start offset on the target file | ||
455 | * | ||
456 | * In order to insert extents into the leaf block, we must divide the extent | ||
457 | * in the leaf block into three extents. The one is located to be inserted | ||
458 | * extents, and the others are located around it. | ||
459 | * | ||
460 | * Therefore, this function creates structures to save extents of the leaf | ||
461 | * block, and inserts extents by calling mext_insert_extents() with | ||
462 | * created extents. Return 0 on success, or a negative error value on failure. | ||
463 | */ | ||
464 | static int | ||
465 | mext_leaf_block(handle_t *handle, struct inode *orig_inode, | ||
466 | struct ext4_ext_path *orig_path, struct ext4_extent *dext, | ||
467 | ext4_lblk_t *from) | ||
468 | { | ||
469 | struct ext4_extent *oext, *o_start, *o_end, *prev_ext; | ||
470 | struct ext4_extent new_ext, start_ext, end_ext; | ||
471 | ext4_lblk_t new_ext_end; | ||
472 | ext4_fsblk_t new_phys_end; | ||
473 | int oext_alen, new_ext_alen, end_ext_alen; | ||
474 | int depth = ext_depth(orig_inode); | ||
475 | int ret; | ||
476 | |||
477 | o_start = o_end = oext = orig_path[depth].p_ext; | ||
478 | oext_alen = ext4_ext_get_actual_len(oext); | ||
479 | start_ext.ee_len = end_ext.ee_len = 0; | ||
480 | |||
481 | new_ext.ee_block = cpu_to_le32(*from); | ||
482 | ext4_ext_store_pblock(&new_ext, ext_pblock(dext)); | ||
483 | new_ext.ee_len = dext->ee_len; | ||
484 | new_ext_alen = ext4_ext_get_actual_len(&new_ext); | ||
485 | new_ext_end = le32_to_cpu(new_ext.ee_block) + new_ext_alen - 1; | ||
486 | new_phys_end = ext_pblock(&new_ext) + new_ext_alen - 1; | ||
487 | |||
488 | /* | ||
489 | * Case: original extent is first | ||
490 | * oext |--------| | ||
491 | * new_ext |--| | ||
492 | * start_ext |--| | ||
493 | */ | ||
494 | if (le32_to_cpu(oext->ee_block) < le32_to_cpu(new_ext.ee_block) && | ||
495 | le32_to_cpu(new_ext.ee_block) < | ||
496 | le32_to_cpu(oext->ee_block) + oext_alen) { | ||
497 | start_ext.ee_len = cpu_to_le16(le32_to_cpu(new_ext.ee_block) - | ||
498 | le32_to_cpu(oext->ee_block)); | ||
499 | copy_extent_status(oext, &start_ext); | ||
500 | } else if (oext > EXT_FIRST_EXTENT(orig_path[depth].p_hdr)) { | ||
501 | prev_ext = oext - 1; | ||
502 | /* | ||
503 | * We can merge new_ext into previous extent, | ||
504 | * if these are contiguous and same extent type. | ||
505 | */ | ||
506 | if (ext4_can_extents_be_merged(orig_inode, prev_ext, | ||
507 | &new_ext)) { | ||
508 | o_start = prev_ext; | ||
509 | start_ext.ee_len = cpu_to_le16( | ||
510 | ext4_ext_get_actual_len(prev_ext) + | ||
511 | new_ext_alen); | ||
512 | copy_extent_status(prev_ext, &start_ext); | ||
513 | new_ext.ee_len = 0; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * Case: new_ext_end must be less than oext | ||
519 | * oext |-----------| | ||
520 | * new_ext |-------| | ||
521 | */ | ||
522 | BUG_ON(le32_to_cpu(oext->ee_block) + oext_alen - 1 < new_ext_end); | ||
523 | |||
524 | /* | ||
525 | * Case: new_ext is smaller than original extent | ||
526 | * oext |---------------| | ||
527 | * new_ext |-----------| | ||
528 | * end_ext |---| | ||
529 | */ | ||
530 | if (le32_to_cpu(oext->ee_block) <= new_ext_end && | ||
531 | new_ext_end < le32_to_cpu(oext->ee_block) + oext_alen - 1) { | ||
532 | end_ext.ee_len = | ||
533 | cpu_to_le16(le32_to_cpu(oext->ee_block) + | ||
534 | oext_alen - 1 - new_ext_end); | ||
535 | copy_extent_status(oext, &end_ext); | ||
536 | end_ext_alen = ext4_ext_get_actual_len(&end_ext); | ||
537 | ext4_ext_store_pblock(&end_ext, | ||
538 | (ext_pblock(o_end) + oext_alen - end_ext_alen)); | ||
539 | end_ext.ee_block = | ||
540 | cpu_to_le32(le32_to_cpu(o_end->ee_block) + | ||
541 | oext_alen - end_ext_alen); | ||
542 | } | ||
543 | |||
544 | ret = mext_insert_extents(handle, orig_inode, orig_path, o_start, | ||
545 | o_end, &start_ext, &new_ext, &end_ext); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | /** | ||
550 | * mext_calc_swap_extents - Calculate extents for extent swapping. | ||
551 | * | ||
552 | * @tmp_dext: the extent that will belong to the original inode | ||
553 | * @tmp_oext: the extent that will belong to the donor inode | ||
554 | * @orig_off: block offset of original inode | ||
555 | * @donor_off: block offset of donor inode | ||
556 | * @max_count: the maximun length of extents | ||
557 | */ | ||
558 | static void | ||
559 | mext_calc_swap_extents(struct ext4_extent *tmp_dext, | ||
560 | struct ext4_extent *tmp_oext, | ||
561 | ext4_lblk_t orig_off, ext4_lblk_t donor_off, | ||
562 | ext4_lblk_t max_count) | ||
563 | { | ||
564 | ext4_lblk_t diff, orig_diff; | ||
565 | struct ext4_extent dext_old, oext_old; | ||
566 | |||
567 | dext_old = *tmp_dext; | ||
568 | oext_old = *tmp_oext; | ||
569 | |||
570 | /* When tmp_dext is too large, pick up the target range. */ | ||
571 | diff = donor_off - le32_to_cpu(tmp_dext->ee_block); | ||
572 | |||
573 | ext4_ext_store_pblock(tmp_dext, ext_pblock(tmp_dext) + diff); | ||
574 | tmp_dext->ee_block = | ||
575 | cpu_to_le32(le32_to_cpu(tmp_dext->ee_block) + diff); | ||
576 | tmp_dext->ee_len = cpu_to_le16(le16_to_cpu(tmp_dext->ee_len) - diff); | ||
577 | |||
578 | if (max_count < ext4_ext_get_actual_len(tmp_dext)) | ||
579 | tmp_dext->ee_len = cpu_to_le16(max_count); | ||
580 | |||
581 | orig_diff = orig_off - le32_to_cpu(tmp_oext->ee_block); | ||
582 | ext4_ext_store_pblock(tmp_oext, ext_pblock(tmp_oext) + orig_diff); | ||
583 | |||
584 | /* Adjust extent length if donor extent is larger than orig */ | ||
585 | if (ext4_ext_get_actual_len(tmp_dext) > | ||
586 | ext4_ext_get_actual_len(tmp_oext) - orig_diff) | ||
587 | tmp_dext->ee_len = cpu_to_le16(le16_to_cpu(tmp_oext->ee_len) - | ||
588 | orig_diff); | ||
589 | |||
590 | tmp_oext->ee_len = cpu_to_le16(ext4_ext_get_actual_len(tmp_dext)); | ||
591 | |||
592 | copy_extent_status(&oext_old, tmp_dext); | ||
593 | copy_extent_status(&dext_old, tmp_oext); | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * mext_replace_branches - Replace original extents with new extents | ||
598 | * | ||
599 | * @handle: journal handle | ||
600 | * @orig_inode: original inode | ||
601 | * @donor_inode: donor inode | ||
602 | * @from: block offset of orig_inode | ||
603 | * @count: block count to be replaced | ||
604 | * | ||
605 | * Replace original inode extents and donor inode extents page by page. | ||
606 | * We implement this replacement in the following three steps: | ||
607 | * 1. Save the block information of original and donor inodes into | ||
608 | * dummy extents. | ||
609 | * 2. Change the block information of original inode to point at the | ||
610 | * donor inode blocks. | ||
611 | * 3. Change the block information of donor inode to point at the saved | ||
612 | * original inode blocks in the dummy extents. | ||
613 | * | ||
614 | * Return 0 on success, or a negative error value on failure. | ||
615 | */ | ||
616 | static int | ||
617 | mext_replace_branches(handle_t *handle, struct inode *orig_inode, | ||
618 | struct inode *donor_inode, ext4_lblk_t from, | ||
619 | ext4_lblk_t count) | ||
620 | { | ||
621 | struct ext4_ext_path *orig_path = NULL; | ||
622 | struct ext4_ext_path *donor_path = NULL; | ||
623 | struct ext4_extent *oext, *dext; | ||
624 | struct ext4_extent tmp_dext, tmp_oext; | ||
625 | ext4_lblk_t orig_off = from, donor_off = from; | ||
626 | int err = 0; | ||
627 | int depth; | ||
628 | int replaced_count = 0; | ||
629 | int dext_alen; | ||
630 | |||
631 | mext_double_down_write(orig_inode, donor_inode); | ||
632 | |||
633 | /* Get the original extent for the block "orig_off" */ | ||
634 | get_ext_path(orig_path, orig_inode, orig_off, err); | ||
635 | if (orig_path == NULL) | ||
636 | goto out; | ||
637 | |||
638 | /* Get the donor extent for the head */ | ||
639 | get_ext_path(donor_path, donor_inode, donor_off, err); | ||
640 | if (donor_path == NULL) | ||
641 | goto out; | ||
642 | depth = ext_depth(orig_inode); | ||
643 | oext = orig_path[depth].p_ext; | ||
644 | tmp_oext = *oext; | ||
645 | |||
646 | depth = ext_depth(donor_inode); | ||
647 | dext = donor_path[depth].p_ext; | ||
648 | tmp_dext = *dext; | ||
649 | |||
650 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | ||
651 | donor_off, count); | ||
652 | |||
653 | /* Loop for the donor extents */ | ||
654 | while (1) { | ||
655 | /* The extent for donor must be found. */ | ||
656 | BUG_ON(!dext || donor_off != le32_to_cpu(tmp_dext.ee_block)); | ||
657 | |||
658 | /* Set donor extent to orig extent */ | ||
659 | err = mext_leaf_block(handle, orig_inode, | ||
660 | orig_path, &tmp_dext, &orig_off); | ||
661 | if (err < 0) | ||
662 | goto out; | ||
663 | |||
664 | /* Set orig extent to donor extent */ | ||
665 | err = mext_leaf_block(handle, donor_inode, | ||
666 | donor_path, &tmp_oext, &donor_off); | ||
667 | if (err < 0) | ||
668 | goto out; | ||
669 | |||
670 | dext_alen = ext4_ext_get_actual_len(&tmp_dext); | ||
671 | replaced_count += dext_alen; | ||
672 | donor_off += dext_alen; | ||
673 | orig_off += dext_alen; | ||
674 | |||
675 | /* Already moved the expected blocks */ | ||
676 | if (replaced_count >= count) | ||
677 | break; | ||
678 | |||
679 | if (orig_path) | ||
680 | ext4_ext_drop_refs(orig_path); | ||
681 | get_ext_path(orig_path, orig_inode, orig_off, err); | ||
682 | if (orig_path == NULL) | ||
683 | goto out; | ||
684 | depth = ext_depth(orig_inode); | ||
685 | oext = orig_path[depth].p_ext; | ||
686 | if (le32_to_cpu(oext->ee_block) + | ||
687 | ext4_ext_get_actual_len(oext) <= orig_off) { | ||
688 | err = 0; | ||
689 | goto out; | ||
690 | } | ||
691 | tmp_oext = *oext; | ||
692 | |||
693 | if (donor_path) | ||
694 | ext4_ext_drop_refs(donor_path); | ||
695 | get_ext_path(donor_path, donor_inode, | ||
696 | donor_off, err); | ||
697 | if (donor_path == NULL) | ||
698 | goto out; | ||
699 | depth = ext_depth(donor_inode); | ||
700 | dext = donor_path[depth].p_ext; | ||
701 | if (le32_to_cpu(dext->ee_block) + | ||
702 | ext4_ext_get_actual_len(dext) <= donor_off) { | ||
703 | err = 0; | ||
704 | goto out; | ||
705 | } | ||
706 | tmp_dext = *dext; | ||
707 | |||
708 | mext_calc_swap_extents(&tmp_dext, &tmp_oext, orig_off, | ||
709 | donor_off, | ||
710 | count - replaced_count); | ||
711 | } | ||
712 | |||
713 | out: | ||
714 | if (orig_path) { | ||
715 | ext4_ext_drop_refs(orig_path); | ||
716 | kfree(orig_path); | ||
717 | } | ||
718 | if (donor_path) { | ||
719 | ext4_ext_drop_refs(donor_path); | ||
720 | kfree(donor_path); | ||
721 | } | ||
722 | |||
723 | mext_double_up_write(orig_inode, donor_inode); | ||
724 | return err; | ||
725 | } | ||
726 | |||
727 | /** | ||
728 | * move_extent_per_page - Move extent data per page | ||
729 | * | ||
730 | * @o_filp: file structure of original file | ||
731 | * @donor_inode: donor inode | ||
732 | * @orig_page_offset: page index on original file | ||
733 | * @data_offset_in_page: block index where data swapping starts | ||
734 | * @block_len_in_page: the number of blocks to be swapped | ||
735 | * @uninit: orig extent is uninitialized or not | ||
736 | * | ||
737 | * Save the data in original inode blocks and replace original inode extents | ||
738 | * with donor inode extents by calling mext_replace_branches(). | ||
739 | * Finally, write out the saved data in new original inode blocks. Return 0 | ||
740 | * on success, or a negative error value on failure. | ||
741 | */ | ||
742 | static int | ||
743 | move_extent_par_page(struct file *o_filp, struct inode *donor_inode, | ||
744 | pgoff_t orig_page_offset, int data_offset_in_page, | ||
745 | int block_len_in_page, int uninit) | ||
746 | { | ||
747 | struct inode *orig_inode = o_filp->f_dentry->d_inode; | ||
748 | struct address_space *mapping = orig_inode->i_mapping; | ||
749 | struct buffer_head *bh; | ||
750 | struct page *page = NULL; | ||
751 | const struct address_space_operations *a_ops = mapping->a_ops; | ||
752 | handle_t *handle; | ||
753 | ext4_lblk_t orig_blk_offset; | ||
754 | long long offs = orig_page_offset << PAGE_CACHE_SHIFT; | ||
755 | unsigned long blocksize = orig_inode->i_sb->s_blocksize; | ||
756 | unsigned int w_flags = 0; | ||
757 | unsigned int tmp_data_len, data_len; | ||
758 | void *fsdata; | ||
759 | int ret, i, jblocks; | ||
760 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | ||
761 | |||
762 | /* | ||
763 | * It needs twice the amount of ordinary journal buffers because | ||
764 | * inode and donor_inode may change each different metadata blocks. | ||
765 | */ | ||
766 | jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; | ||
767 | handle = ext4_journal_start(orig_inode, jblocks); | ||
768 | if (IS_ERR(handle)) { | ||
769 | ret = PTR_ERR(handle); | ||
770 | return ret; | ||
771 | } | ||
772 | |||
773 | if (segment_eq(get_fs(), KERNEL_DS)) | ||
774 | w_flags |= AOP_FLAG_UNINTERRUPTIBLE; | ||
775 | |||
776 | orig_blk_offset = orig_page_offset * blocks_per_page + | ||
777 | data_offset_in_page; | ||
778 | |||
779 | /* | ||
780 | * If orig extent is uninitialized one, | ||
781 | * it's not necessary force the page into memory | ||
782 | * and then force it to be written out again. | ||
783 | * Just swap data blocks between orig and donor. | ||
784 | */ | ||
785 | if (uninit) { | ||
786 | ret = mext_replace_branches(handle, orig_inode, | ||
787 | donor_inode, orig_blk_offset, | ||
788 | block_len_in_page); | ||
789 | |||
790 | /* Clear the inode cache not to refer to the old data */ | ||
791 | ext4_ext_invalidate_cache(orig_inode); | ||
792 | ext4_ext_invalidate_cache(donor_inode); | ||
793 | goto out2; | ||
794 | } | ||
795 | |||
796 | offs = (long long)orig_blk_offset << orig_inode->i_blkbits; | ||
797 | |||
798 | /* Calculate data_len */ | ||
799 | if ((orig_blk_offset + block_len_in_page - 1) == | ||
800 | ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { | ||
801 | /* Replace the last block */ | ||
802 | tmp_data_len = orig_inode->i_size & (blocksize - 1); | ||
803 | /* | ||
804 | * If data_len equal zero, it shows data_len is multiples of | ||
805 | * blocksize. So we set appropriate value. | ||
806 | */ | ||
807 | if (tmp_data_len == 0) | ||
808 | tmp_data_len = blocksize; | ||
809 | |||
810 | data_len = tmp_data_len + | ||
811 | ((block_len_in_page - 1) << orig_inode->i_blkbits); | ||
812 | } else { | ||
813 | data_len = block_len_in_page << orig_inode->i_blkbits; | ||
814 | } | ||
815 | |||
816 | ret = a_ops->write_begin(o_filp, mapping, offs, data_len, w_flags, | ||
817 | &page, &fsdata); | ||
818 | if (unlikely(ret < 0)) | ||
819 | goto out; | ||
820 | |||
821 | if (!PageUptodate(page)) { | ||
822 | mapping->a_ops->readpage(o_filp, page); | ||
823 | lock_page(page); | ||
824 | } | ||
825 | |||
826 | /* | ||
827 | * try_to_release_page() doesn't call releasepage in writeback mode. | ||
828 | * We should care about the order of writing to the same file | ||
829 | * by multiple move extent processes. | ||
830 | * It needs to call wait_on_page_writeback() to wait for the | ||
831 | * writeback of the page. | ||
832 | */ | ||
833 | if (PageWriteback(page)) | ||
834 | wait_on_page_writeback(page); | ||
835 | |||
836 | /* Release old bh and drop refs */ | ||
837 | try_to_release_page(page, 0); | ||
838 | |||
839 | ret = mext_replace_branches(handle, orig_inode, donor_inode, | ||
840 | orig_blk_offset, block_len_in_page); | ||
841 | if (ret < 0) | ||
842 | goto out; | ||
843 | |||
844 | /* Clear the inode cache not to refer to the old data */ | ||
845 | ext4_ext_invalidate_cache(orig_inode); | ||
846 | ext4_ext_invalidate_cache(donor_inode); | ||
847 | |||
848 | if (!page_has_buffers(page)) | ||
849 | create_empty_buffers(page, 1 << orig_inode->i_blkbits, 0); | ||
850 | |||
851 | bh = page_buffers(page); | ||
852 | for (i = 0; i < data_offset_in_page; i++) | ||
853 | bh = bh->b_this_page; | ||
854 | |||
855 | for (i = 0; i < block_len_in_page; i++) { | ||
856 | ret = ext4_get_block(orig_inode, | ||
857 | (sector_t)(orig_blk_offset + i), bh, 0); | ||
858 | if (ret < 0) | ||
859 | goto out; | ||
860 | |||
861 | if (bh->b_this_page != NULL) | ||
862 | bh = bh->b_this_page; | ||
863 | } | ||
864 | |||
865 | ret = a_ops->write_end(o_filp, mapping, offs, data_len, data_len, | ||
866 | page, fsdata); | ||
867 | page = NULL; | ||
868 | |||
869 | out: | ||
870 | if (unlikely(page)) { | ||
871 | if (PageLocked(page)) | ||
872 | unlock_page(page); | ||
873 | page_cache_release(page); | ||
874 | } | ||
875 | out2: | ||
876 | ext4_journal_stop(handle); | ||
877 | |||
878 | return ret < 0 ? ret : 0; | ||
879 | } | ||
880 | |||
881 | /** | ||
882 | * mext_check_argumants - Check whether move extent can be done | ||
883 | * | ||
884 | * @orig_inode: original inode | ||
885 | * @donor_inode: donor inode | ||
886 | * @orig_start: logical start offset in block for orig | ||
887 | * @donor_start: logical start offset in block for donor | ||
888 | * @len: the number of blocks to be moved | ||
889 | * @moved_len: moved block length | ||
890 | * | ||
891 | * Check the arguments of ext4_move_extents() whether the files can be | ||
892 | * exchanged with each other. | ||
893 | * Return 0 on success, or a negative error value on failure. | ||
894 | */ | ||
895 | static int | ||
896 | mext_check_arguments(struct inode *orig_inode, | ||
897 | struct inode *donor_inode, __u64 orig_start, | ||
898 | __u64 donor_start, __u64 *len, __u64 moved_len) | ||
899 | { | ||
900 | /* Regular file check */ | ||
901 | if (!S_ISREG(orig_inode->i_mode) || !S_ISREG(donor_inode->i_mode)) { | ||
902 | ext4_debug("ext4 move extent: The argument files should be " | ||
903 | "regular file [ino:orig %lu, donor %lu]\n", | ||
904 | orig_inode->i_ino, donor_inode->i_ino); | ||
905 | return -EINVAL; | ||
906 | } | ||
907 | |||
908 | /* Ext4 move extent does not support swapfile */ | ||
909 | if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { | ||
910 | ext4_debug("ext4 move extent: The argument files should " | ||
911 | "not be swapfile [ino:orig %lu, donor %lu]\n", | ||
912 | orig_inode->i_ino, donor_inode->i_ino); | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | |||
916 | /* Files should be in the same ext4 FS */ | ||
917 | if (orig_inode->i_sb != donor_inode->i_sb) { | ||
918 | ext4_debug("ext4 move extent: The argument files " | ||
919 | "should be in same FS [ino:orig %lu, donor %lu]\n", | ||
920 | orig_inode->i_ino, donor_inode->i_ino); | ||
921 | return -EINVAL; | ||
922 | } | ||
923 | |||
924 | /* orig and donor should be different file */ | ||
925 | if (orig_inode->i_ino == donor_inode->i_ino) { | ||
926 | ext4_debug("ext4 move extent: The argument files should not " | ||
927 | "be same file [ino:orig %lu, donor %lu]\n", | ||
928 | orig_inode->i_ino, donor_inode->i_ino); | ||
929 | return -EINVAL; | ||
930 | } | ||
931 | |||
932 | /* Ext4 move extent supports only extent based file */ | ||
933 | if (!(EXT4_I(orig_inode)->i_flags & EXT4_EXTENTS_FL)) { | ||
934 | ext4_debug("ext4 move extent: orig file is not extents " | ||
935 | "based file [ino:orig %lu]\n", orig_inode->i_ino); | ||
936 | return -EOPNOTSUPP; | ||
937 | } else if (!(EXT4_I(donor_inode)->i_flags & EXT4_EXTENTS_FL)) { | ||
938 | ext4_debug("ext4 move extent: donor file is not extents " | ||
939 | "based file [ino:donor %lu]\n", donor_inode->i_ino); | ||
940 | return -EOPNOTSUPP; | ||
941 | } | ||
942 | |||
943 | if ((!orig_inode->i_size) || (!donor_inode->i_size)) { | ||
944 | ext4_debug("ext4 move extent: File size is 0 byte\n"); | ||
945 | return -EINVAL; | ||
946 | } | ||
947 | |||
948 | /* Start offset should be same */ | ||
949 | if (orig_start != donor_start) { | ||
950 | ext4_debug("ext4 move extent: orig and donor's start " | ||
951 | "offset are not same [ino:orig %lu, donor %lu]\n", | ||
952 | orig_inode->i_ino, donor_inode->i_ino); | ||
953 | return -EINVAL; | ||
954 | } | ||
955 | |||
956 | if (moved_len) { | ||
957 | ext4_debug("ext4 move extent: moved_len should be 0 " | ||
958 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | ||
959 | donor_inode->i_ino); | ||
960 | return -EINVAL; | ||
961 | } | ||
962 | |||
963 | if ((orig_start > MAX_DEFRAG_SIZE) || | ||
964 | (donor_start > MAX_DEFRAG_SIZE) || | ||
965 | (*len > MAX_DEFRAG_SIZE) || | ||
966 | (orig_start + *len > MAX_DEFRAG_SIZE)) { | ||
967 | ext4_debug("ext4 move extent: Can't handle over [%lu] blocks " | ||
968 | "[ino:orig %lu, donor %lu]\n", MAX_DEFRAG_SIZE, | ||
969 | orig_inode->i_ino, donor_inode->i_ino); | ||
970 | return -EINVAL; | ||
971 | } | ||
972 | |||
973 | if (orig_inode->i_size > donor_inode->i_size) { | ||
974 | if (orig_start >= donor_inode->i_size) { | ||
975 | ext4_debug("ext4 move extent: orig start offset " | ||
976 | "[%llu] should be less than donor file size " | ||
977 | "[%lld] [ino:orig %lu, donor_inode %lu]\n", | ||
978 | orig_start, donor_inode->i_size, | ||
979 | orig_inode->i_ino, donor_inode->i_ino); | ||
980 | return -EINVAL; | ||
981 | } | ||
982 | |||
983 | if (orig_start + *len > donor_inode->i_size) { | ||
984 | ext4_debug("ext4 move extent: End offset [%llu] should " | ||
985 | "be less than donor file size [%lld]." | ||
986 | "So adjust length from %llu to %lld " | ||
987 | "[ino:orig %lu, donor %lu]\n", | ||
988 | orig_start + *len, donor_inode->i_size, | ||
989 | *len, donor_inode->i_size - orig_start, | ||
990 | orig_inode->i_ino, donor_inode->i_ino); | ||
991 | *len = donor_inode->i_size - orig_start; | ||
992 | } | ||
993 | } else { | ||
994 | if (orig_start >= orig_inode->i_size) { | ||
995 | ext4_debug("ext4 move extent: start offset [%llu] " | ||
996 | "should be less than original file size " | ||
997 | "[%lld] [inode:orig %lu, donor %lu]\n", | ||
998 | orig_start, orig_inode->i_size, | ||
999 | orig_inode->i_ino, donor_inode->i_ino); | ||
1000 | return -EINVAL; | ||
1001 | } | ||
1002 | |||
1003 | if (orig_start + *len > orig_inode->i_size) { | ||
1004 | ext4_debug("ext4 move extent: Adjust length " | ||
1005 | "from %llu to %lld. Because it should be " | ||
1006 | "less than original file size " | ||
1007 | "[ino:orig %lu, donor %lu]\n", | ||
1008 | *len, orig_inode->i_size - orig_start, | ||
1009 | orig_inode->i_ino, donor_inode->i_ino); | ||
1010 | *len = orig_inode->i_size - orig_start; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | if (!*len) { | ||
1015 | ext4_debug("ext4 move extent: len shoudld not be 0 " | ||
1016 | "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, | ||
1017 | donor_inode->i_ino); | ||
1018 | return -EINVAL; | ||
1019 | } | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | /** | ||
1025 | * mext_inode_double_lock - Lock i_mutex on both @inode1 and @inode2 | ||
1026 | * | ||
1027 | * @inode1: the inode structure | ||
1028 | * @inode2: the inode structure | ||
1029 | * | ||
1030 | * Lock two inodes' i_mutex by i_ino order. This function is moved from | ||
1031 | * fs/inode.c. | ||
1032 | */ | ||
1033 | static void | ||
1034 | mext_inode_double_lock(struct inode *inode1, struct inode *inode2) | ||
1035 | { | ||
1036 | if (inode1 == NULL || inode2 == NULL || inode1 == inode2) { | ||
1037 | if (inode1) | ||
1038 | mutex_lock(&inode1->i_mutex); | ||
1039 | else if (inode2) | ||
1040 | mutex_lock(&inode2->i_mutex); | ||
1041 | return; | ||
1042 | } | ||
1043 | |||
1044 | if (inode1->i_ino < inode2->i_ino) { | ||
1045 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT); | ||
1046 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD); | ||
1047 | } else { | ||
1048 | mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT); | ||
1049 | mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | /** | ||
1054 | * mext_inode_double_unlock - Release i_mutex on both @inode1 and @inode2 | ||
1055 | * | ||
1056 | * @inode1: the inode that is released first | ||
1057 | * @inode2: the inode that is released second | ||
1058 | * | ||
1059 | * This function is moved from fs/inode.c. | ||
1060 | */ | ||
1061 | |||
1062 | static void | ||
1063 | mext_inode_double_unlock(struct inode *inode1, struct inode *inode2) | ||
1064 | { | ||
1065 | if (inode1) | ||
1066 | mutex_unlock(&inode1->i_mutex); | ||
1067 | |||
1068 | if (inode2 && inode2 != inode1) | ||
1069 | mutex_unlock(&inode2->i_mutex); | ||
1070 | } | ||
1071 | |||
1072 | /** | ||
1073 | * ext4_move_extents - Exchange the specified range of a file | ||
1074 | * | ||
1075 | * @o_filp: file structure of the original file | ||
1076 | * @d_filp: file structure of the donor file | ||
1077 | * @orig_start: start offset in block for orig | ||
1078 | * @donor_start: start offset in block for donor | ||
1079 | * @len: the number of blocks to be moved | ||
1080 | * @moved_len: moved block length | ||
1081 | * | ||
1082 | * This function returns 0 and moved block length is set in moved_len | ||
1083 | * if succeed, otherwise returns error value. | ||
1084 | * | ||
1085 | * Note: ext4_move_extents() proceeds the following order. | ||
1086 | * 1:ext4_move_extents() calculates the last block number of moving extent | ||
1087 | * function by the start block number (orig_start) and the number of blocks | ||
1088 | * to be moved (len) specified as arguments. | ||
1089 | * If the {orig, donor}_start points a hole, the extent's start offset | ||
1090 | * pointed by ext_cur (current extent), holecheck_path, orig_path are set | ||
1091 | * after hole behind. | ||
1092 | * 2:Continue step 3 to step 5, until the holecheck_path points to last_extent | ||
1093 | * or the ext_cur exceeds the block_end which is last logical block number. | ||
1094 | * 3:To get the length of continues area, call mext_next_extent() | ||
1095 | * specified with the ext_cur (initial value is holecheck_path) re-cursive, | ||
1096 | * until find un-continuous extent, the start logical block number exceeds | ||
1097 | * the block_end or the extent points to the last extent. | ||
1098 | * 4:Exchange the original inode data with donor inode data | ||
1099 | * from orig_page_offset to seq_end_page. | ||
1100 | * The start indexes of data are specified as arguments. | ||
1101 | * That of the original inode is orig_page_offset, | ||
1102 | * and the donor inode is also orig_page_offset | ||
1103 | * (To easily handle blocksize != pagesize case, the offset for the | ||
1104 | * donor inode is block unit). | ||
1105 | * 5:Update holecheck_path and orig_path to points a next proceeding extent, | ||
1106 | * then returns to step 2. | ||
1107 | * 6:Release holecheck_path, orig_path and set the len to moved_len | ||
1108 | * which shows the number of moved blocks. | ||
1109 | * The moved_len is useful for the command to calculate the file offset | ||
1110 | * for starting next move extent ioctl. | ||
1111 | * 7:Return 0 on success, or a negative error value on failure. | ||
1112 | */ | ||
1113 | int | ||
1114 | ext4_move_extents(struct file *o_filp, struct file *d_filp, | ||
1115 | __u64 orig_start, __u64 donor_start, __u64 len, | ||
1116 | __u64 *moved_len) | ||
1117 | { | ||
1118 | struct inode *orig_inode = o_filp->f_dentry->d_inode; | ||
1119 | struct inode *donor_inode = d_filp->f_dentry->d_inode; | ||
1120 | struct ext4_ext_path *orig_path = NULL, *holecheck_path = NULL; | ||
1121 | struct ext4_extent *ext_prev, *ext_cur, *ext_dummy; | ||
1122 | ext4_lblk_t block_start = orig_start; | ||
1123 | ext4_lblk_t block_end, seq_start, add_blocks, file_end, seq_blocks = 0; | ||
1124 | ext4_lblk_t rest_blocks; | ||
1125 | pgoff_t orig_page_offset = 0, seq_end_page; | ||
1126 | int ret, depth, last_extent = 0; | ||
1127 | int blocks_per_page = PAGE_CACHE_SIZE >> orig_inode->i_blkbits; | ||
1128 | int data_offset_in_page; | ||
1129 | int block_len_in_page; | ||
1130 | int uninit; | ||
1131 | |||
1132 | /* protect orig and donor against a truncate */ | ||
1133 | mext_inode_double_lock(orig_inode, donor_inode); | ||
1134 | |||
1135 | mext_double_down_read(orig_inode, donor_inode); | ||
1136 | /* Check the filesystem environment whether move_extent can be done */ | ||
1137 | ret = mext_check_arguments(orig_inode, donor_inode, orig_start, | ||
1138 | donor_start, &len, *moved_len); | ||
1139 | mext_double_up_read(orig_inode, donor_inode); | ||
1140 | if (ret) | ||
1141 | goto out2; | ||
1142 | |||
1143 | file_end = (i_size_read(orig_inode) - 1) >> orig_inode->i_blkbits; | ||
1144 | block_end = block_start + len - 1; | ||
1145 | if (file_end < block_end) | ||
1146 | len -= block_end - file_end; | ||
1147 | |||
1148 | get_ext_path(orig_path, orig_inode, block_start, ret); | ||
1149 | if (orig_path == NULL) | ||
1150 | goto out2; | ||
1151 | |||
1152 | /* Get path structure to check the hole */ | ||
1153 | get_ext_path(holecheck_path, orig_inode, block_start, ret); | ||
1154 | if (holecheck_path == NULL) | ||
1155 | goto out; | ||
1156 | |||
1157 | depth = ext_depth(orig_inode); | ||
1158 | ext_cur = holecheck_path[depth].p_ext; | ||
1159 | if (ext_cur == NULL) { | ||
1160 | ret = -EINVAL; | ||
1161 | goto out; | ||
1162 | } | ||
1163 | |||
1164 | /* | ||
1165 | * Get proper extent whose ee_block is beyond block_start | ||
1166 | * if block_start was within the hole. | ||
1167 | */ | ||
1168 | if (le32_to_cpu(ext_cur->ee_block) + | ||
1169 | ext4_ext_get_actual_len(ext_cur) - 1 < block_start) { | ||
1170 | last_extent = mext_next_extent(orig_inode, | ||
1171 | holecheck_path, &ext_cur); | ||
1172 | if (last_extent < 0) { | ||
1173 | ret = last_extent; | ||
1174 | goto out; | ||
1175 | } | ||
1176 | last_extent = mext_next_extent(orig_inode, orig_path, | ||
1177 | &ext_dummy); | ||
1178 | if (last_extent < 0) { | ||
1179 | ret = last_extent; | ||
1180 | goto out; | ||
1181 | } | ||
1182 | } | ||
1183 | seq_start = block_start; | ||
1184 | |||
1185 | /* No blocks within the specified range. */ | ||
1186 | if (le32_to_cpu(ext_cur->ee_block) > block_end) { | ||
1187 | ext4_debug("ext4 move extent: The specified range of file " | ||
1188 | "may be the hole\n"); | ||
1189 | ret = -EINVAL; | ||
1190 | goto out; | ||
1191 | } | ||
1192 | |||
1193 | /* Adjust start blocks */ | ||
1194 | add_blocks = min(le32_to_cpu(ext_cur->ee_block) + | ||
1195 | ext4_ext_get_actual_len(ext_cur), block_end + 1) - | ||
1196 | max(le32_to_cpu(ext_cur->ee_block), block_start); | ||
1197 | |||
1198 | while (!last_extent && le32_to_cpu(ext_cur->ee_block) <= block_end) { | ||
1199 | seq_blocks += add_blocks; | ||
1200 | |||
1201 | /* Adjust tail blocks */ | ||
1202 | if (seq_start + seq_blocks - 1 > block_end) | ||
1203 | seq_blocks = block_end - seq_start + 1; | ||
1204 | |||
1205 | ext_prev = ext_cur; | ||
1206 | last_extent = mext_next_extent(orig_inode, holecheck_path, | ||
1207 | &ext_cur); | ||
1208 | if (last_extent < 0) { | ||
1209 | ret = last_extent; | ||
1210 | break; | ||
1211 | } | ||
1212 | add_blocks = ext4_ext_get_actual_len(ext_cur); | ||
1213 | |||
1214 | /* | ||
1215 | * Extend the length of contiguous block (seq_blocks) | ||
1216 | * if extents are contiguous. | ||
1217 | */ | ||
1218 | if (ext4_can_extents_be_merged(orig_inode, | ||
1219 | ext_prev, ext_cur) && | ||
1220 | block_end >= le32_to_cpu(ext_cur->ee_block) && | ||
1221 | !last_extent) | ||
1222 | continue; | ||
1223 | |||
1224 | /* Is original extent is uninitialized */ | ||
1225 | uninit = ext4_ext_is_uninitialized(ext_prev); | ||
1226 | |||
1227 | data_offset_in_page = seq_start % blocks_per_page; | ||
1228 | |||
1229 | /* | ||
1230 | * Calculate data blocks count that should be swapped | ||
1231 | * at the first page. | ||
1232 | */ | ||
1233 | if (data_offset_in_page + seq_blocks > blocks_per_page) { | ||
1234 | /* Swapped blocks are across pages */ | ||
1235 | block_len_in_page = | ||
1236 | blocks_per_page - data_offset_in_page; | ||
1237 | } else { | ||
1238 | /* Swapped blocks are in a page */ | ||
1239 | block_len_in_page = seq_blocks; | ||
1240 | } | ||
1241 | |||
1242 | orig_page_offset = seq_start >> | ||
1243 | (PAGE_CACHE_SHIFT - orig_inode->i_blkbits); | ||
1244 | seq_end_page = (seq_start + seq_blocks - 1) >> | ||
1245 | (PAGE_CACHE_SHIFT - orig_inode->i_blkbits); | ||
1246 | seq_start = le32_to_cpu(ext_cur->ee_block); | ||
1247 | rest_blocks = seq_blocks; | ||
1248 | |||
1249 | /* Discard preallocations of two inodes */ | ||
1250 | down_write(&EXT4_I(orig_inode)->i_data_sem); | ||
1251 | ext4_discard_preallocations(orig_inode); | ||
1252 | up_write(&EXT4_I(orig_inode)->i_data_sem); | ||
1253 | |||
1254 | down_write(&EXT4_I(donor_inode)->i_data_sem); | ||
1255 | ext4_discard_preallocations(donor_inode); | ||
1256 | up_write(&EXT4_I(donor_inode)->i_data_sem); | ||
1257 | |||
1258 | while (orig_page_offset <= seq_end_page) { | ||
1259 | |||
1260 | /* Swap original branches with new branches */ | ||
1261 | ret = move_extent_par_page(o_filp, donor_inode, | ||
1262 | orig_page_offset, | ||
1263 | data_offset_in_page, | ||
1264 | block_len_in_page, uninit); | ||
1265 | if (ret < 0) | ||
1266 | goto out; | ||
1267 | orig_page_offset++; | ||
1268 | /* Count how many blocks we have exchanged */ | ||
1269 | *moved_len += block_len_in_page; | ||
1270 | BUG_ON(*moved_len > len); | ||
1271 | |||
1272 | data_offset_in_page = 0; | ||
1273 | rest_blocks -= block_len_in_page; | ||
1274 | if (rest_blocks > blocks_per_page) | ||
1275 | block_len_in_page = blocks_per_page; | ||
1276 | else | ||
1277 | block_len_in_page = rest_blocks; | ||
1278 | } | ||
1279 | |||
1280 | /* Decrease buffer counter */ | ||
1281 | if (holecheck_path) | ||
1282 | ext4_ext_drop_refs(holecheck_path); | ||
1283 | get_ext_path(holecheck_path, orig_inode, | ||
1284 | seq_start, ret); | ||
1285 | if (holecheck_path == NULL) | ||
1286 | break; | ||
1287 | depth = holecheck_path->p_depth; | ||
1288 | |||
1289 | /* Decrease buffer counter */ | ||
1290 | if (orig_path) | ||
1291 | ext4_ext_drop_refs(orig_path); | ||
1292 | get_ext_path(orig_path, orig_inode, seq_start, ret); | ||
1293 | if (orig_path == NULL) | ||
1294 | break; | ||
1295 | |||
1296 | ext_cur = holecheck_path[depth].p_ext; | ||
1297 | add_blocks = ext4_ext_get_actual_len(ext_cur); | ||
1298 | seq_blocks = 0; | ||
1299 | |||
1300 | } | ||
1301 | out: | ||
1302 | if (orig_path) { | ||
1303 | ext4_ext_drop_refs(orig_path); | ||
1304 | kfree(orig_path); | ||
1305 | } | ||
1306 | if (holecheck_path) { | ||
1307 | ext4_ext_drop_refs(holecheck_path); | ||
1308 | kfree(holecheck_path); | ||
1309 | } | ||
1310 | out2: | ||
1311 | mext_inode_double_unlock(orig_inode, donor_inode); | ||
1312 | |||
1313 | if (ret) | ||
1314 | return ret; | ||
1315 | |||
1316 | /* All of the specified blocks must be exchanged in succeed */ | ||
1317 | BUG_ON(*moved_len != len); | ||
1318 | |||
1319 | return 0; | ||
1320 | } | ||
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 07eb6649e4fa..de04013d16ff 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1782,7 +1782,7 @@ retry: | |||
1782 | if (IS_DIRSYNC(dir)) | 1782 | if (IS_DIRSYNC(dir)) |
1783 | ext4_handle_sync(handle); | 1783 | ext4_handle_sync(handle); |
1784 | 1784 | ||
1785 | inode = ext4_new_inode (handle, dir, mode); | 1785 | inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0); |
1786 | err = PTR_ERR(inode); | 1786 | err = PTR_ERR(inode); |
1787 | if (!IS_ERR(inode)) { | 1787 | if (!IS_ERR(inode)) { |
1788 | inode->i_op = &ext4_file_inode_operations; | 1788 | inode->i_op = &ext4_file_inode_operations; |
@@ -1816,7 +1816,7 @@ retry: | |||
1816 | if (IS_DIRSYNC(dir)) | 1816 | if (IS_DIRSYNC(dir)) |
1817 | ext4_handle_sync(handle); | 1817 | ext4_handle_sync(handle); |
1818 | 1818 | ||
1819 | inode = ext4_new_inode(handle, dir, mode); | 1819 | inode = ext4_new_inode(handle, dir, mode, &dentry->d_name, 0); |
1820 | err = PTR_ERR(inode); | 1820 | err = PTR_ERR(inode); |
1821 | if (!IS_ERR(inode)) { | 1821 | if (!IS_ERR(inode)) { |
1822 | init_special_inode(inode, inode->i_mode, rdev); | 1822 | init_special_inode(inode, inode->i_mode, rdev); |
@@ -1853,7 +1853,8 @@ retry: | |||
1853 | if (IS_DIRSYNC(dir)) | 1853 | if (IS_DIRSYNC(dir)) |
1854 | ext4_handle_sync(handle); | 1854 | ext4_handle_sync(handle); |
1855 | 1855 | ||
1856 | inode = ext4_new_inode(handle, dir, S_IFDIR | mode); | 1856 | inode = ext4_new_inode(handle, dir, S_IFDIR | mode, |
1857 | &dentry->d_name, 0); | ||
1857 | err = PTR_ERR(inode); | 1858 | err = PTR_ERR(inode); |
1858 | if (IS_ERR(inode)) | 1859 | if (IS_ERR(inode)) |
1859 | goto out_stop; | 1860 | goto out_stop; |
@@ -2264,7 +2265,8 @@ retry: | |||
2264 | if (IS_DIRSYNC(dir)) | 2265 | if (IS_DIRSYNC(dir)) |
2265 | ext4_handle_sync(handle); | 2266 | ext4_handle_sync(handle); |
2266 | 2267 | ||
2267 | inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO); | 2268 | inode = ext4_new_inode(handle, dir, S_IFLNK|S_IRWXUGO, |
2269 | &dentry->d_name, 0); | ||
2268 | err = PTR_ERR(inode); | 2270 | err = PTR_ERR(inode); |
2269 | if (IS_ERR(inode)) | 2271 | if (IS_ERR(inode)) |
2270 | goto out_stop; | 2272 | goto out_stop; |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 27eb289eea37..68b0351fc647 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -1002,7 +1002,7 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, | |||
1002 | " too large to resize to %llu blocks safely\n", | 1002 | " too large to resize to %llu blocks safely\n", |
1003 | sb->s_id, n_blocks_count); | 1003 | sb->s_id, n_blocks_count); |
1004 | if (sizeof(sector_t) < 8) | 1004 | if (sizeof(sector_t) < 8) |
1005 | ext4_warning(sb, __func__, "CONFIG_LBD not enabled"); | 1005 | ext4_warning(sb, __func__, "CONFIG_LBDAF not enabled"); |
1006 | return -EINVAL; | 1006 | return -EINVAL; |
1007 | } | 1007 | } |
1008 | 1008 | ||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 012c4251397e..8f4f079e6b9a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -37,7 +37,6 @@ | |||
37 | #include <linux/seq_file.h> | 37 | #include <linux/seq_file.h> |
38 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
39 | #include <linux/ctype.h> | 39 | #include <linux/ctype.h> |
40 | #include <linux/marker.h> | ||
41 | #include <linux/log2.h> | 40 | #include <linux/log2.h> |
42 | #include <linux/crc16.h> | 41 | #include <linux/crc16.h> |
43 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
@@ -47,6 +46,9 @@ | |||
47 | #include "xattr.h" | 46 | #include "xattr.h" |
48 | #include "acl.h" | 47 | #include "acl.h" |
49 | 48 | ||
49 | #define CREATE_TRACE_POINTS | ||
50 | #include <trace/events/ext4.h> | ||
51 | |||
50 | static int default_mb_history_length = 1000; | 52 | static int default_mb_history_length = 1000; |
51 | 53 | ||
52 | module_param_named(default_mb_history_length, default_mb_history_length, | 54 | module_param_named(default_mb_history_length, default_mb_history_length, |
@@ -301,7 +303,7 @@ static void ext4_handle_error(struct super_block *sb) | |||
301 | if (!test_opt(sb, ERRORS_CONT)) { | 303 | if (!test_opt(sb, ERRORS_CONT)) { |
302 | journal_t *journal = EXT4_SB(sb)->s_journal; | 304 | journal_t *journal = EXT4_SB(sb)->s_journal; |
303 | 305 | ||
304 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; | 306 | EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; |
305 | if (journal) | 307 | if (journal) |
306 | jbd2_journal_abort(journal, -EIO); | 308 | jbd2_journal_abort(journal, -EIO); |
307 | } | 309 | } |
@@ -414,7 +416,7 @@ void ext4_abort(struct super_block *sb, const char *function, | |||
414 | ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); | 416 | ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); |
415 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; | 417 | EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; |
416 | sb->s_flags |= MS_RDONLY; | 418 | sb->s_flags |= MS_RDONLY; |
417 | EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT; | 419 | EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; |
418 | if (EXT4_SB(sb)->s_journal) | 420 | if (EXT4_SB(sb)->s_journal) |
419 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); | 421 | jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); |
420 | } | 422 | } |
@@ -664,10 +666,6 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
664 | if (!ei) | 666 | if (!ei) |
665 | return NULL; | 667 | return NULL; |
666 | 668 | ||
667 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
668 | ei->i_acl = EXT4_ACL_NOT_CACHED; | ||
669 | ei->i_default_acl = EXT4_ACL_NOT_CACHED; | ||
670 | #endif | ||
671 | ei->vfs_inode.i_version = 1; | 669 | ei->vfs_inode.i_version = 1; |
672 | ei->vfs_inode.i_data.writeback_index = 0; | 670 | ei->vfs_inode.i_data.writeback_index = 0; |
673 | memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); | 671 | memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache)); |
@@ -733,18 +731,6 @@ static void destroy_inodecache(void) | |||
733 | 731 | ||
734 | static void ext4_clear_inode(struct inode *inode) | 732 | static void ext4_clear_inode(struct inode *inode) |
735 | { | 733 | { |
736 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | ||
737 | if (EXT4_I(inode)->i_acl && | ||
738 | EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) { | ||
739 | posix_acl_release(EXT4_I(inode)->i_acl); | ||
740 | EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED; | ||
741 | } | ||
742 | if (EXT4_I(inode)->i_default_acl && | ||
743 | EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) { | ||
744 | posix_acl_release(EXT4_I(inode)->i_default_acl); | ||
745 | EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED; | ||
746 | } | ||
747 | #endif | ||
748 | ext4_discard_preallocations(inode); | 734 | ext4_discard_preallocations(inode); |
749 | if (EXT4_JOURNAL(inode)) | 735 | if (EXT4_JOURNAL(inode)) |
750 | jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal, | 736 | jbd2_journal_release_jbd_inode(EXT4_SB(inode->i_sb)->s_journal, |
@@ -1474,7 +1460,7 @@ set_qf_format: | |||
1474 | break; | 1460 | break; |
1475 | #endif | 1461 | #endif |
1476 | case Opt_abort: | 1462 | case Opt_abort: |
1477 | set_opt(sbi->s_mount_opt, ABORT); | 1463 | sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; |
1478 | break; | 1464 | break; |
1479 | case Opt_nobarrier: | 1465 | case Opt_nobarrier: |
1480 | clear_opt(sbi->s_mount_opt, BARRIER); | 1466 | clear_opt(sbi->s_mount_opt, BARRIER); |
@@ -1653,7 +1639,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, | |||
1653 | ext4_commit_super(sb, 1); | 1639 | ext4_commit_super(sb, 1); |
1654 | if (test_opt(sb, DEBUG)) | 1640 | if (test_opt(sb, DEBUG)) |
1655 | printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " | 1641 | printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " |
1656 | "bpg=%lu, ipg=%lu, mo=%04lx]\n", | 1642 | "bpg=%lu, ipg=%lu, mo=%04x]\n", |
1657 | sb->s_blocksize, | 1643 | sb->s_blocksize, |
1658 | sbi->s_groups_count, | 1644 | sbi->s_groups_count, |
1659 | EXT4_BLOCKS_PER_GROUP(sb), | 1645 | EXT4_BLOCKS_PER_GROUP(sb), |
@@ -1957,7 +1943,7 @@ static loff_t ext4_max_size(int blkbits, int has_huge_files) | |||
1957 | /* small i_blocks in vfs inode? */ | 1943 | /* small i_blocks in vfs inode? */ |
1958 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { | 1944 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { |
1959 | /* | 1945 | /* |
1960 | * CONFIG_LBD is not enabled implies the inode | 1946 | * CONFIG_LBDAF is not enabled implies the inode |
1961 | * i_block represent total blocks in 512 bytes | 1947 | * i_block represent total blocks in 512 bytes |
1962 | * 32 == size of vfs inode i_blocks * 8 | 1948 | * 32 == size of vfs inode i_blocks * 8 |
1963 | */ | 1949 | */ |
@@ -2000,7 +1986,7 @@ static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) | |||
2000 | 1986 | ||
2001 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { | 1987 | if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { |
2002 | /* | 1988 | /* |
2003 | * !has_huge_files or CONFIG_LBD not enabled implies that | 1989 | * !has_huge_files or CONFIG_LBDAF not enabled implies that |
2004 | * the inode i_block field represents total file blocks in | 1990 | * the inode i_block field represents total file blocks in |
2005 | * 2^32 512-byte sectors == size of vfs inode i_blocks * 8 | 1991 | * 2^32 512-byte sectors == size of vfs inode i_blocks * 8 |
2006 | */ | 1992 | */ |
@@ -2204,6 +2190,7 @@ EXT4_RO_ATTR(session_write_kbytes); | |||
2204 | EXT4_RO_ATTR(lifetime_write_kbytes); | 2190 | EXT4_RO_ATTR(lifetime_write_kbytes); |
2205 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, | 2191 | EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, sbi_ui_show, |
2206 | inode_readahead_blks_store, s_inode_readahead_blks); | 2192 | inode_readahead_blks_store, s_inode_readahead_blks); |
2193 | EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); | ||
2207 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); | 2194 | EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); |
2208 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); | 2195 | EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); |
2209 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); | 2196 | EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); |
@@ -2216,6 +2203,7 @@ static struct attribute *ext4_attrs[] = { | |||
2216 | ATTR_LIST(session_write_kbytes), | 2203 | ATTR_LIST(session_write_kbytes), |
2217 | ATTR_LIST(lifetime_write_kbytes), | 2204 | ATTR_LIST(lifetime_write_kbytes), |
2218 | ATTR_LIST(inode_readahead_blks), | 2205 | ATTR_LIST(inode_readahead_blks), |
2206 | ATTR_LIST(inode_goal), | ||
2219 | ATTR_LIST(mb_stats), | 2207 | ATTR_LIST(mb_stats), |
2220 | ATTR_LIST(mb_max_to_scan), | 2208 | ATTR_LIST(mb_max_to_scan), |
2221 | ATTR_LIST(mb_min_to_scan), | 2209 | ATTR_LIST(mb_min_to_scan), |
@@ -2436,13 +2424,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2436 | if (has_huge_files) { | 2424 | if (has_huge_files) { |
2437 | /* | 2425 | /* |
2438 | * Large file size enabled file system can only be | 2426 | * Large file size enabled file system can only be |
2439 | * mount if kernel is build with CONFIG_LBD | 2427 | * mount if kernel is build with CONFIG_LBDAF |
2440 | */ | 2428 | */ |
2441 | if (sizeof(root->i_blocks) < sizeof(u64) && | 2429 | if (sizeof(root->i_blocks) < sizeof(u64) && |
2442 | !(sb->s_flags & MS_RDONLY)) { | 2430 | !(sb->s_flags & MS_RDONLY)) { |
2443 | ext4_msg(sb, KERN_ERR, "Filesystem with huge " | 2431 | ext4_msg(sb, KERN_ERR, "Filesystem with huge " |
2444 | "files cannot be mounted read-write " | 2432 | "files cannot be mounted read-write " |
2445 | "without CONFIG_LBD"); | 2433 | "without CONFIG_LBDAF"); |
2446 | goto failed_mount; | 2434 | goto failed_mount; |
2447 | } | 2435 | } |
2448 | } | 2436 | } |
@@ -2566,7 +2554,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2566 | ext4_msg(sb, KERN_ERR, "filesystem" | 2554 | ext4_msg(sb, KERN_ERR, "filesystem" |
2567 | " too large to mount safely"); | 2555 | " too large to mount safely"); |
2568 | if (sizeof(sector_t) < 8) | 2556 | if (sizeof(sector_t) < 8) |
2569 | ext4_msg(sb, KERN_WARNING, "CONFIG_LBD not enabled"); | 2557 | ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); |
2570 | goto failed_mount; | 2558 | goto failed_mount; |
2571 | } | 2559 | } |
2572 | 2560 | ||
@@ -3346,7 +3334,7 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
3346 | int ret = 0; | 3334 | int ret = 0; |
3347 | tid_t target; | 3335 | tid_t target; |
3348 | 3336 | ||
3349 | trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait); | 3337 | trace_ext4_sync_fs(sb, wait); |
3350 | if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { | 3338 | if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) { |
3351 | if (wait) | 3339 | if (wait) |
3352 | jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); | 3340 | jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target); |
@@ -3450,7 +3438,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
3450 | goto restore_opts; | 3438 | goto restore_opts; |
3451 | } | 3439 | } |
3452 | 3440 | ||
3453 | if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) | 3441 | if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) |
3454 | ext4_abort(sb, __func__, "Abort forced by user"); | 3442 | ext4_abort(sb, __func__, "Abort forced by user"); |
3455 | 3443 | ||
3456 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | | 3444 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | |
@@ -3465,7 +3453,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
3465 | 3453 | ||
3466 | if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || | 3454 | if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || |
3467 | n_blocks_count > ext4_blocks_count(es)) { | 3455 | n_blocks_count > ext4_blocks_count(es)) { |
3468 | if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) { | 3456 | if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) { |
3469 | err = -EROFS; | 3457 | err = -EROFS; |
3470 | goto restore_opts; | 3458 | goto restore_opts; |
3471 | } | 3459 | } |
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index b42602298087..923990e4f16e 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c | |||
@@ -241,7 +241,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) | |||
241 | while (*fclus < cluster) { | 241 | while (*fclus < cluster) { |
242 | /* prevent the infinite loop of cluster chain */ | 242 | /* prevent the infinite loop of cluster chain */ |
243 | if (*fclus > limit) { | 243 | if (*fclus > limit) { |
244 | fat_fs_panic(sb, "%s: detected the cluster chain loop" | 244 | fat_fs_error(sb, "%s: detected the cluster chain loop" |
245 | " (i_pos %lld)", __func__, | 245 | " (i_pos %lld)", __func__, |
246 | MSDOS_I(inode)->i_pos); | 246 | MSDOS_I(inode)->i_pos); |
247 | nr = -EIO; | 247 | nr = -EIO; |
@@ -252,7 +252,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) | |||
252 | if (nr < 0) | 252 | if (nr < 0) |
253 | goto out; | 253 | goto out; |
254 | else if (nr == FAT_ENT_FREE) { | 254 | else if (nr == FAT_ENT_FREE) { |
255 | fat_fs_panic(sb, "%s: invalid cluster chain" | 255 | fat_fs_error(sb, "%s: invalid cluster chain" |
256 | " (i_pos %lld)", __func__, | 256 | " (i_pos %lld)", __func__, |
257 | MSDOS_I(inode)->i_pos); | 257 | MSDOS_I(inode)->i_pos); |
258 | nr = -EIO; | 258 | nr = -EIO; |
@@ -285,7 +285,7 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) | |||
285 | if (ret < 0) | 285 | if (ret < 0) |
286 | return ret; | 286 | return ret; |
287 | else if (ret == FAT_ENT_EOF) { | 287 | else if (ret == FAT_ENT_EOF) { |
288 | fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)", | 288 | fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", |
289 | __func__, MSDOS_I(inode)->i_pos); | 289 | __func__, MSDOS_I(inode)->i_pos); |
290 | return -EIO; | 290 | return -EIO; |
291 | } | 291 | } |
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index f3500294eec5..530b4ca01510 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -16,12 +16,24 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/buffer_head.h> | 19 | #include <linux/buffer_head.h> |
21 | #include <linux/compat.h> | 20 | #include <linux/compat.h> |
22 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
23 | #include "fat.h" | 22 | #include "fat.h" |
24 | 23 | ||
24 | /* | ||
25 | * Maximum buffer size of short name. | ||
26 | * [(MSDOS_NAME + '.') * max one char + nul] | ||
27 | * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul] | ||
28 | */ | ||
29 | #define FAT_MAX_SHORT_SIZE ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1) | ||
30 | /* | ||
31 | * Maximum buffer size of unicode chars from slots. | ||
32 | * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)] | ||
33 | */ | ||
34 | #define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1) | ||
35 | #define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t)) | ||
36 | |||
25 | static inline loff_t fat_make_i_pos(struct super_block *sb, | 37 | static inline loff_t fat_make_i_pos(struct super_block *sb, |
26 | struct buffer_head *bh, | 38 | struct buffer_head *bh, |
27 | struct msdos_dir_entry *de) | 39 | struct msdos_dir_entry *de) |
@@ -171,7 +183,8 @@ static inline int fat_uni_to_x8(struct msdos_sb_info *sbi, const wchar_t *uni, | |||
171 | unsigned char *buf, int size) | 183 | unsigned char *buf, int size) |
172 | { | 184 | { |
173 | if (sbi->options.utf8) | 185 | if (sbi->options.utf8) |
174 | return utf8_wcstombs(buf, uni, size); | 186 | return utf16s_to_utf8s(uni, FAT_MAX_UNI_CHARS, |
187 | UTF16_HOST_ENDIAN, buf, size); | ||
175 | else | 188 | else |
176 | return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate, | 189 | return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate, |
177 | sbi->nls_io); | 190 | sbi->nls_io); |
@@ -325,19 +338,6 @@ parse_long: | |||
325 | } | 338 | } |
326 | 339 | ||
327 | /* | 340 | /* |
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 | /* | ||
341 | * Return values: negative -> error, 0 -> not found, positive -> found, | 341 | * Return values: negative -> error, 0 -> not found, positive -> found, |
342 | * value is the total amount of slots, including the shortname entry. | 342 | * value is the total amount of slots, including the shortname entry. |
343 | */ | 343 | */ |
@@ -1334,7 +1334,7 @@ found: | |||
1334 | goto error_remove; | 1334 | goto error_remove; |
1335 | } | 1335 | } |
1336 | if (dir->i_size & (sbi->cluster_size - 1)) { | 1336 | if (dir->i_size & (sbi->cluster_size - 1)) { |
1337 | fat_fs_panic(sb, "Odd directory size"); | 1337 | fat_fs_error(sb, "Odd directory size"); |
1338 | dir->i_size = (dir->i_size + sbi->cluster_size - 1) | 1338 | dir->i_size = (dir->i_size + sbi->cluster_size - 1) |
1339 | & ~((loff_t)sbi->cluster_size - 1); | 1339 | & ~((loff_t)sbi->cluster_size - 1); |
1340 | } | 1340 | } |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index e4d88527b5dd..adb0e72a176d 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -17,6 +17,10 @@ | |||
17 | #define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ | 17 | #define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ |
18 | #define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ | 18 | #define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ |
19 | 19 | ||
20 | #define FAT_ERRORS_CONT 1 /* ignore error and continue */ | ||
21 | #define FAT_ERRORS_PANIC 2 /* panic on error */ | ||
22 | #define FAT_ERRORS_RO 3 /* remount r/o on error */ | ||
23 | |||
20 | struct fat_mount_options { | 24 | struct fat_mount_options { |
21 | uid_t fs_uid; | 25 | uid_t fs_uid; |
22 | gid_t fs_gid; | 26 | gid_t fs_gid; |
@@ -26,6 +30,7 @@ struct fat_mount_options { | |||
26 | char *iocharset; /* Charset used for filename input/display */ | 30 | char *iocharset; /* Charset used for filename input/display */ |
27 | unsigned short shortname; /* flags for shortname display/create rule */ | 31 | unsigned short shortname; /* flags for shortname display/create rule */ |
28 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ | 32 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ |
33 | unsigned char errors; /* On error: continue, panic, remount-ro */ | ||
29 | unsigned short allow_utime;/* permission for setting the [am]time */ | 34 | unsigned short allow_utime;/* permission for setting the [am]time */ |
30 | unsigned quiet:1, /* set = fake successful chmods and chowns */ | 35 | unsigned quiet:1, /* set = fake successful chmods and chowns */ |
31 | showexec:1, /* set = only set x bit for com/exe/bat */ | 36 | showexec:1, /* set = only set x bit for com/exe/bat */ |
@@ -316,7 +321,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
316 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, | 321 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, |
317 | struct inode *i2); | 322 | struct inode *i2); |
318 | /* fat/misc.c */ | 323 | /* fat/misc.c */ |
319 | extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) | 324 | extern void fat_fs_error(struct super_block *s, const char *fmt, ...) |
320 | __attribute__ ((format (printf, 2, 3))) __cold; | 325 | __attribute__ ((format (printf, 2, 3))) __cold; |
321 | extern void fat_clusters_flush(struct super_block *sb); | 326 | extern void fat_clusters_flush(struct super_block *sb); |
322 | extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); | 327 | extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); |
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 618f5305c2e4..a81037721a6f 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
@@ -348,7 +348,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) | |||
348 | 348 | ||
349 | if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { | 349 | if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { |
350 | fatent_brelse(fatent); | 350 | fatent_brelse(fatent); |
351 | fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry); | 351 | fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); |
352 | return -EIO; | 352 | return -EIO; |
353 | } | 353 | } |
354 | 354 | ||
@@ -560,7 +560,7 @@ int fat_free_clusters(struct inode *inode, int cluster) | |||
560 | err = cluster; | 560 | err = cluster; |
561 | goto error; | 561 | goto error; |
562 | } else if (cluster == FAT_ENT_FREE) { | 562 | } else if (cluster == FAT_ENT_FREE) { |
563 | fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF", | 563 | fat_fs_error(sb, "%s: deleting FAT entry beyond EOF", |
564 | __func__); | 564 | __func__); |
565 | err = -EIO; | 565 | err = -EIO; |
566 | goto error; | 566 | goto error; |
diff --git a/fs/fat/file.c b/fs/fat/file.c index e955a56b4e5e..f042b965c95c 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -18,106 +18,112 @@ | |||
18 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include "fat.h" | 19 | #include "fat.h" |
20 | 20 | ||
21 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 21 | static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) |
22 | unsigned int cmd, unsigned long arg) | ||
23 | { | 22 | { |
23 | u32 attr; | ||
24 | |||
25 | mutex_lock(&inode->i_mutex); | ||
26 | attr = fat_make_attrs(inode); | ||
27 | mutex_unlock(&inode->i_mutex); | ||
28 | |||
29 | return put_user(attr, user_attr); | ||
30 | } | ||
31 | |||
32 | static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) | ||
33 | { | ||
34 | struct inode *inode = file->f_path.dentry->d_inode; | ||
24 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 35 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
25 | u32 __user *user_attr = (u32 __user *)arg; | 36 | int is_dir = S_ISDIR(inode->i_mode); |
37 | u32 attr, oldattr; | ||
38 | struct iattr ia; | ||
39 | int err; | ||
26 | 40 | ||
27 | switch (cmd) { | 41 | err = get_user(attr, user_attr); |
28 | case FAT_IOCTL_GET_ATTRIBUTES: | 42 | if (err) |
29 | { | 43 | goto out; |
30 | u32 attr; | ||
31 | 44 | ||
32 | mutex_lock(&inode->i_mutex); | 45 | mutex_lock(&inode->i_mutex); |
33 | attr = fat_make_attrs(inode); | 46 | err = mnt_want_write(file->f_path.mnt); |
34 | mutex_unlock(&inode->i_mutex); | 47 | if (err) |
48 | goto out_unlock_inode; | ||
35 | 49 | ||
36 | return put_user(attr, user_attr); | 50 | /* |
51 | * ATTR_VOLUME and ATTR_DIR cannot be changed; this also | ||
52 | * prevents the user from turning us into a VFAT | ||
53 | * longname entry. Also, we obviously can't set | ||
54 | * any of the NTFS attributes in the high 24 bits. | ||
55 | */ | ||
56 | attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); | ||
57 | /* Merge in ATTR_VOLUME and ATTR_DIR */ | ||
58 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | | ||
59 | (is_dir ? ATTR_DIR : 0); | ||
60 | oldattr = fat_make_attrs(inode); | ||
61 | |||
62 | /* Equivalent to a chmod() */ | ||
63 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
64 | ia.ia_ctime = current_fs_time(inode->i_sb); | ||
65 | if (is_dir) | ||
66 | ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); | ||
67 | else { | ||
68 | ia.ia_mode = fat_make_mode(sbi, attr, | ||
69 | S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); | ||
37 | } | 70 | } |
38 | case FAT_IOCTL_SET_ATTRIBUTES: | ||
39 | { | ||
40 | u32 attr, oldattr; | ||
41 | int err, is_dir = S_ISDIR(inode->i_mode); | ||
42 | struct iattr ia; | ||
43 | 71 | ||
44 | err = get_user(attr, user_attr); | 72 | /* The root directory has no attributes */ |
45 | if (err) | 73 | if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { |
46 | return err; | 74 | err = -EINVAL; |
75 | goto out_drop_write; | ||
76 | } | ||
47 | 77 | ||
48 | mutex_lock(&inode->i_mutex); | 78 | if (sbi->options.sys_immutable && |
49 | 79 | ((attr | oldattr) & ATTR_SYS) && | |
50 | err = mnt_want_write(filp->f_path.mnt); | 80 | !capable(CAP_LINUX_IMMUTABLE)) { |
51 | if (err) | 81 | err = -EPERM; |
52 | goto up_no_drop_write; | 82 | goto out_drop_write; |
53 | 83 | } | |
54 | /* | ||
55 | * ATTR_VOLUME and ATTR_DIR cannot be changed; this also | ||
56 | * prevents the user from turning us into a VFAT | ||
57 | * longname entry. Also, we obviously can't set | ||
58 | * any of the NTFS attributes in the high 24 bits. | ||
59 | */ | ||
60 | attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); | ||
61 | /* Merge in ATTR_VOLUME and ATTR_DIR */ | ||
62 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | | ||
63 | (is_dir ? ATTR_DIR : 0); | ||
64 | oldattr = fat_make_attrs(inode); | ||
65 | |||
66 | /* Equivalent to a chmod() */ | ||
67 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | ||
68 | ia.ia_ctime = current_fs_time(inode->i_sb); | ||
69 | if (is_dir) | ||
70 | ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); | ||
71 | else { | ||
72 | ia.ia_mode = fat_make_mode(sbi, attr, | ||
73 | S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); | ||
74 | } | ||
75 | 84 | ||
76 | /* The root directory has no attributes */ | 85 | /* |
77 | if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { | 86 | * The security check is questionable... We single |
78 | err = -EINVAL; | 87 | * out the RO attribute for checking by the security |
79 | goto up; | 88 | * module, just because it maps to a file mode. |
80 | } | 89 | */ |
90 | err = security_inode_setattr(file->f_path.dentry, &ia); | ||
91 | if (err) | ||
92 | goto out_drop_write; | ||
81 | 93 | ||
82 | if (sbi->options.sys_immutable) { | 94 | /* This MUST be done before doing anything irreversible... */ |
83 | if ((attr | oldattr) & ATTR_SYS) { | 95 | err = fat_setattr(file->f_path.dentry, &ia); |
84 | if (!capable(CAP_LINUX_IMMUTABLE)) { | 96 | if (err) |
85 | err = -EPERM; | 97 | goto out_drop_write; |
86 | goto up; | 98 | |
87 | } | 99 | fsnotify_change(file->f_path.dentry, ia.ia_valid); |
88 | } | 100 | if (sbi->options.sys_immutable) { |
89 | } | 101 | if (attr & ATTR_SYS) |
102 | inode->i_flags |= S_IMMUTABLE; | ||
103 | else | ||
104 | inode->i_flags &= S_IMMUTABLE; | ||
105 | } | ||
90 | 106 | ||
91 | /* | 107 | fat_save_attrs(inode, attr); |
92 | * The security check is questionable... We single | 108 | mark_inode_dirty(inode); |
93 | * out the RO attribute for checking by the security | 109 | out_drop_write: |
94 | * module, just because it maps to a file mode. | 110 | mnt_drop_write(file->f_path.mnt); |
95 | */ | 111 | out_unlock_inode: |
96 | err = security_inode_setattr(filp->f_path.dentry, &ia); | 112 | mutex_unlock(&inode->i_mutex); |
97 | if (err) | 113 | out: |
98 | goto up; | 114 | return err; |
99 | 115 | } | |
100 | /* This MUST be done before doing anything irreversible... */ | ||
101 | err = fat_setattr(filp->f_path.dentry, &ia); | ||
102 | if (err) | ||
103 | goto up; | ||
104 | |||
105 | fsnotify_change(filp->f_path.dentry, ia.ia_valid); | ||
106 | if (sbi->options.sys_immutable) { | ||
107 | if (attr & ATTR_SYS) | ||
108 | inode->i_flags |= S_IMMUTABLE; | ||
109 | else | ||
110 | inode->i_flags &= S_IMMUTABLE; | ||
111 | } | ||
112 | 116 | ||
113 | fat_save_attrs(inode, attr); | 117 | int fat_generic_ioctl(struct inode *inode, struct file *filp, |
114 | mark_inode_dirty(inode); | 118 | unsigned int cmd, unsigned long arg) |
115 | up: | 119 | { |
116 | mnt_drop_write(filp->f_path.mnt); | 120 | u32 __user *user_attr = (u32 __user *)arg; |
117 | up_no_drop_write: | 121 | |
118 | mutex_unlock(&inode->i_mutex); | 122 | switch (cmd) { |
119 | return err; | 123 | case FAT_IOCTL_GET_ATTRIBUTES: |
120 | } | 124 | return fat_ioctl_get_attributes(inode, user_attr); |
125 | case FAT_IOCTL_SET_ATTRIBUTES: | ||
126 | return fat_ioctl_set_attributes(filp, user_attr); | ||
121 | default: | 127 | default: |
122 | return -ENOTTY; /* Inappropriate ioctl for device */ | 128 | return -ENOTTY; /* Inappropriate ioctl for device */ |
123 | } | 129 | } |
@@ -128,7 +134,7 @@ static int fat_file_release(struct inode *inode, struct file *filp) | |||
128 | if ((filp->f_mode & FMODE_WRITE) && | 134 | if ((filp->f_mode & FMODE_WRITE) && |
129 | MSDOS_SB(inode->i_sb)->options.flush) { | 135 | MSDOS_SB(inode->i_sb)->options.flush) { |
130 | fat_flush_inodes(inode->i_sb, inode, NULL); | 136 | fat_flush_inodes(inode->i_sb, inode, NULL); |
131 | congestion_wait(WRITE, HZ/10); | 137 | congestion_wait(BLK_RW_ASYNC, HZ/10); |
132 | } | 138 | } |
133 | return 0; | 139 | return 0; |
134 | } | 140 | } |
@@ -225,7 +231,7 @@ static int fat_free(struct inode *inode, int skip) | |||
225 | fatent_brelse(&fatent); | 231 | fatent_brelse(&fatent); |
226 | return 0; | 232 | return 0; |
227 | } else if (ret == FAT_ENT_FREE) { | 233 | } else if (ret == FAT_ENT_FREE) { |
228 | fat_fs_panic(sb, | 234 | fat_fs_error(sb, |
229 | "%s: invalid cluster chain (i_pos %lld)", | 235 | "%s: invalid cluster chain (i_pos %lld)", |
230 | __func__, MSDOS_I(inode)->i_pos); | 236 | __func__, MSDOS_I(inode)->i_pos); |
231 | ret = -EIO; | 237 | ret = -EIO; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 51a5ecf9000a..8970d8c49bb0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -76,7 +76,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, | |||
76 | return 0; | 76 | return 0; |
77 | 77 | ||
78 | if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { | 78 | if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { |
79 | fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", | 79 | fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)", |
80 | MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); | 80 | MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); |
81 | return -EIO; | 81 | return -EIO; |
82 | } | 82 | } |
@@ -856,6 +856,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
856 | seq_puts(m, ",flush"); | 856 | seq_puts(m, ",flush"); |
857 | if (opts->tz_utc) | 857 | if (opts->tz_utc) |
858 | seq_puts(m, ",tz=UTC"); | 858 | seq_puts(m, ",tz=UTC"); |
859 | if (opts->errors == FAT_ERRORS_CONT) | ||
860 | seq_puts(m, ",errors=continue"); | ||
861 | else if (opts->errors == FAT_ERRORS_PANIC) | ||
862 | seq_puts(m, ",errors=panic"); | ||
863 | else | ||
864 | seq_puts(m, ",errors=remount-ro"); | ||
859 | 865 | ||
860 | return 0; | 866 | return 0; |
861 | } | 867 | } |
@@ -868,7 +874,8 @@ enum { | |||
868 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 874 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
869 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 875 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
870 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 876 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
871 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, | 877 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, |
878 | Opt_err_panic, Opt_err_ro, Opt_err, | ||
872 | }; | 879 | }; |
873 | 880 | ||
874 | static const match_table_t fat_tokens = { | 881 | static const match_table_t fat_tokens = { |
@@ -891,6 +898,11 @@ static const match_table_t fat_tokens = { | |||
891 | {Opt_showexec, "showexec"}, | 898 | {Opt_showexec, "showexec"}, |
892 | {Opt_debug, "debug"}, | 899 | {Opt_debug, "debug"}, |
893 | {Opt_immutable, "sys_immutable"}, | 900 | {Opt_immutable, "sys_immutable"}, |
901 | {Opt_flush, "flush"}, | ||
902 | {Opt_tz_utc, "tz=UTC"}, | ||
903 | {Opt_err_cont, "errors=continue"}, | ||
904 | {Opt_err_panic, "errors=panic"}, | ||
905 | {Opt_err_ro, "errors=remount-ro"}, | ||
894 | {Opt_obsolate, "conv=binary"}, | 906 | {Opt_obsolate, "conv=binary"}, |
895 | {Opt_obsolate, "conv=text"}, | 907 | {Opt_obsolate, "conv=text"}, |
896 | {Opt_obsolate, "conv=auto"}, | 908 | {Opt_obsolate, "conv=auto"}, |
@@ -902,8 +914,6 @@ static const match_table_t fat_tokens = { | |||
902 | {Opt_obsolate, "cvf_format=%20s"}, | 914 | {Opt_obsolate, "cvf_format=%20s"}, |
903 | {Opt_obsolate, "cvf_options=%100s"}, | 915 | {Opt_obsolate, "cvf_options=%100s"}, |
904 | {Opt_obsolate, "posix"}, | 916 | {Opt_obsolate, "posix"}, |
905 | {Opt_flush, "flush"}, | ||
906 | {Opt_tz_utc, "tz=UTC"}, | ||
907 | {Opt_err, NULL}, | 917 | {Opt_err, NULL}, |
908 | }; | 918 | }; |
909 | static const match_table_t msdos_tokens = { | 919 | static const match_table_t msdos_tokens = { |
@@ -956,7 +966,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
956 | 966 | ||
957 | opts->fs_uid = current_uid(); | 967 | opts->fs_uid = current_uid(); |
958 | opts->fs_gid = current_gid(); | 968 | opts->fs_gid = current_gid(); |
959 | opts->fs_fmask = current_umask(); | 969 | opts->fs_fmask = opts->fs_dmask = current_umask(); |
960 | opts->allow_utime = -1; | 970 | opts->allow_utime = -1; |
961 | opts->codepage = fat_default_codepage; | 971 | opts->codepage = fat_default_codepage; |
962 | opts->iocharset = fat_default_iocharset; | 972 | opts->iocharset = fat_default_iocharset; |
@@ -973,6 +983,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
973 | opts->numtail = 1; | 983 | opts->numtail = 1; |
974 | opts->usefree = opts->nocase = 0; | 984 | opts->usefree = opts->nocase = 0; |
975 | opts->tz_utc = 0; | 985 | opts->tz_utc = 0; |
986 | opts->errors = FAT_ERRORS_RO; | ||
976 | *debug = 0; | 987 | *debug = 0; |
977 | 988 | ||
978 | if (!options) | 989 | if (!options) |
@@ -1065,6 +1076,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1065 | case Opt_tz_utc: | 1076 | case Opt_tz_utc: |
1066 | opts->tz_utc = 1; | 1077 | opts->tz_utc = 1; |
1067 | break; | 1078 | break; |
1079 | case Opt_err_cont: | ||
1080 | opts->errors = FAT_ERRORS_CONT; | ||
1081 | break; | ||
1082 | case Opt_err_panic: | ||
1083 | opts->errors = FAT_ERRORS_PANIC; | ||
1084 | break; | ||
1085 | case Opt_err_ro: | ||
1086 | opts->errors = FAT_ERRORS_RO; | ||
1087 | break; | ||
1068 | 1088 | ||
1069 | /* msdos specific */ | 1089 | /* msdos specific */ |
1070 | case Opt_dots: | 1090 | case Opt_dots: |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index ac39ebcc1496..a6c20473dfd7 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
@@ -12,14 +12,19 @@ | |||
12 | #include "fat.h" | 12 | #include "fat.h" |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * fat_fs_panic reports a severe file system problem and sets the file system | 15 | * fat_fs_error reports a file system problem that might indicate fa data |
16 | * read-only. The file system can be made writable again by remounting it. | 16 | * corruption/inconsistency. Depending on 'errors' mount option the |
17 | * panic() is called, or error message is printed FAT and nothing is done, | ||
18 | * or filesystem is remounted read-only (default behavior). | ||
19 | * In case the file system is remounted read-only, it can be made writable | ||
20 | * again by remounting it. | ||
17 | */ | 21 | */ |
18 | void fat_fs_panic(struct super_block *s, const char *fmt, ...) | 22 | void fat_fs_error(struct super_block *s, const char *fmt, ...) |
19 | { | 23 | { |
24 | struct fat_mount_options *opts = &MSDOS_SB(s)->options; | ||
20 | va_list args; | 25 | va_list args; |
21 | 26 | ||
22 | printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id); | 27 | printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id); |
23 | 28 | ||
24 | printk(KERN_ERR " "); | 29 | printk(KERN_ERR " "); |
25 | va_start(args, fmt); | 30 | va_start(args, fmt); |
@@ -27,13 +32,14 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...) | |||
27 | va_end(args); | 32 | va_end(args); |
28 | printk("\n"); | 33 | printk("\n"); |
29 | 34 | ||
30 | if (!(s->s_flags & MS_RDONLY)) { | 35 | if (opts->errors == FAT_ERRORS_PANIC) |
36 | panic(" FAT fs panic from previous error\n"); | ||
37 | else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) { | ||
31 | s->s_flags |= MS_RDONLY; | 38 | s->s_flags |= MS_RDONLY; |
32 | printk(KERN_ERR " File system has been set read-only\n"); | 39 | printk(KERN_ERR " File system has been set read-only\n"); |
33 | } | 40 | } |
34 | } | 41 | } |
35 | 42 | EXPORT_SYMBOL_GPL(fat_fs_error); | |
36 | EXPORT_SYMBOL_GPL(fat_fs_panic); | ||
37 | 43 | ||
38 | /* Flushes the number of free clusters on FAT32 */ | 44 | /* Flushes the number of free clusters on FAT32 */ |
39 | /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ | 45 | /* XXX: Need to write one per FSINFO block. Currently only writes 1 */ |
@@ -124,7 +130,7 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) | |||
124 | mark_inode_dirty(inode); | 130 | mark_inode_dirty(inode); |
125 | } | 131 | } |
126 | if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { | 132 | if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { |
127 | fat_fs_panic(sb, "clusters badly computed (%d != %llu)", | 133 | fat_fs_error(sb, "clusters badly computed (%d != %llu)", |
128 | new_fclus, | 134 | new_fclus, |
129 | (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); | 135 | (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); |
130 | fat_cache_inval_inode(inode); | 136 | fat_cache_inval_inode(inode); |
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 20f522861355..bbc94ae4fd77 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
12 | #include <linux/smp_lock.h> | ||
13 | #include "fat.h" | 12 | #include "fat.h" |
14 | 13 | ||
15 | /* Characters that are undesirable in an MS-DOS file name */ | 14 | /* Characters that are undesirable in an MS-DOS file name */ |
@@ -608,7 +607,7 @@ error_inode: | |||
608 | sinfo.bh = NULL; | 607 | sinfo.bh = NULL; |
609 | } | 608 | } |
610 | if (corrupt < 0) { | 609 | if (corrupt < 0) { |
611 | fat_fs_panic(new_dir->i_sb, | 610 | fat_fs_error(new_dir->i_sb, |
612 | "%s: Filesystem corrupted (i_pos %lld)", | 611 | "%s: Filesystem corrupted (i_pos %lld)", |
613 | __func__, sinfo.i_pos); | 612 | __func__, sinfo.i_pos); |
614 | } | 613 | } |
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b50ecbe97f83..cb6e83557112 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
20 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/smp_lock.h> | ||
23 | #include <linux/buffer_head.h> | 22 | #include <linux/buffer_head.h> |
24 | #include <linux/namei.h> | 23 | #include <linux/namei.h> |
25 | #include "fat.h" | 24 | #include "fat.h" |
@@ -502,11 +501,11 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, | |||
502 | if (utf8) { | 501 | if (utf8) { |
503 | int name_len = strlen(name); | 502 | int name_len = strlen(name); |
504 | 503 | ||
505 | *outlen = utf8_mbstowcs((wchar_t *)outname, name, PATH_MAX); | 504 | *outlen = utf8s_to_utf16s(name, PATH_MAX, (wchar_t *) outname); |
506 | 505 | ||
507 | /* | 506 | /* |
508 | * We stripped '.'s before and set len appropriately, | 507 | * We stripped '.'s before and set len appropriately, |
509 | * but utf8_mbstowcs doesn't care about len | 508 | * but utf8s_to_utf16s doesn't care about len |
510 | */ | 509 | */ |
511 | *outlen -= (name_len - len); | 510 | *outlen -= (name_len - len); |
512 | 511 | ||
@@ -1030,7 +1029,7 @@ error_inode: | |||
1030 | sinfo.bh = NULL; | 1029 | sinfo.bh = NULL; |
1031 | } | 1030 | } |
1032 | if (corrupt < 0) { | 1031 | if (corrupt < 0) { |
1033 | fat_fs_panic(new_dir->i_sb, | 1032 | fat_fs_error(new_dir->i_sb, |
1034 | "%s: Filesystem corrupted (i_pos %lld)", | 1033 | "%s: Filesystem corrupted (i_pos %lld)", |
1035 | __func__, sinfo.i_pos); | 1034 | __func__, sinfo.i_pos); |
1036 | } | 1035 | } |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 1ad703150dee..ae413086db97 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/signal.h> | 19 | #include <linux/signal.h> |
20 | #include <linux/rcupdate.h> | 20 | #include <linux/rcupdate.h> |
21 | #include <linux/pid_namespace.h> | 21 | #include <linux/pid_namespace.h> |
22 | #include <linux/smp_lock.h> | ||
23 | 22 | ||
24 | #include <asm/poll.h> | 23 | #include <asm/poll.h> |
25 | #include <asm/siginfo.h> | 24 | #include <asm/siginfo.h> |
@@ -198,15 +197,19 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
198 | } | 197 | } |
199 | 198 | ||
200 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, | 199 | static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, |
201 | uid_t uid, uid_t euid, int force) | 200 | int force) |
202 | { | 201 | { |
203 | write_lock_irq(&filp->f_owner.lock); | 202 | write_lock_irq(&filp->f_owner.lock); |
204 | if (force || !filp->f_owner.pid) { | 203 | if (force || !filp->f_owner.pid) { |
205 | put_pid(filp->f_owner.pid); | 204 | put_pid(filp->f_owner.pid); |
206 | filp->f_owner.pid = get_pid(pid); | 205 | filp->f_owner.pid = get_pid(pid); |
207 | filp->f_owner.pid_type = type; | 206 | filp->f_owner.pid_type = type; |
208 | filp->f_owner.uid = uid; | 207 | |
209 | filp->f_owner.euid = euid; | 208 | if (pid) { |
209 | const struct cred *cred = current_cred(); | ||
210 | filp->f_owner.uid = cred->uid; | ||
211 | filp->f_owner.euid = cred->euid; | ||
212 | } | ||
210 | } | 213 | } |
211 | write_unlock_irq(&filp->f_owner.lock); | 214 | write_unlock_irq(&filp->f_owner.lock); |
212 | } | 215 | } |
@@ -214,14 +217,13 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, | |||
214 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, | 217 | int __f_setown(struct file *filp, struct pid *pid, enum pid_type type, |
215 | int force) | 218 | int force) |
216 | { | 219 | { |
217 | const struct cred *cred = current_cred(); | ||
218 | int err; | 220 | int err; |
219 | 221 | ||
220 | err = security_file_set_fowner(filp); | 222 | err = security_file_set_fowner(filp); |
221 | if (err) | 223 | if (err) |
222 | return err; | 224 | return err; |
223 | 225 | ||
224 | f_modown(filp, pid, type, cred->uid, cred->euid, force); | 226 | f_modown(filp, pid, type, force); |
225 | return 0; | 227 | return 0; |
226 | } | 228 | } |
227 | EXPORT_SYMBOL(__f_setown); | 229 | EXPORT_SYMBOL(__f_setown); |
@@ -247,7 +249,7 @@ EXPORT_SYMBOL(f_setown); | |||
247 | 249 | ||
248 | void f_delown(struct file *filp) | 250 | void f_delown(struct file *filp) |
249 | { | 251 | { |
250 | f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1); | 252 | f_modown(filp, NULL, PIDTYPE_PID, 1); |
251 | } | 253 | } |
252 | 254 | ||
253 | pid_t f_getown(struct file *filp) | 255 | pid_t f_getown(struct file *filp) |
@@ -425,14 +427,20 @@ static inline int sigio_perm(struct task_struct *p, | |||
425 | } | 427 | } |
426 | 428 | ||
427 | static void send_sigio_to_task(struct task_struct *p, | 429 | static void send_sigio_to_task(struct task_struct *p, |
428 | struct fown_struct *fown, | 430 | struct fown_struct *fown, |
429 | int fd, | 431 | int fd, |
430 | int reason) | 432 | int reason) |
431 | { | 433 | { |
432 | if (!sigio_perm(p, fown, fown->signum)) | 434 | /* |
435 | * F_SETSIG can change ->signum lockless in parallel, make | ||
436 | * sure we read it once and use the same value throughout. | ||
437 | */ | ||
438 | int signum = ACCESS_ONCE(fown->signum); | ||
439 | |||
440 | if (!sigio_perm(p, fown, signum)) | ||
433 | return; | 441 | return; |
434 | 442 | ||
435 | switch (fown->signum) { | 443 | switch (signum) { |
436 | siginfo_t si; | 444 | siginfo_t si; |
437 | default: | 445 | default: |
438 | /* Queue a rt signal with the appropriate fd as its | 446 | /* Queue a rt signal with the appropriate fd as its |
@@ -441,7 +449,7 @@ static void send_sigio_to_task(struct task_struct *p, | |||
441 | delivered even if we can't queue. Failure to | 449 | delivered even if we can't queue. Failure to |
442 | queue in this case _should_ be reported; we fall | 450 | queue in this case _should_ be reported; we fall |
443 | back to SIGIO in that case. --sct */ | 451 | back to SIGIO in that case. --sct */ |
444 | si.si_signo = fown->signum; | 452 | si.si_signo = signum; |
445 | si.si_errno = 0; | 453 | si.si_errno = 0; |
446 | si.si_code = reason; | 454 | si.si_code = reason; |
447 | /* Make sure we are called with one of the POLL_* | 455 | /* Make sure we are called with one of the POLL_* |
@@ -453,7 +461,7 @@ static void send_sigio_to_task(struct task_struct *p, | |||
453 | else | 461 | else |
454 | si.si_band = band_table[reason - POLL_IN]; | 462 | si.si_band = band_table[reason - POLL_IN]; |
455 | si.si_fd = fd; | 463 | si.si_fd = fd; |
456 | if (!group_send_sig_info(fown->signum, &si, p)) | 464 | if (!group_send_sig_info(signum, &si, p)) |
457 | break; | 465 | break; |
458 | /* fall-through: fall back on the old plain SIGIO signal */ | 466 | /* fall-through: fall back on the old plain SIGIO signal */ |
459 | case 0: | 467 | case 0: |
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index cdbd1654e4cd..1e8af939b3e4 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/buffer_head.h> | 38 | #include <linux/buffer_head.h> |
39 | #include <linux/kernel.h> | 39 | #include <linux/kernel.h> |
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <linux/smp_lock.h> | ||
41 | #include <linux/stat.h> | 42 | #include <linux/stat.h> |
42 | #include <linux/vfs.h> | 43 | #include <linux/vfs.h> |
43 | #include <linux/mount.h> | 44 | #include <linux/mount.h> |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 40308e98c6a4..c54226be5294 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -278,7 +278,26 @@ int sb_has_dirty_inodes(struct super_block *sb) | |||
278 | EXPORT_SYMBOL(sb_has_dirty_inodes); | 278 | EXPORT_SYMBOL(sb_has_dirty_inodes); |
279 | 279 | ||
280 | /* | 280 | /* |
281 | * Write a single inode's dirty pages and inode data out to disk. | 281 | * Wait for writeback on an inode to complete. |
282 | */ | ||
283 | static void inode_wait_for_writeback(struct inode *inode) | ||
284 | { | ||
285 | DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC); | ||
286 | wait_queue_head_t *wqh; | ||
287 | |||
288 | wqh = bit_waitqueue(&inode->i_state, __I_SYNC); | ||
289 | do { | ||
290 | spin_unlock(&inode_lock); | ||
291 | __wait_on_bit(wqh, &wq, inode_wait, TASK_UNINTERRUPTIBLE); | ||
292 | spin_lock(&inode_lock); | ||
293 | } while (inode->i_state & I_SYNC); | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * Write out an inode's dirty pages. Called under inode_lock. Either the | ||
298 | * caller has ref on the inode (either via __iget or via syscall against an fd) | ||
299 | * or the inode has I_WILL_FREE set (via generic_forget_inode) | ||
300 | * | ||
282 | * If `wait' is set, wait on the writeout. | 301 | * If `wait' is set, wait on the writeout. |
283 | * | 302 | * |
284 | * The whole writeout design is quite complex and fragile. We want to avoid | 303 | * The whole writeout design is quite complex and fragile. We want to avoid |
@@ -288,13 +307,38 @@ EXPORT_SYMBOL(sb_has_dirty_inodes); | |||
288 | * Called under inode_lock. | 307 | * Called under inode_lock. |
289 | */ | 308 | */ |
290 | static int | 309 | static int |
291 | __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | 310 | writeback_single_inode(struct inode *inode, struct writeback_control *wbc) |
292 | { | 311 | { |
293 | unsigned dirty; | ||
294 | struct address_space *mapping = inode->i_mapping; | 312 | struct address_space *mapping = inode->i_mapping; |
295 | int wait = wbc->sync_mode == WB_SYNC_ALL; | 313 | int wait = wbc->sync_mode == WB_SYNC_ALL; |
314 | unsigned dirty; | ||
296 | int ret; | 315 | int ret; |
297 | 316 | ||
317 | if (!atomic_read(&inode->i_count)) | ||
318 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); | ||
319 | else | ||
320 | WARN_ON(inode->i_state & I_WILL_FREE); | ||
321 | |||
322 | if (inode->i_state & I_SYNC) { | ||
323 | /* | ||
324 | * If this inode is locked for writeback and we are not doing | ||
325 | * writeback-for-data-integrity, move it to s_more_io so that | ||
326 | * writeback can proceed with the other inodes on s_io. | ||
327 | * | ||
328 | * We'll have another go at writing back this inode when we | ||
329 | * completed a full scan of s_io. | ||
330 | */ | ||
331 | if (!wait) { | ||
332 | requeue_io(inode); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * It's a data-integrity sync. We must wait. | ||
338 | */ | ||
339 | inode_wait_for_writeback(inode); | ||
340 | } | ||
341 | |||
298 | BUG_ON(inode->i_state & I_SYNC); | 342 | BUG_ON(inode->i_state & I_SYNC); |
299 | 343 | ||
300 | /* Set I_SYNC, reset I_DIRTY */ | 344 | /* Set I_SYNC, reset I_DIRTY */ |
@@ -321,7 +365,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
321 | 365 | ||
322 | spin_lock(&inode_lock); | 366 | spin_lock(&inode_lock); |
323 | inode->i_state &= ~I_SYNC; | 367 | inode->i_state &= ~I_SYNC; |
324 | if (!(inode->i_state & I_FREEING)) { | 368 | if (!(inode->i_state & (I_FREEING | I_CLEAR))) { |
325 | if (!(inode->i_state & I_DIRTY) && | 369 | if (!(inode->i_state & I_DIRTY) && |
326 | mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | 370 | mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { |
327 | /* | 371 | /* |
@@ -390,50 +434,6 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
390 | } | 434 | } |
391 | 435 | ||
392 | /* | 436 | /* |
393 | * Write out an inode's dirty pages. Called under inode_lock. Either the | ||
394 | * caller has ref on the inode (either via __iget or via syscall against an fd) | ||
395 | * or the inode has I_WILL_FREE set (via generic_forget_inode) | ||
396 | */ | ||
397 | static int | ||
398 | __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | ||
399 | { | ||
400 | wait_queue_head_t *wqh; | ||
401 | |||
402 | if (!atomic_read(&inode->i_count)) | ||
403 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); | ||
404 | else | ||
405 | WARN_ON(inode->i_state & I_WILL_FREE); | ||
406 | |||
407 | if ((wbc->sync_mode != WB_SYNC_ALL) && (inode->i_state & I_SYNC)) { | ||
408 | /* | ||
409 | * We're skipping this inode because it's locked, and we're not | ||
410 | * doing writeback-for-data-integrity. Move it to s_more_io so | ||
411 | * that writeback can proceed with the other inodes on s_io. | ||
412 | * We'll have another go at writing back this inode when we | ||
413 | * completed a full scan of s_io. | ||
414 | */ | ||
415 | requeue_io(inode); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | /* | ||
420 | * It's a data-integrity sync. We must wait. | ||
421 | */ | ||
422 | if (inode->i_state & I_SYNC) { | ||
423 | DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC); | ||
424 | |||
425 | wqh = bit_waitqueue(&inode->i_state, __I_SYNC); | ||
426 | do { | ||
427 | spin_unlock(&inode_lock); | ||
428 | __wait_on_bit(wqh, &wq, inode_wait, | ||
429 | TASK_UNINTERRUPTIBLE); | ||
430 | spin_lock(&inode_lock); | ||
431 | } while (inode->i_state & I_SYNC); | ||
432 | } | ||
433 | return __sync_single_inode(inode, wbc); | ||
434 | } | ||
435 | |||
436 | /* | ||
437 | * Write out a superblock's list of dirty inodes. A wait will be performed | 437 | * Write out a superblock's list of dirty inodes. A wait will be performed |
438 | * upon no inodes, all inodes or the final one, depending upon sync_mode. | 438 | * upon no inodes, all inodes or the final one, depending upon sync_mode. |
439 | * | 439 | * |
@@ -492,7 +492,7 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
492 | break; | 492 | break; |
493 | } | 493 | } |
494 | 494 | ||
495 | if (inode->i_state & I_NEW) { | 495 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { |
496 | requeue_io(inode); | 496 | requeue_io(inode); |
497 | continue; | 497 | continue; |
498 | } | 498 | } |
@@ -523,10 +523,10 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
523 | if (current_is_pdflush() && !writeback_acquire(bdi)) | 523 | if (current_is_pdflush() && !writeback_acquire(bdi)) |
524 | break; | 524 | break; |
525 | 525 | ||
526 | BUG_ON(inode->i_state & I_FREEING); | 526 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); |
527 | __iget(inode); | 527 | __iget(inode); |
528 | pages_skipped = wbc->pages_skipped; | 528 | pages_skipped = wbc->pages_skipped; |
529 | __writeback_single_inode(inode, wbc); | 529 | writeback_single_inode(inode, wbc); |
530 | if (current_is_pdflush()) | 530 | if (current_is_pdflush()) |
531 | writeback_release(bdi); | 531 | writeback_release(bdi); |
532 | if (wbc->pages_skipped != pages_skipped) { | 532 | if (wbc->pages_skipped != pages_skipped) { |
@@ -708,7 +708,7 @@ int write_inode_now(struct inode *inode, int sync) | |||
708 | 708 | ||
709 | might_sleep(); | 709 | might_sleep(); |
710 | spin_lock(&inode_lock); | 710 | spin_lock(&inode_lock); |
711 | ret = __writeback_single_inode(inode, &wbc); | 711 | ret = writeback_single_inode(inode, &wbc); |
712 | spin_unlock(&inode_lock); | 712 | spin_unlock(&inode_lock); |
713 | if (sync) | 713 | if (sync) |
714 | inode_sync_wait(inode); | 714 | inode_sync_wait(inode); |
@@ -732,7 +732,7 @@ int sync_inode(struct inode *inode, struct writeback_control *wbc) | |||
732 | int ret; | 732 | int ret; |
733 | 733 | ||
734 | spin_lock(&inode_lock); | 734 | spin_lock(&inode_lock); |
735 | ret = __writeback_single_inode(inode, wbc); | 735 | ret = writeback_single_inode(inode, wbc); |
736 | spin_unlock(&inode_lock); | 736 | spin_unlock(&inode_lock); |
737 | return ret; | 737 | return ret; |
738 | } | 738 | } |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 8fed2ed12f38..6484eb75acd6 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -286,8 +286,8 @@ __releases(&fc->lock) | |||
286 | } | 286 | } |
287 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && | 287 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && |
288 | fc->connected && fc->bdi_initialized) { | 288 | fc->connected && fc->bdi_initialized) { |
289 | clear_bdi_congested(&fc->bdi, READ); | 289 | clear_bdi_congested(&fc->bdi, BLK_RW_SYNC); |
290 | clear_bdi_congested(&fc->bdi, WRITE); | 290 | clear_bdi_congested(&fc->bdi, BLK_RW_ASYNC); |
291 | } | 291 | } |
292 | fc->num_background--; | 292 | fc->num_background--; |
293 | fc->active_background--; | 293 | fc->active_background--; |
@@ -414,8 +414,8 @@ static void fuse_request_send_nowait_locked(struct fuse_conn *fc, | |||
414 | fc->blocked = 1; | 414 | fc->blocked = 1; |
415 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && | 415 | if (fc->num_background == FUSE_CONGESTION_THRESHOLD && |
416 | fc->bdi_initialized) { | 416 | fc->bdi_initialized) { |
417 | set_bdi_congested(&fc->bdi, READ); | 417 | set_bdi_congested(&fc->bdi, BLK_RW_SYNC); |
418 | set_bdi_congested(&fc->bdi, WRITE); | 418 | set_bdi_congested(&fc->bdi, BLK_RW_ASYNC); |
419 | } | 419 | } |
420 | list_add_tail(&req->list, &fc->bg_queue); | 420 | list_add_tail(&req->list, &fc->bg_queue); |
421 | flush_bg_queue(fc); | 421 | flush_bg_queue(fc); |
@@ -849,6 +849,81 @@ err: | |||
849 | return err; | 849 | return err; |
850 | } | 850 | } |
851 | 851 | ||
852 | static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size, | ||
853 | struct fuse_copy_state *cs) | ||
854 | { | ||
855 | struct fuse_notify_inval_inode_out outarg; | ||
856 | int err = -EINVAL; | ||
857 | |||
858 | if (size != sizeof(outarg)) | ||
859 | goto err; | ||
860 | |||
861 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
862 | if (err) | ||
863 | goto err; | ||
864 | fuse_copy_finish(cs); | ||
865 | |||
866 | down_read(&fc->killsb); | ||
867 | err = -ENOENT; | ||
868 | if (!fc->sb) | ||
869 | goto err_unlock; | ||
870 | |||
871 | err = fuse_reverse_inval_inode(fc->sb, outarg.ino, | ||
872 | outarg.off, outarg.len); | ||
873 | |||
874 | err_unlock: | ||
875 | up_read(&fc->killsb); | ||
876 | return err; | ||
877 | |||
878 | err: | ||
879 | fuse_copy_finish(cs); | ||
880 | return err; | ||
881 | } | ||
882 | |||
883 | static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size, | ||
884 | struct fuse_copy_state *cs) | ||
885 | { | ||
886 | struct fuse_notify_inval_entry_out outarg; | ||
887 | int err = -EINVAL; | ||
888 | char buf[FUSE_NAME_MAX+1]; | ||
889 | struct qstr name; | ||
890 | |||
891 | if (size < sizeof(outarg)) | ||
892 | goto err; | ||
893 | |||
894 | err = fuse_copy_one(cs, &outarg, sizeof(outarg)); | ||
895 | if (err) | ||
896 | goto err; | ||
897 | |||
898 | err = -ENAMETOOLONG; | ||
899 | if (outarg.namelen > FUSE_NAME_MAX) | ||
900 | goto err; | ||
901 | |||
902 | name.name = buf; | ||
903 | name.len = outarg.namelen; | ||
904 | err = fuse_copy_one(cs, buf, outarg.namelen + 1); | ||
905 | if (err) | ||
906 | goto err; | ||
907 | fuse_copy_finish(cs); | ||
908 | buf[outarg.namelen] = 0; | ||
909 | name.hash = full_name_hash(name.name, name.len); | ||
910 | |||
911 | down_read(&fc->killsb); | ||
912 | err = -ENOENT; | ||
913 | if (!fc->sb) | ||
914 | goto err_unlock; | ||
915 | |||
916 | err = fuse_reverse_inval_entry(fc->sb, outarg.parent, &name); | ||
917 | |||
918 | err_unlock: | ||
919 | up_read(&fc->killsb); | ||
920 | return err; | ||
921 | |||
922 | err: | ||
923 | fuse_copy_finish(cs); | ||
924 | return err; | ||
925 | } | ||
926 | |||
852 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | 927 | static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, |
853 | unsigned int size, struct fuse_copy_state *cs) | 928 | unsigned int size, struct fuse_copy_state *cs) |
854 | { | 929 | { |
@@ -856,6 +931,12 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code, | |||
856 | case FUSE_NOTIFY_POLL: | 931 | case FUSE_NOTIFY_POLL: |
857 | return fuse_notify_poll(fc, size, cs); | 932 | return fuse_notify_poll(fc, size, cs); |
858 | 933 | ||
934 | case FUSE_NOTIFY_INVAL_INODE: | ||
935 | return fuse_notify_inval_inode(fc, size, cs); | ||
936 | |||
937 | case FUSE_NOTIFY_INVAL_ENTRY: | ||
938 | return fuse_notify_inval_entry(fc, size, cs); | ||
939 | |||
859 | default: | 940 | default: |
860 | fuse_copy_finish(cs); | 941 | fuse_copy_finish(cs); |
861 | return -EINVAL; | 942 | return -EINVAL; |
@@ -910,7 +991,7 @@ static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov, | |||
910 | unsigned long nr_segs, loff_t pos) | 991 | unsigned long nr_segs, loff_t pos) |
911 | { | 992 | { |
912 | int err; | 993 | int err; |
913 | unsigned nbytes = iov_length(iov, nr_segs); | 994 | size_t nbytes = iov_length(iov, nr_segs); |
914 | struct fuse_req *req; | 995 | struct fuse_req *req; |
915 | struct fuse_out_header oh; | 996 | struct fuse_out_header oh; |
916 | struct fuse_copy_state cs; | 997 | struct fuse_copy_state cs; |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b3089a083d30..e703654e7f40 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -375,7 +375,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
375 | struct fuse_conn *fc = get_fuse_conn(dir); | 375 | struct fuse_conn *fc = get_fuse_conn(dir); |
376 | struct fuse_req *req; | 376 | struct fuse_req *req; |
377 | struct fuse_req *forget_req; | 377 | struct fuse_req *forget_req; |
378 | struct fuse_open_in inarg; | 378 | struct fuse_create_in inarg; |
379 | struct fuse_open_out outopen; | 379 | struct fuse_open_out outopen; |
380 | struct fuse_entry_out outentry; | 380 | struct fuse_entry_out outentry; |
381 | struct fuse_file *ff; | 381 | struct fuse_file *ff; |
@@ -399,15 +399,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
399 | if (!ff) | 399 | if (!ff) |
400 | goto out_put_request; | 400 | goto out_put_request; |
401 | 401 | ||
402 | if (!fc->dont_mask) | ||
403 | mode &= ~current_umask(); | ||
404 | |||
402 | flags &= ~O_NOCTTY; | 405 | flags &= ~O_NOCTTY; |
403 | memset(&inarg, 0, sizeof(inarg)); | 406 | memset(&inarg, 0, sizeof(inarg)); |
404 | memset(&outentry, 0, sizeof(outentry)); | 407 | memset(&outentry, 0, sizeof(outentry)); |
405 | inarg.flags = flags; | 408 | inarg.flags = flags; |
406 | inarg.mode = mode; | 409 | inarg.mode = mode; |
410 | inarg.umask = current_umask(); | ||
407 | req->in.h.opcode = FUSE_CREATE; | 411 | req->in.h.opcode = FUSE_CREATE; |
408 | req->in.h.nodeid = get_node_id(dir); | 412 | req->in.h.nodeid = get_node_id(dir); |
409 | req->in.numargs = 2; | 413 | req->in.numargs = 2; |
410 | req->in.args[0].size = sizeof(inarg); | 414 | req->in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) : |
415 | sizeof(inarg); | ||
411 | req->in.args[0].value = &inarg; | 416 | req->in.args[0].value = &inarg; |
412 | req->in.args[1].size = entry->d_name.len + 1; | 417 | req->in.args[1].size = entry->d_name.len + 1; |
413 | req->in.args[1].value = entry->d_name.name; | 418 | req->in.args[1].value = entry->d_name.name; |
@@ -546,12 +551,17 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, | |||
546 | if (IS_ERR(req)) | 551 | if (IS_ERR(req)) |
547 | return PTR_ERR(req); | 552 | return PTR_ERR(req); |
548 | 553 | ||
554 | if (!fc->dont_mask) | ||
555 | mode &= ~current_umask(); | ||
556 | |||
549 | memset(&inarg, 0, sizeof(inarg)); | 557 | memset(&inarg, 0, sizeof(inarg)); |
550 | inarg.mode = mode; | 558 | inarg.mode = mode; |
551 | inarg.rdev = new_encode_dev(rdev); | 559 | inarg.rdev = new_encode_dev(rdev); |
560 | inarg.umask = current_umask(); | ||
552 | req->in.h.opcode = FUSE_MKNOD; | 561 | req->in.h.opcode = FUSE_MKNOD; |
553 | req->in.numargs = 2; | 562 | req->in.numargs = 2; |
554 | req->in.args[0].size = sizeof(inarg); | 563 | req->in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE : |
564 | sizeof(inarg); | ||
555 | req->in.args[0].value = &inarg; | 565 | req->in.args[0].value = &inarg; |
556 | req->in.args[1].size = entry->d_name.len + 1; | 566 | req->in.args[1].size = entry->d_name.len + 1; |
557 | req->in.args[1].value = entry->d_name.name; | 567 | req->in.args[1].value = entry->d_name.name; |
@@ -578,8 +588,12 @@ static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode) | |||
578 | if (IS_ERR(req)) | 588 | if (IS_ERR(req)) |
579 | return PTR_ERR(req); | 589 | return PTR_ERR(req); |
580 | 590 | ||
591 | if (!fc->dont_mask) | ||
592 | mode &= ~current_umask(); | ||
593 | |||
581 | memset(&inarg, 0, sizeof(inarg)); | 594 | memset(&inarg, 0, sizeof(inarg)); |
582 | inarg.mode = mode; | 595 | inarg.mode = mode; |
596 | inarg.umask = current_umask(); | ||
583 | req->in.h.opcode = FUSE_MKDIR; | 597 | req->in.h.opcode = FUSE_MKDIR; |
584 | req->in.numargs = 2; | 598 | req->in.numargs = 2; |
585 | req->in.args[0].size = sizeof(inarg); | 599 | req->in.args[0].size = sizeof(inarg); |
@@ -845,6 +859,43 @@ int fuse_update_attributes(struct inode *inode, struct kstat *stat, | |||
845 | return err; | 859 | return err; |
846 | } | 860 | } |
847 | 861 | ||
862 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | ||
863 | struct qstr *name) | ||
864 | { | ||
865 | int err = -ENOTDIR; | ||
866 | struct inode *parent; | ||
867 | struct dentry *dir; | ||
868 | struct dentry *entry; | ||
869 | |||
870 | parent = ilookup5(sb, parent_nodeid, fuse_inode_eq, &parent_nodeid); | ||
871 | if (!parent) | ||
872 | return -ENOENT; | ||
873 | |||
874 | mutex_lock(&parent->i_mutex); | ||
875 | if (!S_ISDIR(parent->i_mode)) | ||
876 | goto unlock; | ||
877 | |||
878 | err = -ENOENT; | ||
879 | dir = d_find_alias(parent); | ||
880 | if (!dir) | ||
881 | goto unlock; | ||
882 | |||
883 | entry = d_lookup(dir, name); | ||
884 | dput(dir); | ||
885 | if (!entry) | ||
886 | goto unlock; | ||
887 | |||
888 | fuse_invalidate_attr(parent); | ||
889 | fuse_invalidate_entry(entry); | ||
890 | dput(entry); | ||
891 | err = 0; | ||
892 | |||
893 | unlock: | ||
894 | mutex_unlock(&parent->i_mutex); | ||
895 | iput(parent); | ||
896 | return err; | ||
897 | } | ||
898 | |||
848 | /* | 899 | /* |
849 | * Calling into a user-controlled filesystem gives the filesystem | 900 | * Calling into a user-controlled filesystem gives the filesystem |
850 | * daemon ptrace-like capabilities over the requester process. This | 901 | * daemon ptrace-like capabilities over the requester process. This |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index fce6ce694fde..cbc464043b6f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1922,7 +1922,7 @@ unsigned fuse_file_poll(struct file *file, poll_table *wait) | |||
1922 | 1922 | ||
1923 | req = fuse_get_req(fc); | 1923 | req = fuse_get_req(fc); |
1924 | if (IS_ERR(req)) | 1924 | if (IS_ERR(req)) |
1925 | return PTR_ERR(req); | 1925 | return POLLERR; |
1926 | 1926 | ||
1927 | req->in.h.opcode = FUSE_POLL; | 1927 | req->in.h.opcode = FUSE_POLL; |
1928 | req->in.h.nodeid = ff->nodeid; | 1928 | req->in.h.nodeid = ff->nodeid; |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index aaf2f9ff970e..52b641fc0faf 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -446,6 +446,9 @@ struct fuse_conn { | |||
446 | /** Do multi-page cached writes */ | 446 | /** Do multi-page cached writes */ |
447 | unsigned big_writes:1; | 447 | unsigned big_writes:1; |
448 | 448 | ||
449 | /** Don't apply umask to creation modes */ | ||
450 | unsigned dont_mask:1; | ||
451 | |||
449 | /** The number of requests waiting for completion */ | 452 | /** The number of requests waiting for completion */ |
450 | atomic_t num_waiting; | 453 | atomic_t num_waiting; |
451 | 454 | ||
@@ -481,6 +484,12 @@ struct fuse_conn { | |||
481 | 484 | ||
482 | /** Called on final put */ | 485 | /** Called on final put */ |
483 | void (*release)(struct fuse_conn *); | 486 | void (*release)(struct fuse_conn *); |
487 | |||
488 | /** Super block for this connection. */ | ||
489 | struct super_block *sb; | ||
490 | |||
491 | /** Read/write semaphore to hold when accessing sb. */ | ||
492 | struct rw_semaphore killsb; | ||
484 | }; | 493 | }; |
485 | 494 | ||
486 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 495 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) |
@@ -509,6 +518,11 @@ extern const struct file_operations fuse_dev_operations; | |||
509 | extern const struct dentry_operations fuse_dentry_operations; | 518 | extern const struct dentry_operations fuse_dentry_operations; |
510 | 519 | ||
511 | /** | 520 | /** |
521 | * Inode to nodeid comparison. | ||
522 | */ | ||
523 | int fuse_inode_eq(struct inode *inode, void *_nodeidp); | ||
524 | |||
525 | /** | ||
512 | * Get a filled in inode | 526 | * Get a filled in inode |
513 | */ | 527 | */ |
514 | struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | 528 | struct inode *fuse_iget(struct super_block *sb, u64 nodeid, |
@@ -708,6 +722,19 @@ void fuse_release_nowrite(struct inode *inode); | |||
708 | 722 | ||
709 | u64 fuse_get_attr_version(struct fuse_conn *fc); | 723 | u64 fuse_get_attr_version(struct fuse_conn *fc); |
710 | 724 | ||
725 | /** | ||
726 | * File-system tells the kernel to invalidate cache for the given node id. | ||
727 | */ | ||
728 | int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, | ||
729 | loff_t offset, loff_t len); | ||
730 | |||
731 | /** | ||
732 | * File-system tells the kernel to invalidate parent attributes and | ||
733 | * the dentry matching parent/name. | ||
734 | */ | ||
735 | int fuse_reverse_inval_entry(struct super_block *sb, u64 parent_nodeid, | ||
736 | struct qstr *name); | ||
737 | |||
711 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | 738 | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, |
712 | bool isdir); | 739 | bool isdir); |
713 | ssize_t fuse_direct_io(struct file *file, const char __user *buf, | 740 | ssize_t fuse_direct_io(struct file *file, const char __user *buf, |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f0df55a52929..f91ccc4a189d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -19,7 +19,6 @@ | |||
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 | #include <linux/exportfs.h> |
22 | #include <linux/smp_lock.h> | ||
23 | 22 | ||
24 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | 23 | MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); |
25 | MODULE_DESCRIPTION("Filesystem in Userspace"); | 24 | MODULE_DESCRIPTION("Filesystem in Userspace"); |
@@ -207,7 +206,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
207 | BUG(); | 206 | BUG(); |
208 | } | 207 | } |
209 | 208 | ||
210 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) | 209 | int fuse_inode_eq(struct inode *inode, void *_nodeidp) |
211 | { | 210 | { |
212 | u64 nodeid = *(u64 *) _nodeidp; | 211 | u64 nodeid = *(u64 *) _nodeidp; |
213 | if (get_node_id(inode) == nodeid) | 212 | if (get_node_id(inode) == nodeid) |
@@ -258,11 +257,34 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid, | |||
258 | return inode; | 257 | return inode; |
259 | } | 258 | } |
260 | 259 | ||
260 | int fuse_reverse_inval_inode(struct super_block *sb, u64 nodeid, | ||
261 | loff_t offset, loff_t len) | ||
262 | { | ||
263 | struct inode *inode; | ||
264 | pgoff_t pg_start; | ||
265 | pgoff_t pg_end; | ||
266 | |||
267 | inode = ilookup5(sb, nodeid, fuse_inode_eq, &nodeid); | ||
268 | if (!inode) | ||
269 | return -ENOENT; | ||
270 | |||
271 | fuse_invalidate_attr(inode); | ||
272 | if (offset >= 0) { | ||
273 | pg_start = offset >> PAGE_CACHE_SHIFT; | ||
274 | if (len <= 0) | ||
275 | pg_end = -1; | ||
276 | else | ||
277 | pg_end = (offset + len - 1) >> PAGE_CACHE_SHIFT; | ||
278 | invalidate_inode_pages2_range(inode->i_mapping, | ||
279 | pg_start, pg_end); | ||
280 | } | ||
281 | iput(inode); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
261 | static void fuse_umount_begin(struct super_block *sb) | 285 | static void fuse_umount_begin(struct super_block *sb) |
262 | { | 286 | { |
263 | lock_kernel(); | ||
264 | fuse_abort_conn(get_fuse_conn_super(sb)); | 287 | fuse_abort_conn(get_fuse_conn_super(sb)); |
265 | unlock_kernel(); | ||
266 | } | 288 | } |
267 | 289 | ||
268 | static void fuse_send_destroy(struct fuse_conn *fc) | 290 | static void fuse_send_destroy(struct fuse_conn *fc) |
@@ -483,6 +505,7 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
483 | memset(fc, 0, sizeof(*fc)); | 505 | memset(fc, 0, sizeof(*fc)); |
484 | spin_lock_init(&fc->lock); | 506 | spin_lock_init(&fc->lock); |
485 | mutex_init(&fc->inst_mutex); | 507 | mutex_init(&fc->inst_mutex); |
508 | init_rwsem(&fc->killsb); | ||
486 | atomic_set(&fc->count, 1); | 509 | atomic_set(&fc->count, 1); |
487 | init_waitqueue_head(&fc->waitq); | 510 | init_waitqueue_head(&fc->waitq); |
488 | init_waitqueue_head(&fc->blocked_waitq); | 511 | init_waitqueue_head(&fc->blocked_waitq); |
@@ -728,6 +751,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
728 | } | 751 | } |
729 | if (arg->flags & FUSE_BIG_WRITES) | 752 | if (arg->flags & FUSE_BIG_WRITES) |
730 | fc->big_writes = 1; | 753 | fc->big_writes = 1; |
754 | if (arg->flags & FUSE_DONT_MASK) | ||
755 | fc->dont_mask = 1; | ||
731 | } else { | 756 | } else { |
732 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 757 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
733 | fc->no_lock = 1; | 758 | fc->no_lock = 1; |
@@ -751,7 +776,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
751 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 776 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
752 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 777 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
753 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | | 778 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC | |
754 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES; | 779 | FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK; |
755 | req->in.h.opcode = FUSE_INIT; | 780 | req->in.h.opcode = FUSE_INIT; |
756 | req->in.numargs = 1; | 781 | req->in.numargs = 1; |
757 | req->in.args[0].size = sizeof(*arg); | 782 | req->in.args[0].size = sizeof(*arg); |
@@ -863,10 +888,16 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
863 | fuse_conn_init(fc); | 888 | fuse_conn_init(fc); |
864 | 889 | ||
865 | fc->dev = sb->s_dev; | 890 | fc->dev = sb->s_dev; |
891 | fc->sb = sb; | ||
866 | err = fuse_bdi_init(fc, sb); | 892 | err = fuse_bdi_init(fc, sb); |
867 | if (err) | 893 | if (err) |
868 | goto err_put_conn; | 894 | goto err_put_conn; |
869 | 895 | ||
896 | /* Handle umasking inside the fuse code */ | ||
897 | if (sb->s_flags & MS_POSIXACL) | ||
898 | fc->dont_mask = 1; | ||
899 | sb->s_flags |= MS_POSIXACL; | ||
900 | |||
870 | fc->release = fuse_free_conn; | 901 | fc->release = fuse_free_conn; |
871 | fc->flags = d.flags; | 902 | fc->flags = d.flags; |
872 | fc->user_id = d.user_id; | 903 | fc->user_id = d.user_id; |
@@ -944,12 +975,25 @@ static int fuse_get_sb(struct file_system_type *fs_type, | |||
944 | return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); | 975 | return get_sb_nodev(fs_type, flags, raw_data, fuse_fill_super, mnt); |
945 | } | 976 | } |
946 | 977 | ||
978 | static void fuse_kill_sb_anon(struct super_block *sb) | ||
979 | { | ||
980 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
981 | |||
982 | if (fc) { | ||
983 | down_write(&fc->killsb); | ||
984 | fc->sb = NULL; | ||
985 | up_write(&fc->killsb); | ||
986 | } | ||
987 | |||
988 | kill_anon_super(sb); | ||
989 | } | ||
990 | |||
947 | static struct file_system_type fuse_fs_type = { | 991 | static struct file_system_type fuse_fs_type = { |
948 | .owner = THIS_MODULE, | 992 | .owner = THIS_MODULE, |
949 | .name = "fuse", | 993 | .name = "fuse", |
950 | .fs_flags = FS_HAS_SUBTYPE, | 994 | .fs_flags = FS_HAS_SUBTYPE, |
951 | .get_sb = fuse_get_sb, | 995 | .get_sb = fuse_get_sb, |
952 | .kill_sb = kill_anon_super, | 996 | .kill_sb = fuse_kill_sb_anon, |
953 | }; | 997 | }; |
954 | 998 | ||
955 | #ifdef CONFIG_BLOCK | 999 | #ifdef CONFIG_BLOCK |
@@ -961,11 +1005,24 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type, | |||
961 | mnt); | 1005 | mnt); |
962 | } | 1006 | } |
963 | 1007 | ||
1008 | static void fuse_kill_sb_blk(struct super_block *sb) | ||
1009 | { | ||
1010 | struct fuse_conn *fc = get_fuse_conn_super(sb); | ||
1011 | |||
1012 | if (fc) { | ||
1013 | down_write(&fc->killsb); | ||
1014 | fc->sb = NULL; | ||
1015 | up_write(&fc->killsb); | ||
1016 | } | ||
1017 | |||
1018 | kill_block_super(sb); | ||
1019 | } | ||
1020 | |||
964 | static struct file_system_type fuseblk_fs_type = { | 1021 | static struct file_system_type fuseblk_fs_type = { |
965 | .owner = THIS_MODULE, | 1022 | .owner = THIS_MODULE, |
966 | .name = "fuseblk", | 1023 | .name = "fuseblk", |
967 | .get_sb = fuse_get_sb_blk, | 1024 | .get_sb = fuse_get_sb_blk, |
968 | .kill_sb = kill_block_super, | 1025 | .kill_sb = fuse_kill_sb_blk, |
969 | .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, | 1026 | .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, |
970 | }; | 1027 | }; |
971 | 1028 | ||
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig index cad957cdb1e5..5971359d2090 100644 --- a/fs/gfs2/Kconfig +++ b/fs/gfs2/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config GFS2_FS | 1 | config GFS2_FS |
2 | tristate "GFS2 file system support" | 2 | tristate "GFS2 file system support" |
3 | depends on EXPERIMENTAL && (64BIT || LBD) | 3 | depends on EXPERIMENTAL && (64BIT || LBDAF) |
4 | select DLM if GFS2_FS_LOCKING_DLM | 4 | select DLM if GFS2_FS_LOCKING_DLM |
5 | select CONFIGFS_FS if GFS2_FS_LOCKING_DLM | 5 | select CONFIGFS_FS if GFS2_FS_LOCKING_DLM |
6 | select SYSFS if GFS2_FS_LOCKING_DLM | 6 | select SYSFS if GFS2_FS_LOCKING_DLM |
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 03ebb439ace0..7ebae9a4ecc0 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
@@ -624,6 +624,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
624 | { | 624 | { |
625 | struct gfs2_inode *ip = GFS2_I(mapping->host); | 625 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
626 | struct gfs2_sbd *sdp = GFS2_SB(mapping->host); | 626 | struct gfs2_sbd *sdp = GFS2_SB(mapping->host); |
627 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
627 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; | 628 | unsigned int data_blocks = 0, ind_blocks = 0, rblocks; |
628 | int alloc_required; | 629 | int alloc_required; |
629 | int error = 0; | 630 | int error = 0; |
@@ -637,6 +638,14 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
637 | error = gfs2_glock_nq(&ip->i_gh); | 638 | error = gfs2_glock_nq(&ip->i_gh); |
638 | if (unlikely(error)) | 639 | if (unlikely(error)) |
639 | goto out_uninit; | 640 | goto out_uninit; |
641 | if (&ip->i_inode == sdp->sd_rindex) { | ||
642 | error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, | ||
643 | GL_NOCACHE, &m_ip->i_gh); | ||
644 | if (unlikely(error)) { | ||
645 | gfs2_glock_dq(&ip->i_gh); | ||
646 | goto out_uninit; | ||
647 | } | ||
648 | } | ||
640 | 649 | ||
641 | error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); | 650 | error = gfs2_write_alloc_required(ip, pos, len, &alloc_required); |
642 | if (error) | 651 | if (error) |
@@ -667,6 +676,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping, | |||
667 | rblocks += data_blocks ? data_blocks : 1; | 676 | rblocks += data_blocks ? data_blocks : 1; |
668 | if (ind_blocks || data_blocks) | 677 | if (ind_blocks || data_blocks) |
669 | rblocks += RES_STATFS + RES_QUOTA; | 678 | rblocks += RES_STATFS + RES_QUOTA; |
679 | if (&ip->i_inode == sdp->sd_rindex) | ||
680 | rblocks += 2 * RES_STATFS; | ||
670 | 681 | ||
671 | error = gfs2_trans_begin(sdp, rblocks, | 682 | error = gfs2_trans_begin(sdp, rblocks, |
672 | PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); | 683 | PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize); |
@@ -712,6 +723,10 @@ out_alloc_put: | |||
712 | gfs2_alloc_put(ip); | 723 | gfs2_alloc_put(ip); |
713 | } | 724 | } |
714 | out_unlock: | 725 | out_unlock: |
726 | if (&ip->i_inode == sdp->sd_rindex) { | ||
727 | gfs2_glock_dq(&m_ip->i_gh); | ||
728 | gfs2_holder_uninit(&m_ip->i_gh); | ||
729 | } | ||
715 | gfs2_glock_dq(&ip->i_gh); | 730 | gfs2_glock_dq(&ip->i_gh); |
716 | out_uninit: | 731 | out_uninit: |
717 | gfs2_holder_uninit(&ip->i_gh); | 732 | gfs2_holder_uninit(&ip->i_gh); |
@@ -725,14 +740,21 @@ out_uninit: | |||
725 | static void adjust_fs_space(struct inode *inode) | 740 | static void adjust_fs_space(struct inode *inode) |
726 | { | 741 | { |
727 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | 742 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; |
743 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
744 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); | ||
728 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; | 745 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; |
729 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; | 746 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; |
747 | struct buffer_head *m_bh, *l_bh; | ||
730 | u64 fs_total, new_free; | 748 | u64 fs_total, new_free; |
731 | 749 | ||
732 | /* Total up the file system space, according to the latest rindex. */ | 750 | /* Total up the file system space, according to the latest rindex. */ |
733 | fs_total = gfs2_ri_total(sdp); | 751 | fs_total = gfs2_ri_total(sdp); |
752 | if (gfs2_meta_inode_buffer(m_ip, &m_bh) != 0) | ||
753 | return; | ||
734 | 754 | ||
735 | spin_lock(&sdp->sd_statfs_spin); | 755 | spin_lock(&sdp->sd_statfs_spin); |
756 | gfs2_statfs_change_in(m_sc, m_bh->b_data + | ||
757 | sizeof(struct gfs2_dinode)); | ||
736 | if (fs_total > (m_sc->sc_total + l_sc->sc_total)) | 758 | if (fs_total > (m_sc->sc_total + l_sc->sc_total)) |
737 | new_free = fs_total - (m_sc->sc_total + l_sc->sc_total); | 759 | new_free = fs_total - (m_sc->sc_total + l_sc->sc_total); |
738 | else | 760 | else |
@@ -741,6 +763,13 @@ static void adjust_fs_space(struct inode *inode) | |||
741 | fs_warn(sdp, "File system extended by %llu blocks.\n", | 763 | fs_warn(sdp, "File system extended by %llu blocks.\n", |
742 | (unsigned long long)new_free); | 764 | (unsigned long long)new_free); |
743 | gfs2_statfs_change(sdp, new_free, new_free, 0); | 765 | gfs2_statfs_change(sdp, new_free, new_free, 0); |
766 | |||
767 | if (gfs2_meta_inode_buffer(l_ip, &l_bh) != 0) | ||
768 | goto out; | ||
769 | update_statfs(sdp, m_bh, l_bh); | ||
770 | brelse(l_bh); | ||
771 | out: | ||
772 | brelse(m_bh); | ||
744 | } | 773 | } |
745 | 774 | ||
746 | /** | 775 | /** |
@@ -763,6 +792,7 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, | |||
763 | { | 792 | { |
764 | struct gfs2_inode *ip = GFS2_I(inode); | 793 | struct gfs2_inode *ip = GFS2_I(inode); |
765 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 794 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
795 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
766 | u64 to = pos + copied; | 796 | u64 to = pos + copied; |
767 | void *kaddr; | 797 | void *kaddr; |
768 | unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); | 798 | unsigned char *buf = dibh->b_data + sizeof(struct gfs2_dinode); |
@@ -794,6 +824,10 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh, | |||
794 | 824 | ||
795 | brelse(dibh); | 825 | brelse(dibh); |
796 | gfs2_trans_end(sdp); | 826 | gfs2_trans_end(sdp); |
827 | if (inode == sdp->sd_rindex) { | ||
828 | gfs2_glock_dq(&m_ip->i_gh); | ||
829 | gfs2_holder_uninit(&m_ip->i_gh); | ||
830 | } | ||
797 | gfs2_glock_dq(&ip->i_gh); | 831 | gfs2_glock_dq(&ip->i_gh); |
798 | gfs2_holder_uninit(&ip->i_gh); | 832 | gfs2_holder_uninit(&ip->i_gh); |
799 | return copied; | 833 | return copied; |
@@ -823,6 +857,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping, | |||
823 | struct inode *inode = page->mapping->host; | 857 | struct inode *inode = page->mapping->host; |
824 | struct gfs2_inode *ip = GFS2_I(inode); | 858 | struct gfs2_inode *ip = GFS2_I(inode); |
825 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 859 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
860 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
826 | struct buffer_head *dibh; | 861 | struct buffer_head *dibh; |
827 | struct gfs2_alloc *al = ip->i_alloc; | 862 | struct gfs2_alloc *al = ip->i_alloc; |
828 | unsigned int from = pos & (PAGE_CACHE_SIZE - 1); | 863 | unsigned int from = pos & (PAGE_CACHE_SIZE - 1); |
@@ -865,6 +900,10 @@ failed: | |||
865 | gfs2_quota_unlock(ip); | 900 | gfs2_quota_unlock(ip); |
866 | gfs2_alloc_put(ip); | 901 | gfs2_alloc_put(ip); |
867 | } | 902 | } |
903 | if (inode == sdp->sd_rindex) { | ||
904 | gfs2_glock_dq(&m_ip->i_gh); | ||
905 | gfs2_holder_uninit(&m_ip->i_gh); | ||
906 | } | ||
868 | gfs2_glock_dq(&ip->i_gh); | 907 | gfs2_glock_dq(&ip->i_gh); |
869 | gfs2_holder_uninit(&ip->i_gh); | 908 | gfs2_holder_uninit(&ip->i_gh); |
870 | return ret; | 909 | return ret; |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 297421c0427a..8b674b1f3a55 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -63,6 +63,7 @@ static void do_xmote(struct gfs2_glock *gl, struct gfs2_holder *gh, unsigned int | |||
63 | static DECLARE_RWSEM(gfs2_umount_flush_sem); | 63 | static DECLARE_RWSEM(gfs2_umount_flush_sem); |
64 | static struct dentry *gfs2_root; | 64 | static struct dentry *gfs2_root; |
65 | static struct workqueue_struct *glock_workqueue; | 65 | static struct workqueue_struct *glock_workqueue; |
66 | struct workqueue_struct *gfs2_delete_workqueue; | ||
66 | static LIST_HEAD(lru_list); | 67 | static LIST_HEAD(lru_list); |
67 | static atomic_t lru_count = ATOMIC_INIT(0); | 68 | static atomic_t lru_count = ATOMIC_INIT(0); |
68 | static DEFINE_SPINLOCK(lru_lock); | 69 | static DEFINE_SPINLOCK(lru_lock); |
@@ -167,13 +168,33 @@ static void glock_free(struct gfs2_glock *gl) | |||
167 | * | 168 | * |
168 | */ | 169 | */ |
169 | 170 | ||
170 | static void gfs2_glock_hold(struct gfs2_glock *gl) | 171 | void gfs2_glock_hold(struct gfs2_glock *gl) |
171 | { | 172 | { |
172 | GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0); | 173 | GLOCK_BUG_ON(gl, atomic_read(&gl->gl_ref) == 0); |
173 | atomic_inc(&gl->gl_ref); | 174 | atomic_inc(&gl->gl_ref); |
174 | } | 175 | } |
175 | 176 | ||
176 | /** | 177 | /** |
178 | * demote_ok - Check to see if it's ok to unlock a glock | ||
179 | * @gl: the glock | ||
180 | * | ||
181 | * Returns: 1 if it's ok | ||
182 | */ | ||
183 | |||
184 | static int demote_ok(const struct gfs2_glock *gl) | ||
185 | { | ||
186 | const struct gfs2_glock_operations *glops = gl->gl_ops; | ||
187 | |||
188 | if (gl->gl_state == LM_ST_UNLOCKED) | ||
189 | return 0; | ||
190 | if (!list_empty(&gl->gl_holders)) | ||
191 | return 0; | ||
192 | if (glops->go_demote_ok) | ||
193 | return glops->go_demote_ok(gl); | ||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | /** | ||
177 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list | 198 | * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list |
178 | * @gl: the glock | 199 | * @gl: the glock |
179 | * | 200 | * |
@@ -181,8 +202,13 @@ static void gfs2_glock_hold(struct gfs2_glock *gl) | |||
181 | 202 | ||
182 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | 203 | static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) |
183 | { | 204 | { |
205 | int may_reclaim; | ||
206 | may_reclaim = (demote_ok(gl) && | ||
207 | (atomic_read(&gl->gl_ref) == 1 || | ||
208 | (gl->gl_name.ln_type == LM_TYPE_INODE && | ||
209 | atomic_read(&gl->gl_ref) <= 2))); | ||
184 | spin_lock(&lru_lock); | 210 | spin_lock(&lru_lock); |
185 | if (list_empty(&gl->gl_lru) && gl->gl_state != LM_ST_UNLOCKED) { | 211 | if (list_empty(&gl->gl_lru) && may_reclaim) { |
186 | list_add_tail(&gl->gl_lru, &lru_list); | 212 | list_add_tail(&gl->gl_lru, &lru_list); |
187 | atomic_inc(&lru_count); | 213 | atomic_inc(&lru_count); |
188 | } | 214 | } |
@@ -190,6 +216,21 @@ static void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl) | |||
190 | } | 216 | } |
191 | 217 | ||
192 | /** | 218 | /** |
219 | * gfs2_glock_put_nolock() - Decrement reference count on glock | ||
220 | * @gl: The glock to put | ||
221 | * | ||
222 | * This function should only be used if the caller has its own reference | ||
223 | * to the glock, in addition to the one it is dropping. | ||
224 | */ | ||
225 | |||
226 | void gfs2_glock_put_nolock(struct gfs2_glock *gl) | ||
227 | { | ||
228 | if (atomic_dec_and_test(&gl->gl_ref)) | ||
229 | GLOCK_BUG_ON(gl, 1); | ||
230 | gfs2_glock_schedule_for_reclaim(gl); | ||
231 | } | ||
232 | |||
233 | /** | ||
193 | * gfs2_glock_put() - Decrement reference count on glock | 234 | * gfs2_glock_put() - Decrement reference count on glock |
194 | * @gl: The glock to put | 235 | * @gl: The glock to put |
195 | * | 236 | * |
@@ -214,9 +255,9 @@ int gfs2_glock_put(struct gfs2_glock *gl) | |||
214 | rv = 1; | 255 | rv = 1; |
215 | goto out; | 256 | goto out; |
216 | } | 257 | } |
217 | /* 1 for being hashed, 1 for having state != LM_ST_UNLOCKED */ | 258 | spin_lock(&gl->gl_spin); |
218 | if (atomic_read(&gl->gl_ref) == 2) | 259 | gfs2_glock_schedule_for_reclaim(gl); |
219 | gfs2_glock_schedule_for_reclaim(gl); | 260 | spin_unlock(&gl->gl_spin); |
220 | write_unlock(gl_lock_addr(gl->gl_hash)); | 261 | write_unlock(gl_lock_addr(gl->gl_hash)); |
221 | out: | 262 | out: |
222 | return rv; | 263 | return rv; |
@@ -398,7 +439,7 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state) | |||
398 | if (held2) | 439 | if (held2) |
399 | gfs2_glock_hold(gl); | 440 | gfs2_glock_hold(gl); |
400 | else | 441 | else |
401 | gfs2_glock_put(gl); | 442 | gfs2_glock_put_nolock(gl); |
402 | } | 443 | } |
403 | 444 | ||
404 | gl->gl_state = new_state; | 445 | gl->gl_state = new_state; |
@@ -633,12 +674,35 @@ out: | |||
633 | out_sched: | 674 | out_sched: |
634 | gfs2_glock_hold(gl); | 675 | gfs2_glock_hold(gl); |
635 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 676 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
636 | gfs2_glock_put(gl); | 677 | gfs2_glock_put_nolock(gl); |
637 | out_unlock: | 678 | out_unlock: |
638 | clear_bit(GLF_LOCK, &gl->gl_flags); | 679 | clear_bit(GLF_LOCK, &gl->gl_flags); |
639 | goto out; | 680 | goto out; |
640 | } | 681 | } |
641 | 682 | ||
683 | static void delete_work_func(struct work_struct *work) | ||
684 | { | ||
685 | struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete); | ||
686 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
687 | struct gfs2_inode *ip = NULL; | ||
688 | struct inode *inode; | ||
689 | u64 no_addr = 0; | ||
690 | |||
691 | spin_lock(&gl->gl_spin); | ||
692 | ip = (struct gfs2_inode *)gl->gl_object; | ||
693 | if (ip) | ||
694 | no_addr = ip->i_no_addr; | ||
695 | spin_unlock(&gl->gl_spin); | ||
696 | if (ip) { | ||
697 | inode = gfs2_ilookup(sdp->sd_vfs, no_addr); | ||
698 | if (inode) { | ||
699 | d_prune_aliases(inode); | ||
700 | iput(inode); | ||
701 | } | ||
702 | } | ||
703 | gfs2_glock_put(gl); | ||
704 | } | ||
705 | |||
642 | static void glock_work_func(struct work_struct *work) | 706 | static void glock_work_func(struct work_struct *work) |
643 | { | 707 | { |
644 | unsigned long delay = 0; | 708 | unsigned long delay = 0; |
@@ -717,6 +781,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, | |||
717 | gl->gl_sbd = sdp; | 781 | gl->gl_sbd = sdp; |
718 | gl->gl_aspace = NULL; | 782 | gl->gl_aspace = NULL; |
719 | INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); | 783 | INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); |
784 | INIT_WORK(&gl->gl_delete, delete_work_func); | ||
720 | 785 | ||
721 | /* If this glock protects actual on-disk data or metadata blocks, | 786 | /* If this glock protects actual on-disk data or metadata blocks, |
722 | create a VFS inode to manage the pages/buffers holding them. */ | 787 | create a VFS inode to manage the pages/buffers holding them. */ |
@@ -858,6 +923,8 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state, | |||
858 | gl->gl_demote_state != state) { | 923 | gl->gl_demote_state != state) { |
859 | gl->gl_demote_state = LM_ST_UNLOCKED; | 924 | gl->gl_demote_state = LM_ST_UNLOCKED; |
860 | } | 925 | } |
926 | if (gl->gl_ops->go_callback) | ||
927 | gl->gl_ops->go_callback(gl); | ||
861 | trace_gfs2_demote_rq(gl); | 928 | trace_gfs2_demote_rq(gl); |
862 | } | 929 | } |
863 | 930 | ||
@@ -1274,33 +1341,12 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret) | |||
1274 | gfs2_glock_put(gl); | 1341 | gfs2_glock_put(gl); |
1275 | } | 1342 | } |
1276 | 1343 | ||
1277 | /** | ||
1278 | * demote_ok - Check to see if it's ok to unlock a glock | ||
1279 | * @gl: the glock | ||
1280 | * | ||
1281 | * Returns: 1 if it's ok | ||
1282 | */ | ||
1283 | |||
1284 | static int demote_ok(const struct gfs2_glock *gl) | ||
1285 | { | ||
1286 | const struct gfs2_glock_operations *glops = gl->gl_ops; | ||
1287 | |||
1288 | if (gl->gl_state == LM_ST_UNLOCKED) | ||
1289 | return 0; | ||
1290 | if (!list_empty(&gl->gl_holders)) | ||
1291 | return 0; | ||
1292 | if (glops->go_demote_ok) | ||
1293 | return glops->go_demote_ok(gl); | ||
1294 | return 1; | ||
1295 | } | ||
1296 | |||
1297 | 1344 | ||
1298 | static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | 1345 | static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) |
1299 | { | 1346 | { |
1300 | struct gfs2_glock *gl; | 1347 | struct gfs2_glock *gl; |
1301 | int may_demote; | 1348 | int may_demote; |
1302 | int nr_skipped = 0; | 1349 | int nr_skipped = 0; |
1303 | int got_ref = 0; | ||
1304 | LIST_HEAD(skipped); | 1350 | LIST_HEAD(skipped); |
1305 | 1351 | ||
1306 | if (nr == 0) | 1352 | if (nr == 0) |
@@ -1315,37 +1361,29 @@ static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask) | |||
1315 | list_del_init(&gl->gl_lru); | 1361 | list_del_init(&gl->gl_lru); |
1316 | atomic_dec(&lru_count); | 1362 | atomic_dec(&lru_count); |
1317 | 1363 | ||
1364 | /* Check if glock is about to be freed */ | ||
1365 | if (atomic_read(&gl->gl_ref) == 0) | ||
1366 | continue; | ||
1367 | |||
1318 | /* Test for being demotable */ | 1368 | /* Test for being demotable */ |
1319 | if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { | 1369 | if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) { |
1320 | gfs2_glock_hold(gl); | 1370 | gfs2_glock_hold(gl); |
1321 | got_ref = 1; | ||
1322 | spin_unlock(&lru_lock); | 1371 | spin_unlock(&lru_lock); |
1323 | spin_lock(&gl->gl_spin); | 1372 | spin_lock(&gl->gl_spin); |
1324 | may_demote = demote_ok(gl); | 1373 | may_demote = demote_ok(gl); |
1325 | spin_unlock(&gl->gl_spin); | ||
1326 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
1327 | if (may_demote) { | 1374 | if (may_demote) { |
1328 | handle_callback(gl, LM_ST_UNLOCKED, 0); | 1375 | handle_callback(gl, LM_ST_UNLOCKED, 0); |
1329 | nr--; | 1376 | nr--; |
1330 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | ||
1331 | gfs2_glock_put(gl); | ||
1332 | got_ref = 0; | ||
1333 | } | 1377 | } |
1378 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | ||
1379 | gfs2_glock_put_nolock(gl); | ||
1380 | spin_unlock(&gl->gl_spin); | ||
1381 | clear_bit(GLF_LOCK, &gl->gl_flags); | ||
1334 | spin_lock(&lru_lock); | 1382 | spin_lock(&lru_lock); |
1335 | if (may_demote) | 1383 | continue; |
1336 | continue; | ||
1337 | } | ||
1338 | if (list_empty(&gl->gl_lru) && | ||
1339 | (atomic_read(&gl->gl_ref) <= (2 + got_ref))) { | ||
1340 | nr_skipped++; | ||
1341 | list_add(&gl->gl_lru, &skipped); | ||
1342 | } | ||
1343 | if (got_ref) { | ||
1344 | spin_unlock(&lru_lock); | ||
1345 | gfs2_glock_put(gl); | ||
1346 | spin_lock(&lru_lock); | ||
1347 | got_ref = 0; | ||
1348 | } | 1384 | } |
1385 | nr_skipped++; | ||
1386 | list_add(&gl->gl_lru, &skipped); | ||
1349 | } | 1387 | } |
1350 | list_splice(&skipped, &lru_list); | 1388 | list_splice(&skipped, &lru_list); |
1351 | atomic_add(nr_skipped, &lru_count); | 1389 | atomic_add(nr_skipped, &lru_count); |
@@ -1727,6 +1765,11 @@ int __init gfs2_glock_init(void) | |||
1727 | glock_workqueue = create_workqueue("glock_workqueue"); | 1765 | glock_workqueue = create_workqueue("glock_workqueue"); |
1728 | if (IS_ERR(glock_workqueue)) | 1766 | if (IS_ERR(glock_workqueue)) |
1729 | return PTR_ERR(glock_workqueue); | 1767 | return PTR_ERR(glock_workqueue); |
1768 | gfs2_delete_workqueue = create_workqueue("delete_workqueue"); | ||
1769 | if (IS_ERR(gfs2_delete_workqueue)) { | ||
1770 | destroy_workqueue(glock_workqueue); | ||
1771 | return PTR_ERR(gfs2_delete_workqueue); | ||
1772 | } | ||
1730 | 1773 | ||
1731 | register_shrinker(&glock_shrinker); | 1774 | register_shrinker(&glock_shrinker); |
1732 | 1775 | ||
@@ -1737,6 +1780,7 @@ void gfs2_glock_exit(void) | |||
1737 | { | 1780 | { |
1738 | unregister_shrinker(&glock_shrinker); | 1781 | unregister_shrinker(&glock_shrinker); |
1739 | destroy_workqueue(glock_workqueue); | 1782 | destroy_workqueue(glock_workqueue); |
1783 | destroy_workqueue(gfs2_delete_workqueue); | ||
1740 | } | 1784 | } |
1741 | 1785 | ||
1742 | static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) | 1786 | static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) |
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index a602a28f6f08..c609894ec0d0 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h | |||
@@ -143,6 +143,7 @@ struct lm_lockops { | |||
143 | 143 | ||
144 | #define GLR_TRYFAILED 13 | 144 | #define GLR_TRYFAILED 13 |
145 | 145 | ||
146 | extern struct workqueue_struct *gfs2_delete_workqueue; | ||
146 | static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) | 147 | static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) |
147 | { | 148 | { |
148 | struct gfs2_holder *gh; | 149 | struct gfs2_holder *gh; |
@@ -191,6 +192,8 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl) | |||
191 | int gfs2_glock_get(struct gfs2_sbd *sdp, | 192 | int gfs2_glock_get(struct gfs2_sbd *sdp, |
192 | u64 number, const struct gfs2_glock_operations *glops, | 193 | u64 number, const struct gfs2_glock_operations *glops, |
193 | int create, struct gfs2_glock **glp); | 194 | int create, struct gfs2_glock **glp); |
195 | void gfs2_glock_hold(struct gfs2_glock *gl); | ||
196 | void gfs2_glock_put_nolock(struct gfs2_glock *gl); | ||
194 | int gfs2_glock_put(struct gfs2_glock *gl); | 197 | int gfs2_glock_put(struct gfs2_glock *gl); |
195 | void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, | 198 | void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags, |
196 | struct gfs2_holder *gh); | 199 | struct gfs2_holder *gh); |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index d5e4ab155ca0..6985eef06c39 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -323,6 +323,7 @@ static void trans_go_sync(struct gfs2_glock *gl) | |||
323 | 323 | ||
324 | if (gl->gl_state != LM_ST_UNLOCKED && | 324 | if (gl->gl_state != LM_ST_UNLOCKED && |
325 | test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { | 325 | test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { |
326 | flush_workqueue(gfs2_delete_workqueue); | ||
326 | gfs2_meta_syncfs(sdp); | 327 | gfs2_meta_syncfs(sdp); |
327 | gfs2_log_shutdown(sdp); | 328 | gfs2_log_shutdown(sdp); |
328 | } | 329 | } |
@@ -372,6 +373,25 @@ static int trans_go_demote_ok(const struct gfs2_glock *gl) | |||
372 | return 0; | 373 | return 0; |
373 | } | 374 | } |
374 | 375 | ||
376 | /** | ||
377 | * iopen_go_callback - schedule the dcache entry for the inode to be deleted | ||
378 | * @gl: the glock | ||
379 | * | ||
380 | * gl_spin lock is held while calling this | ||
381 | */ | ||
382 | static void iopen_go_callback(struct gfs2_glock *gl) | ||
383 | { | ||
384 | struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object; | ||
385 | |||
386 | if (gl->gl_demote_state == LM_ST_UNLOCKED && | ||
387 | gl->gl_state == LM_ST_SHARED && | ||
388 | ip && test_bit(GIF_USER, &ip->i_flags)) { | ||
389 | gfs2_glock_hold(gl); | ||
390 | if (queue_work(gfs2_delete_workqueue, &gl->gl_delete) == 0) | ||
391 | gfs2_glock_put_nolock(gl); | ||
392 | } | ||
393 | } | ||
394 | |||
375 | const struct gfs2_glock_operations gfs2_meta_glops = { | 395 | const struct gfs2_glock_operations gfs2_meta_glops = { |
376 | .go_type = LM_TYPE_META, | 396 | .go_type = LM_TYPE_META, |
377 | }; | 397 | }; |
@@ -406,6 +426,7 @@ const struct gfs2_glock_operations gfs2_trans_glops = { | |||
406 | 426 | ||
407 | const struct gfs2_glock_operations gfs2_iopen_glops = { | 427 | const struct gfs2_glock_operations gfs2_iopen_glops = { |
408 | .go_type = LM_TYPE_IOPEN, | 428 | .go_type = LM_TYPE_IOPEN, |
429 | .go_callback = iopen_go_callback, | ||
409 | }; | 430 | }; |
410 | 431 | ||
411 | const struct gfs2_glock_operations gfs2_flock_glops = { | 432 | const struct gfs2_glock_operations gfs2_flock_glops = { |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 225347fbff3c..61801ada36f0 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -159,6 +159,7 @@ struct gfs2_glock_operations { | |||
159 | int (*go_lock) (struct gfs2_holder *gh); | 159 | int (*go_lock) (struct gfs2_holder *gh); |
160 | void (*go_unlock) (struct gfs2_holder *gh); | 160 | void (*go_unlock) (struct gfs2_holder *gh); |
161 | int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl); | 161 | int (*go_dump)(struct seq_file *seq, const struct gfs2_glock *gl); |
162 | void (*go_callback) (struct gfs2_glock *gl); | ||
162 | const int go_type; | 163 | const int go_type; |
163 | const unsigned long go_min_hold_time; | 164 | const unsigned long go_min_hold_time; |
164 | }; | 165 | }; |
@@ -228,6 +229,7 @@ struct gfs2_glock { | |||
228 | struct list_head gl_ail_list; | 229 | struct list_head gl_ail_list; |
229 | atomic_t gl_ail_count; | 230 | atomic_t gl_ail_count; |
230 | struct delayed_work gl_work; | 231 | struct delayed_work gl_work; |
232 | struct work_struct gl_delete; | ||
231 | }; | 233 | }; |
232 | 234 | ||
233 | #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ | 235 | #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index daa4ae341a29..fba795798d3a 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -285,27 +285,19 @@ void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd) | |||
285 | } | 285 | } |
286 | 286 | ||
287 | tmp = rgd->rd_data - rgd->rd_free - rgd->rd_dinodes; | 287 | tmp = rgd->rd_data - rgd->rd_free - rgd->rd_dinodes; |
288 | if (count[1] + count[2] != tmp) { | 288 | if (count[1] != tmp) { |
289 | if (gfs2_consist_rgrpd(rgd)) | 289 | if (gfs2_consist_rgrpd(rgd)) |
290 | fs_err(sdp, "used data mismatch: %u != %u\n", | 290 | fs_err(sdp, "used data mismatch: %u != %u\n", |
291 | count[1], tmp); | 291 | count[1], tmp); |
292 | return; | 292 | return; |
293 | } | 293 | } |
294 | 294 | ||
295 | if (count[3] != rgd->rd_dinodes) { | 295 | if (count[2] + count[3] != rgd->rd_dinodes) { |
296 | if (gfs2_consist_rgrpd(rgd)) | 296 | if (gfs2_consist_rgrpd(rgd)) |
297 | fs_err(sdp, "used metadata mismatch: %u != %u\n", | 297 | fs_err(sdp, "used metadata mismatch: %u != %u\n", |
298 | count[3], rgd->rd_dinodes); | 298 | count[2] + count[3], rgd->rd_dinodes); |
299 | return; | 299 | return; |
300 | } | 300 | } |
301 | |||
302 | if (count[2] > count[3]) { | ||
303 | if (gfs2_consist_rgrpd(rgd)) | ||
304 | fs_err(sdp, "unlinked inodes > inodes: %u\n", | ||
305 | count[2]); | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | } | 301 | } |
310 | 302 | ||
311 | static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) | 303 | static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) |
@@ -961,7 +953,8 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al) | |||
961 | * Returns: The inode, if one has been found | 953 | * Returns: The inode, if one has been found |
962 | */ | 954 | */ |
963 | 955 | ||
964 | static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) | 956 | static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, |
957 | u64 skip) | ||
965 | { | 958 | { |
966 | struct inode *inode; | 959 | struct inode *inode; |
967 | u32 goal = 0, block; | 960 | u32 goal = 0, block; |
@@ -985,6 +978,8 @@ static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked) | |||
985 | goal++; | 978 | goal++; |
986 | if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) | 979 | if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked) |
987 | continue; | 980 | continue; |
981 | if (no_addr == skip) | ||
982 | continue; | ||
988 | *last_unlinked = no_addr; | 983 | *last_unlinked = no_addr; |
989 | inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, | 984 | inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN, |
990 | no_addr, -1, 1); | 985 | no_addr, -1, 1); |
@@ -1104,7 +1099,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1104 | if (try_rgrp_fit(rgd, al)) | 1099 | if (try_rgrp_fit(rgd, al)) |
1105 | goto out; | 1100 | goto out; |
1106 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1101 | if (rgd->rd_flags & GFS2_RDF_CHECK) |
1107 | inode = try_rgrp_unlink(rgd, last_unlinked); | 1102 | inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); |
1108 | if (!rg_locked) | 1103 | if (!rg_locked) |
1109 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1104 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1110 | if (inode) | 1105 | if (inode) |
@@ -1138,7 +1133,7 @@ static struct inode *get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) | |||
1138 | if (try_rgrp_fit(rgd, al)) | 1133 | if (try_rgrp_fit(rgd, al)) |
1139 | goto out; | 1134 | goto out; |
1140 | if (rgd->rd_flags & GFS2_RDF_CHECK) | 1135 | if (rgd->rd_flags & GFS2_RDF_CHECK) |
1141 | inode = try_rgrp_unlink(rgd, last_unlinked); | 1136 | inode = try_rgrp_unlink(rgd, last_unlinked, ip->i_no_addr); |
1142 | if (!rg_locked) | 1137 | if (!rg_locked) |
1143 | gfs2_glock_dq_uninit(&al->al_rgd_gh); | 1138 | gfs2_glock_dq_uninit(&al->al_rgd_gh); |
1144 | if (inode) | 1139 | if (inode) |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 0a6801336470..f522bb017973 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -353,7 +353,7 @@ fail: | |||
353 | return error; | 353 | return error; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf) | 356 | void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, const void *buf) |
357 | { | 357 | { |
358 | const struct gfs2_statfs_change *str = buf; | 358 | const struct gfs2_statfs_change *str = buf; |
359 | 359 | ||
@@ -441,6 +441,29 @@ void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | |||
441 | brelse(l_bh); | 441 | brelse(l_bh); |
442 | } | 442 | } |
443 | 443 | ||
444 | void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | ||
445 | struct buffer_head *l_bh) | ||
446 | { | ||
447 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | ||
448 | struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode); | ||
449 | struct gfs2_statfs_change_host *m_sc = &sdp->sd_statfs_master; | ||
450 | struct gfs2_statfs_change_host *l_sc = &sdp->sd_statfs_local; | ||
451 | |||
452 | gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); | ||
453 | |||
454 | spin_lock(&sdp->sd_statfs_spin); | ||
455 | m_sc->sc_total += l_sc->sc_total; | ||
456 | m_sc->sc_free += l_sc->sc_free; | ||
457 | m_sc->sc_dinodes += l_sc->sc_dinodes; | ||
458 | memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); | ||
459 | memset(l_bh->b_data + sizeof(struct gfs2_dinode), | ||
460 | 0, sizeof(struct gfs2_statfs_change)); | ||
461 | spin_unlock(&sdp->sd_statfs_spin); | ||
462 | |||
463 | gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); | ||
464 | gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); | ||
465 | } | ||
466 | |||
444 | int gfs2_statfs_sync(struct gfs2_sbd *sdp) | 467 | int gfs2_statfs_sync(struct gfs2_sbd *sdp) |
445 | { | 468 | { |
446 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); | 469 | struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode); |
@@ -477,19 +500,7 @@ int gfs2_statfs_sync(struct gfs2_sbd *sdp) | |||
477 | if (error) | 500 | if (error) |
478 | goto out_bh2; | 501 | goto out_bh2; |
479 | 502 | ||
480 | gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1); | 503 | update_statfs(sdp, m_bh, l_bh); |
481 | |||
482 | spin_lock(&sdp->sd_statfs_spin); | ||
483 | m_sc->sc_total += l_sc->sc_total; | ||
484 | m_sc->sc_free += l_sc->sc_free; | ||
485 | m_sc->sc_dinodes += l_sc->sc_dinodes; | ||
486 | memset(l_sc, 0, sizeof(struct gfs2_statfs_change)); | ||
487 | memset(l_bh->b_data + sizeof(struct gfs2_dinode), | ||
488 | 0, sizeof(struct gfs2_statfs_change)); | ||
489 | spin_unlock(&sdp->sd_statfs_spin); | ||
490 | |||
491 | gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1); | ||
492 | gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode)); | ||
493 | 504 | ||
494 | gfs2_trans_end(sdp); | 505 | gfs2_trans_end(sdp); |
495 | 506 | ||
@@ -680,6 +691,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) | |||
680 | struct gfs2_holder t_gh; | 691 | struct gfs2_holder t_gh; |
681 | int error; | 692 | int error; |
682 | 693 | ||
694 | flush_workqueue(gfs2_delete_workqueue); | ||
683 | gfs2_quota_sync(sdp); | 695 | gfs2_quota_sync(sdp); |
684 | gfs2_statfs_sync(sdp); | 696 | gfs2_statfs_sync(sdp); |
685 | 697 | ||
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h index b56413e3e40d..22e0417ed996 100644 --- a/fs/gfs2/super.h +++ b/fs/gfs2/super.h | |||
@@ -40,6 +40,10 @@ extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); | |||
40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); | 40 | extern int gfs2_statfs_init(struct gfs2_sbd *sdp); |
41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, | 41 | extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, |
42 | s64 dinodes); | 42 | s64 dinodes); |
43 | extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc, | ||
44 | const void *buf); | ||
45 | extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh, | ||
46 | struct buffer_head *l_bh); | ||
43 | extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); | 47 | extern int gfs2_statfs_sync(struct gfs2_sbd *sdp); |
44 | 48 | ||
45 | extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); | 49 | extern int gfs2_freeze_fs(struct gfs2_sbd *sdp); |
diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index 98d6ef1c1dc0..148d55c14171 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h | |||
@@ -1,12 +1,11 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM gfs2 | ||
3 | |||
1 | #if !defined(_TRACE_GFS2_H) || defined(TRACE_HEADER_MULTI_READ) | 4 | #if !defined(_TRACE_GFS2_H) || defined(TRACE_HEADER_MULTI_READ) |
2 | #define _TRACE_GFS2_H | 5 | #define _TRACE_GFS2_H |
3 | 6 | ||
4 | #include <linux/tracepoint.h> | 7 | #include <linux/tracepoint.h> |
5 | 8 | ||
6 | #undef TRACE_SYSTEM | ||
7 | #define TRACE_SYSTEM gfs2 | ||
8 | #define TRACE_INCLUDE_FILE trace_gfs2 | ||
9 | |||
10 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
11 | #include <linux/buffer_head.h> | 10 | #include <linux/buffer_head.h> |
12 | #include <linux/dlmconstants.h> | 11 | #include <linux/dlmconstants.h> |
@@ -403,5 +402,6 @@ TRACE_EVENT(gfs2_block_alloc, | |||
403 | /* This part must be outside protection */ | 402 | /* This part must be outside protection */ |
404 | #undef TRACE_INCLUDE_PATH | 403 | #undef TRACE_INCLUDE_PATH |
405 | #define TRACE_INCLUDE_PATH . | 404 | #define TRACE_INCLUDE_PATH . |
405 | #define TRACE_INCLUDE_FILE trace_gfs2 | ||
406 | #include <trace/define_trace.h> | 406 | #include <trace/define_trace.h> |
407 | 407 | ||
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 6f833dc8e910..f7fcbe49da72 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/nls.h> | 19 | #include <linux/nls.h> |
20 | #include <linux/parser.h> | 20 | #include <linux/parser.h> |
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/smp_lock.h> | ||
22 | #include <linux/vfs.h> | 23 | #include <linux/vfs.h> |
23 | 24 | ||
24 | #include "hfs_fs.h" | 25 | #include "hfs_fs.h" |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 9fc3af0c0dab..c0759fe0855b 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/smp_lock.h> | ||
15 | #include <linux/vfs.h> | 16 | #include <linux/vfs.h> |
16 | #include <linux/nls.h> | 17 | #include <linux/nls.h> |
17 | 18 | ||
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index fe02ad4740e7..032604e5ef2c 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -972,6 +972,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) | |||
972 | sb->s_blocksize_bits = 10; | 972 | sb->s_blocksize_bits = 10; |
973 | sb->s_magic = HOSTFS_SUPER_MAGIC; | 973 | sb->s_magic = HOSTFS_SUPER_MAGIC; |
974 | sb->s_op = &hostfs_sbops; | 974 | sb->s_op = &hostfs_sbops; |
975 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
975 | 976 | ||
976 | /* NULL is printed as <NULL> by sprintf: avoid that. */ | 977 | /* NULL is printed as <NULL> by sprintf: avoid that. */ |
977 | if (req_root == NULL) | 978 | if (req_root == NULL) |
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index 6916c41d7017..8865c94f55f6 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * directory VFS functions | 6 | * directory VFS functions |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/smp_lock.h> | ||
9 | #include "hpfs_fn.h" | 10 | #include "hpfs_fn.h" |
10 | 11 | ||
11 | static int hpfs_dir_release(struct inode *inode, struct file *filp) | 12 | static int hpfs_dir_release(struct inode *inode, struct file *filp) |
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 64ab52259204..3efabff00367 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * file VFS functions | 6 | * file VFS functions |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/smp_lock.h> | ||
9 | #include "hpfs_fn.h" | 10 | #include "hpfs_fn.h" |
10 | 11 | ||
11 | #define BLOCKS(size) (((size) + 511) >> 9) | 12 | #define BLOCKS(size) (((size) + 511) >> 9) |
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index c2ea31bae313..701ca54c0867 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
14 | #include <linux/buffer_head.h> | 14 | #include <linux/buffer_head.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/smp_lock.h> | ||
17 | 16 | ||
18 | #include "hpfs.h" | 17 | #include "hpfs.h" |
19 | 18 | ||
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 39a1bfbea312..fe703ae46bc7 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * inode VFS functions | 6 | * inode VFS functions |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/smp_lock.h> | ||
9 | #include "hpfs_fn.h" | 10 | #include "hpfs_fn.h" |
10 | 11 | ||
11 | void hpfs_init_inode(struct inode *i) | 12 | void hpfs_init_inode(struct inode *i) |
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index b649232dde97..82b9c4ba9ed0 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * adding & removing files & directories | 6 | * adding & removing files & directories |
7 | */ | 7 | */ |
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | #include <linux/smp_lock.h> | ||
9 | #include "hpfs_fn.h" | 10 | #include "hpfs_fn.h" |
10 | 11 | ||
11 | static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 12 | static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
diff --git a/fs/inode.c b/fs/inode.c index a88baebf77cf..ae7b67e48661 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/fsnotify.h> | 25 | #include <linux/fsnotify.h> |
26 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
27 | #include <linux/async.h> | 27 | #include <linux/async.h> |
28 | #include <linux/posix_acl.h> | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * This is needed for the following functions: | 31 | * This is needed for the following functions: |
@@ -119,12 +120,11 @@ static void wake_up_inode(struct inode *inode) | |||
119 | * These are initializations that need to be done on every inode | 120 | * These are initializations that need to be done on every inode |
120 | * allocation as the fields are not initialised by slab allocation. | 121 | * allocation as the fields are not initialised by slab allocation. |
121 | */ | 122 | */ |
122 | struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | 123 | int inode_init_always(struct super_block *sb, struct inode *inode) |
123 | { | 124 | { |
124 | static const struct address_space_operations empty_aops; | 125 | static const struct address_space_operations empty_aops; |
125 | static struct inode_operations empty_iops; | 126 | static struct inode_operations empty_iops; |
126 | static const struct file_operations empty_fops; | 127 | static const struct file_operations empty_fops; |
127 | |||
128 | struct address_space *const mapping = &inode->i_data; | 128 | struct address_space *const mapping = &inode->i_data; |
129 | 129 | ||
130 | inode->i_sb = sb; | 130 | inode->i_sb = sb; |
@@ -151,7 +151,7 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
151 | inode->dirtied_when = 0; | 151 | inode->dirtied_when = 0; |
152 | 152 | ||
153 | if (security_inode_alloc(inode)) | 153 | if (security_inode_alloc(inode)) |
154 | goto out_free_inode; | 154 | goto out; |
155 | 155 | ||
156 | /* allocate and initialize an i_integrity */ | 156 | /* allocate and initialize an i_integrity */ |
157 | if (ima_inode_alloc(inode)) | 157 | if (ima_inode_alloc(inode)) |
@@ -189,21 +189,20 @@ struct inode *inode_init_always(struct super_block *sb, struct inode *inode) | |||
189 | } | 189 | } |
190 | inode->i_private = NULL; | 190 | inode->i_private = NULL; |
191 | inode->i_mapping = mapping; | 191 | inode->i_mapping = mapping; |
192 | #ifdef CONFIG_FS_POSIX_ACL | ||
193 | inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; | ||
194 | #endif | ||
192 | 195 | ||
193 | #ifdef CONFIG_FSNOTIFY | 196 | #ifdef CONFIG_FSNOTIFY |
194 | inode->i_fsnotify_mask = 0; | 197 | inode->i_fsnotify_mask = 0; |
195 | #endif | 198 | #endif |
196 | 199 | ||
197 | return inode; | 200 | return 0; |
198 | 201 | ||
199 | out_free_security: | 202 | out_free_security: |
200 | security_inode_free(inode); | 203 | security_inode_free(inode); |
201 | out_free_inode: | 204 | out: |
202 | if (inode->i_sb->s_op->destroy_inode) | 205 | return -ENOMEM; |
203 | inode->i_sb->s_op->destroy_inode(inode); | ||
204 | else | ||
205 | kmem_cache_free(inode_cachep, (inode)); | ||
206 | return NULL; | ||
207 | } | 206 | } |
208 | EXPORT_SYMBOL(inode_init_always); | 207 | EXPORT_SYMBOL(inode_init_always); |
209 | 208 | ||
@@ -216,24 +215,43 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
216 | else | 215 | else |
217 | inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); | 216 | inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); |
218 | 217 | ||
219 | if (inode) | 218 | if (!inode) |
220 | return inode_init_always(sb, inode); | 219 | return NULL; |
221 | return NULL; | 220 | |
221 | if (unlikely(inode_init_always(sb, inode))) { | ||
222 | if (inode->i_sb->s_op->destroy_inode) | ||
223 | inode->i_sb->s_op->destroy_inode(inode); | ||
224 | else | ||
225 | kmem_cache_free(inode_cachep, inode); | ||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | return inode; | ||
222 | } | 230 | } |
223 | 231 | ||
224 | void destroy_inode(struct inode *inode) | 232 | void __destroy_inode(struct inode *inode) |
225 | { | 233 | { |
226 | BUG_ON(inode_has_buffers(inode)); | 234 | BUG_ON(inode_has_buffers(inode)); |
227 | ima_inode_free(inode); | 235 | ima_inode_free(inode); |
228 | security_inode_free(inode); | 236 | security_inode_free(inode); |
229 | fsnotify_inode_delete(inode); | 237 | fsnotify_inode_delete(inode); |
238 | #ifdef CONFIG_FS_POSIX_ACL | ||
239 | if (inode->i_acl && inode->i_acl != ACL_NOT_CACHED) | ||
240 | posix_acl_release(inode->i_acl); | ||
241 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) | ||
242 | posix_acl_release(inode->i_default_acl); | ||
243 | #endif | ||
244 | } | ||
245 | EXPORT_SYMBOL(__destroy_inode); | ||
246 | |||
247 | void destroy_inode(struct inode *inode) | ||
248 | { | ||
249 | __destroy_inode(inode); | ||
230 | if (inode->i_sb->s_op->destroy_inode) | 250 | if (inode->i_sb->s_op->destroy_inode) |
231 | inode->i_sb->s_op->destroy_inode(inode); | 251 | inode->i_sb->s_op->destroy_inode(inode); |
232 | else | 252 | else |
233 | kmem_cache_free(inode_cachep, (inode)); | 253 | kmem_cache_free(inode_cachep, (inode)); |
234 | } | 254 | } |
235 | EXPORT_SYMBOL(destroy_inode); | ||
236 | |||
237 | 255 | ||
238 | /* | 256 | /* |
239 | * These are initializations that only need to be done | 257 | * These are initializations that only need to be done |
@@ -665,12 +683,17 @@ void unlock_new_inode(struct inode *inode) | |||
665 | if (inode->i_mode & S_IFDIR) { | 683 | if (inode->i_mode & S_IFDIR) { |
666 | struct file_system_type *type = inode->i_sb->s_type; | 684 | struct file_system_type *type = inode->i_sb->s_type; |
667 | 685 | ||
668 | /* | 686 | /* Set new key only if filesystem hasn't already changed it */ |
669 | * ensure nobody is actually holding i_mutex | 687 | if (!lockdep_match_class(&inode->i_mutex, |
670 | */ | 688 | &type->i_mutex_key)) { |
671 | mutex_destroy(&inode->i_mutex); | 689 | /* |
672 | mutex_init(&inode->i_mutex); | 690 | * ensure nobody is actually holding i_mutex |
673 | lockdep_set_class(&inode->i_mutex, &type->i_mutex_dir_key); | 691 | */ |
692 | mutex_destroy(&inode->i_mutex); | ||
693 | mutex_init(&inode->i_mutex); | ||
694 | lockdep_set_class(&inode->i_mutex, | ||
695 | &type->i_mutex_dir_key); | ||
696 | } | ||
674 | } | 697 | } |
675 | #endif | 698 | #endif |
676 | /* | 699 | /* |
@@ -1408,7 +1431,7 @@ EXPORT_SYMBOL(touch_atime); | |||
1408 | * for writeback. Note that this function is meant exclusively for | 1431 | * for writeback. Note that this function is meant exclusively for |
1409 | * usage in the file write path of filesystems, and filesystems may | 1432 | * usage in the file write path of filesystems, and filesystems may |
1410 | * choose to explicitly ignore update via this function with the | 1433 | * choose to explicitly ignore update via this function with the |
1411 | * S_NOCTIME inode flag, e.g. for network filesystem where these | 1434 | * S_NOCMTIME inode flag, e.g. for network filesystem where these |
1412 | * timestamps are handled by the server. | 1435 | * timestamps are handled by the server. |
1413 | */ | 1436 | */ |
1414 | 1437 | ||
diff --git a/fs/ioctl.c b/fs/ioctl.c index 286f38dfc6c0..5612880fcbe7 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/uaccess.h> | 15 | #include <linux/uaccess.h> |
16 | #include <linux/writeback.h> | 16 | #include <linux/writeback.h> |
17 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
18 | #include <linux/falloc.h> | ||
18 | 19 | ||
19 | #include <asm/ioctls.h> | 20 | #include <asm/ioctls.h> |
20 | 21 | ||
@@ -70,9 +71,7 @@ static int ioctl_fibmap(struct file *filp, int __user *p) | |||
70 | res = get_user(block, p); | 71 | res = get_user(block, p); |
71 | if (res) | 72 | if (res) |
72 | return res; | 73 | return res; |
73 | lock_kernel(); | ||
74 | res = mapping->a_ops->bmap(mapping, block); | 74 | res = mapping->a_ops->bmap(mapping, block); |
75 | unlock_kernel(); | ||
76 | return put_user(res, p); | 75 | return put_user(res, p); |
77 | } | 76 | } |
78 | 77 | ||
@@ -405,6 +404,37 @@ EXPORT_SYMBOL(generic_block_fiemap); | |||
405 | 404 | ||
406 | #endif /* CONFIG_BLOCK */ | 405 | #endif /* CONFIG_BLOCK */ |
407 | 406 | ||
407 | /* | ||
408 | * This provides compatibility with legacy XFS pre-allocation ioctls | ||
409 | * which predate the fallocate syscall. | ||
410 | * | ||
411 | * Only the l_start, l_len and l_whence fields of the 'struct space_resv' | ||
412 | * are used here, rest are ignored. | ||
413 | */ | ||
414 | int ioctl_preallocate(struct file *filp, void __user *argp) | ||
415 | { | ||
416 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
417 | struct space_resv sr; | ||
418 | |||
419 | if (copy_from_user(&sr, argp, sizeof(sr))) | ||
420 | return -EFAULT; | ||
421 | |||
422 | switch (sr.l_whence) { | ||
423 | case SEEK_SET: | ||
424 | break; | ||
425 | case SEEK_CUR: | ||
426 | sr.l_start += filp->f_pos; | ||
427 | break; | ||
428 | case SEEK_END: | ||
429 | sr.l_start += i_size_read(inode); | ||
430 | break; | ||
431 | default: | ||
432 | return -EINVAL; | ||
433 | } | ||
434 | |||
435 | return do_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); | ||
436 | } | ||
437 | |||
408 | static int file_ioctl(struct file *filp, unsigned int cmd, | 438 | static int file_ioctl(struct file *filp, unsigned int cmd, |
409 | unsigned long arg) | 439 | unsigned long arg) |
410 | { | 440 | { |
@@ -416,6 +446,9 @@ static int file_ioctl(struct file *filp, unsigned int cmd, | |||
416 | return ioctl_fibmap(filp, p); | 446 | return ioctl_fibmap(filp, p); |
417 | case FIONREAD: | 447 | case FIONREAD: |
418 | return put_user(i_size_read(inode) - filp->f_pos, p); | 448 | return put_user(i_size_read(inode) - filp->f_pos, p); |
449 | case FS_IOC_RESVSP: | ||
450 | case FS_IOC_RESVSP64: | ||
451 | return ioctl_preallocate(filp, p); | ||
419 | } | 452 | } |
420 | 453 | ||
421 | return vfs_ioctl(filp, cmd, arg); | 454 | return vfs_ioctl(filp, cmd, arg); |
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 2f0dc5a14633..8ba5441063be 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c | |||
@@ -195,9 +195,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp, | |||
195 | * Do not report hidden files if so instructed, or associated | 195 | * Do not report hidden files if so instructed, or associated |
196 | * files unless instructed to do so | 196 | * files unless instructed to do so |
197 | */ | 197 | */ |
198 | if ((sbi->s_hide == 'y' && | 198 | if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) || |
199 | (de->flags[-sbi->s_high_sierra] & 1)) || | 199 | (!sbi->s_showassoc && |
200 | (sbi->s_showassoc =='n' && | ||
201 | (de->flags[-sbi->s_high_sierra] & 4))) { | 200 | (de->flags[-sbi->s_high_sierra] & 4))) { |
202 | filp->f_pos += de_len; | 201 | filp->f_pos += de_len; |
203 | continue; | 202 | continue; |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 068b34b5a107..85f96bc651c7 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
@@ -141,13 +141,17 @@ static const struct dentry_operations isofs_dentry_ops[] = { | |||
141 | }; | 141 | }; |
142 | 142 | ||
143 | struct iso9660_options{ | 143 | struct iso9660_options{ |
144 | char map; | 144 | unsigned int rock:1; |
145 | char rock; | 145 | unsigned int joliet:1; |
146 | char joliet; | 146 | unsigned int cruft:1; |
147 | char cruft; | 147 | unsigned int hide:1; |
148 | char hide; | 148 | unsigned int showassoc:1; |
149 | char showassoc; | 149 | unsigned int nocompress:1; |
150 | char nocompress; | 150 | unsigned int overriderockperm:1; |
151 | unsigned int uid_set:1; | ||
152 | unsigned int gid_set:1; | ||
153 | unsigned int utf8:1; | ||
154 | unsigned char map; | ||
151 | unsigned char check; | 155 | unsigned char check; |
152 | unsigned int blocksize; | 156 | unsigned int blocksize; |
153 | mode_t fmode; | 157 | mode_t fmode; |
@@ -155,7 +159,6 @@ struct iso9660_options{ | |||
155 | gid_t gid; | 159 | gid_t gid; |
156 | uid_t uid; | 160 | uid_t uid; |
157 | char *iocharset; | 161 | char *iocharset; |
158 | unsigned char utf8; | ||
159 | /* LVE */ | 162 | /* LVE */ |
160 | s32 session; | 163 | s32 session; |
161 | s32 sbsector; | 164 | s32 sbsector; |
@@ -312,7 +315,7 @@ enum { | |||
312 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, | 315 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, |
313 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, | 316 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, |
314 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, | 317 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, |
315 | Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, | 318 | Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm, |
316 | }; | 319 | }; |
317 | 320 | ||
318 | static const match_table_t tokens = { | 321 | static const match_table_t tokens = { |
@@ -340,6 +343,7 @@ static const match_table_t tokens = { | |||
340 | {Opt_gid, "gid=%u"}, | 343 | {Opt_gid, "gid=%u"}, |
341 | {Opt_mode, "mode=%u"}, | 344 | {Opt_mode, "mode=%u"}, |
342 | {Opt_dmode, "dmode=%u"}, | 345 | {Opt_dmode, "dmode=%u"}, |
346 | {Opt_overriderockperm, "overriderockperm"}, | ||
343 | {Opt_block, "block=%u"}, | 347 | {Opt_block, "block=%u"}, |
344 | {Opt_ignore, "conv=binary"}, | 348 | {Opt_ignore, "conv=binary"}, |
345 | {Opt_ignore, "conv=b"}, | 349 | {Opt_ignore, "conv=b"}, |
@@ -359,24 +363,22 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
359 | int option; | 363 | int option; |
360 | 364 | ||
361 | popt->map = 'n'; | 365 | popt->map = 'n'; |
362 | popt->rock = 'y'; | 366 | popt->rock = 1; |
363 | popt->joliet = 'y'; | 367 | popt->joliet = 1; |
364 | popt->cruft = 'n'; | 368 | popt->cruft = 0; |
365 | popt->hide = 'n'; | 369 | popt->hide = 0; |
366 | popt->showassoc = 'n'; | 370 | popt->showassoc = 0; |
367 | popt->check = 'u'; /* unset */ | 371 | popt->check = 'u'; /* unset */ |
368 | popt->nocompress = 0; | 372 | popt->nocompress = 0; |
369 | popt->blocksize = 1024; | 373 | popt->blocksize = 1024; |
370 | popt->fmode = popt->dmode = S_IRUGO | S_IXUGO; /* | 374 | popt->fmode = popt->dmode = ISOFS_INVALID_MODE; |
371 | * r-x for all. The disc could | 375 | popt->uid_set = 0; |
372 | * be shared with DOS machines so | 376 | popt->gid_set = 0; |
373 | * virtually anything could be | ||
374 | * a valid executable. | ||
375 | */ | ||
376 | popt->gid = 0; | 377 | popt->gid = 0; |
377 | popt->uid = 0; | 378 | popt->uid = 0; |
378 | popt->iocharset = NULL; | 379 | popt->iocharset = NULL; |
379 | popt->utf8 = 0; | 380 | popt->utf8 = 0; |
381 | popt->overriderockperm = 0; | ||
380 | popt->session=-1; | 382 | popt->session=-1; |
381 | popt->sbsector=-1; | 383 | popt->sbsector=-1; |
382 | if (!options) | 384 | if (!options) |
@@ -393,20 +395,20 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
393 | token = match_token(p, tokens, args); | 395 | token = match_token(p, tokens, args); |
394 | switch (token) { | 396 | switch (token) { |
395 | case Opt_norock: | 397 | case Opt_norock: |
396 | popt->rock = 'n'; | 398 | popt->rock = 0; |
397 | break; | 399 | break; |
398 | case Opt_nojoliet: | 400 | case Opt_nojoliet: |
399 | popt->joliet = 'n'; | 401 | popt->joliet = 0; |
400 | break; | 402 | break; |
401 | case Opt_hide: | 403 | case Opt_hide: |
402 | popt->hide = 'y'; | 404 | popt->hide = 1; |
403 | break; | 405 | break; |
404 | case Opt_unhide: | 406 | case Opt_unhide: |
405 | case Opt_showassoc: | 407 | case Opt_showassoc: |
406 | popt->showassoc = 'y'; | 408 | popt->showassoc = 1; |
407 | break; | 409 | break; |
408 | case Opt_cruft: | 410 | case Opt_cruft: |
409 | popt->cruft = 'y'; | 411 | popt->cruft = 1; |
410 | break; | 412 | break; |
411 | case Opt_utf8: | 413 | case Opt_utf8: |
412 | popt->utf8 = 1; | 414 | popt->utf8 = 1; |
@@ -450,11 +452,13 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
450 | if (match_int(&args[0], &option)) | 452 | if (match_int(&args[0], &option)) |
451 | return 0; | 453 | return 0; |
452 | popt->uid = option; | 454 | popt->uid = option; |
455 | popt->uid_set = 1; | ||
453 | break; | 456 | break; |
454 | case Opt_gid: | 457 | case Opt_gid: |
455 | if (match_int(&args[0], &option)) | 458 | if (match_int(&args[0], &option)) |
456 | return 0; | 459 | return 0; |
457 | popt->gid = option; | 460 | popt->gid = option; |
461 | popt->gid_set = 1; | ||
458 | break; | 462 | break; |
459 | case Opt_mode: | 463 | case Opt_mode: |
460 | if (match_int(&args[0], &option)) | 464 | if (match_int(&args[0], &option)) |
@@ -466,6 +470,9 @@ static int parse_options(char *options, struct iso9660_options *popt) | |||
466 | return 0; | 470 | return 0; |
467 | popt->dmode = option; | 471 | popt->dmode = option; |
468 | break; | 472 | break; |
473 | case Opt_overriderockperm: | ||
474 | popt->overriderockperm = 1; | ||
475 | break; | ||
469 | case Opt_block: | 476 | case Opt_block: |
470 | if (match_int(&args[0], &option)) | 477 | if (match_int(&args[0], &option)) |
471 | return 0; | 478 | return 0; |
@@ -625,7 +632,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
625 | else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) { | 632 | else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) { |
626 | sec = (struct iso_supplementary_descriptor *)vdp; | 633 | sec = (struct iso_supplementary_descriptor *)vdp; |
627 | if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { | 634 | if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { |
628 | if (opt.joliet == 'y') { | 635 | if (opt.joliet) { |
629 | if (sec->escape[2] == 0x40) | 636 | if (sec->escape[2] == 0x40) |
630 | joliet_level = 1; | 637 | joliet_level = 1; |
631 | else if (sec->escape[2] == 0x43) | 638 | else if (sec->escape[2] == 0x43) |
@@ -650,7 +657,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
650 | goto out_freebh; | 657 | goto out_freebh; |
651 | 658 | ||
652 | sbi->s_high_sierra = 1; | 659 | sbi->s_high_sierra = 1; |
653 | opt.rock = 'n'; | 660 | opt.rock = 0; |
654 | h_pri = (struct hs_primary_descriptor *)vdp; | 661 | h_pri = (struct hs_primary_descriptor *)vdp; |
655 | goto root_found; | 662 | goto root_found; |
656 | } | 663 | } |
@@ -673,7 +680,7 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) | |||
673 | 680 | ||
674 | root_found: | 681 | root_found: |
675 | 682 | ||
676 | if (joliet_level && (pri == NULL || opt.rock == 'n')) { | 683 | if (joliet_level && (pri == NULL || !opt.rock)) { |
677 | /* This is the case of Joliet with the norock mount flag. | 684 | /* This is the case of Joliet with the norock mount flag. |
678 | * A disc with both Joliet and Rock Ridge is handled later | 685 | * A disc with both Joliet and Rock Ridge is handled later |
679 | */ | 686 | */ |
@@ -802,22 +809,31 @@ root_found: | |||
802 | s->s_op = &isofs_sops; | 809 | s->s_op = &isofs_sops; |
803 | s->s_export_op = &isofs_export_ops; | 810 | s->s_export_op = &isofs_export_ops; |
804 | sbi->s_mapping = opt.map; | 811 | sbi->s_mapping = opt.map; |
805 | sbi->s_rock = (opt.rock == 'y' ? 2 : 0); | 812 | sbi->s_rock = (opt.rock ? 2 : 0); |
806 | sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ | 813 | sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ |
807 | sbi->s_cruft = opt.cruft; | 814 | sbi->s_cruft = opt.cruft; |
808 | sbi->s_hide = opt.hide; | 815 | sbi->s_hide = opt.hide; |
809 | sbi->s_showassoc = opt.showassoc; | 816 | sbi->s_showassoc = opt.showassoc; |
810 | sbi->s_uid = opt.uid; | 817 | sbi->s_uid = opt.uid; |
811 | sbi->s_gid = opt.gid; | 818 | sbi->s_gid = opt.gid; |
819 | sbi->s_uid_set = opt.uid_set; | ||
820 | sbi->s_gid_set = opt.gid_set; | ||
812 | sbi->s_utf8 = opt.utf8; | 821 | sbi->s_utf8 = opt.utf8; |
813 | sbi->s_nocompress = opt.nocompress; | 822 | sbi->s_nocompress = opt.nocompress; |
823 | sbi->s_overriderockperm = opt.overriderockperm; | ||
814 | /* | 824 | /* |
815 | * It would be incredibly stupid to allow people to mark every file | 825 | * It would be incredibly stupid to allow people to mark every file |
816 | * on the disk as suid, so we merely allow them to set the default | 826 | * on the disk as suid, so we merely allow them to set the default |
817 | * permissions. | 827 | * permissions. |
818 | */ | 828 | */ |
819 | sbi->s_fmode = opt.fmode & 0777; | 829 | if (opt.fmode != ISOFS_INVALID_MODE) |
820 | sbi->s_dmode = opt.dmode & 0777; | 830 | sbi->s_fmode = opt.fmode & 0777; |
831 | else | ||
832 | sbi->s_fmode = ISOFS_INVALID_MODE; | ||
833 | if (opt.dmode != ISOFS_INVALID_MODE) | ||
834 | sbi->s_dmode = opt.dmode & 0777; | ||
835 | else | ||
836 | sbi->s_dmode = ISOFS_INVALID_MODE; | ||
821 | 837 | ||
822 | /* | 838 | /* |
823 | * Read the root inode, which _may_ result in changing | 839 | * Read the root inode, which _may_ result in changing |
@@ -1095,18 +1111,6 @@ static const struct address_space_operations isofs_aops = { | |||
1095 | .bmap = _isofs_bmap | 1111 | .bmap = _isofs_bmap |
1096 | }; | 1112 | }; |
1097 | 1113 | ||
1098 | static inline void test_and_set_uid(uid_t *p, uid_t value) | ||
1099 | { | ||
1100 | if (value) | ||
1101 | *p = value; | ||
1102 | } | ||
1103 | |||
1104 | static inline void test_and_set_gid(gid_t *p, gid_t value) | ||
1105 | { | ||
1106 | if (value) | ||
1107 | *p = value; | ||
1108 | } | ||
1109 | |||
1110 | static int isofs_read_level3_size(struct inode *inode) | 1114 | static int isofs_read_level3_size(struct inode *inode) |
1111 | { | 1115 | { |
1112 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); | 1116 | unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); |
@@ -1261,7 +1265,10 @@ static int isofs_read_inode(struct inode *inode) | |||
1261 | ei->i_file_format = isofs_file_normal; | 1265 | ei->i_file_format = isofs_file_normal; |
1262 | 1266 | ||
1263 | if (de->flags[-high_sierra] & 2) { | 1267 | if (de->flags[-high_sierra] & 2) { |
1264 | inode->i_mode = sbi->s_dmode | S_IFDIR; | 1268 | if (sbi->s_dmode != ISOFS_INVALID_MODE) |
1269 | inode->i_mode = S_IFDIR | sbi->s_dmode; | ||
1270 | else | ||
1271 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
1265 | inode->i_nlink = 1; /* | 1272 | inode->i_nlink = 1; /* |
1266 | * Set to 1. We know there are 2, but | 1273 | * Set to 1. We know there are 2, but |
1267 | * the find utility tries to optimize | 1274 | * the find utility tries to optimize |
@@ -1270,8 +1277,16 @@ static int isofs_read_inode(struct inode *inode) | |||
1270 | * do it the hard way. | 1277 | * do it the hard way. |
1271 | */ | 1278 | */ |
1272 | } else { | 1279 | } else { |
1273 | /* Everybody gets to read the file. */ | 1280 | if (sbi->s_fmode != ISOFS_INVALID_MODE) { |
1274 | inode->i_mode = sbi->s_fmode | S_IFREG; | 1281 | inode->i_mode = S_IFREG | sbi->s_fmode; |
1282 | } else { | ||
1283 | /* | ||
1284 | * Set default permissions: r-x for all. The disc | ||
1285 | * could be shared with DOS machines so virtually | ||
1286 | * anything could be a valid executable. | ||
1287 | */ | ||
1288 | inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO; | ||
1289 | } | ||
1275 | inode->i_nlink = 1; | 1290 | inode->i_nlink = 1; |
1276 | } | 1291 | } |
1277 | inode->i_uid = sbi->s_uid; | 1292 | inode->i_uid = sbi->s_uid; |
@@ -1300,7 +1315,7 @@ static int isofs_read_inode(struct inode *inode) | |||
1300 | * this CDROM was mounted with the cruft option. | 1315 | * this CDROM was mounted with the cruft option. |
1301 | */ | 1316 | */ |
1302 | 1317 | ||
1303 | if (sbi->s_cruft == 'y') | 1318 | if (sbi->s_cruft) |
1304 | inode->i_size &= 0x00ffffff; | 1319 | inode->i_size &= 0x00ffffff; |
1305 | 1320 | ||
1306 | if (de->interleave[0]) { | 1321 | if (de->interleave[0]) { |
@@ -1346,9 +1361,18 @@ static int isofs_read_inode(struct inode *inode) | |||
1346 | if (!high_sierra) { | 1361 | if (!high_sierra) { |
1347 | parse_rock_ridge_inode(de, inode); | 1362 | parse_rock_ridge_inode(de, inode); |
1348 | /* if we want uid/gid set, override the rock ridge setting */ | 1363 | /* if we want uid/gid set, override the rock ridge setting */ |
1349 | test_and_set_uid(&inode->i_uid, sbi->s_uid); | 1364 | if (sbi->s_uid_set) |
1350 | test_and_set_gid(&inode->i_gid, sbi->s_gid); | 1365 | inode->i_uid = sbi->s_uid; |
1366 | if (sbi->s_gid_set) | ||
1367 | inode->i_gid = sbi->s_gid; | ||
1351 | } | 1368 | } |
1369 | /* Now set final access rights if overriding rock ridge setting */ | ||
1370 | if (S_ISDIR(inode->i_mode) && sbi->s_overriderockperm && | ||
1371 | sbi->s_dmode != ISOFS_INVALID_MODE) | ||
1372 | inode->i_mode = S_IFDIR | sbi->s_dmode; | ||
1373 | if (S_ISREG(inode->i_mode) && sbi->s_overriderockperm && | ||
1374 | sbi->s_fmode != ISOFS_INVALID_MODE) | ||
1375 | inode->i_mode = S_IFREG | sbi->s_fmode; | ||
1352 | 1376 | ||
1353 | /* Install the inode operations vector */ | 1377 | /* Install the inode operations vector */ |
1354 | if (S_ISREG(inode->i_mode)) { | 1378 | if (S_ISREG(inode->i_mode)) { |
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index ccbf72faf27a..7d33de84f52a 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h | |||
@@ -35,21 +35,20 @@ struct isofs_sb_info { | |||
35 | unsigned long s_log_zone_size; | 35 | unsigned long s_log_zone_size; |
36 | unsigned long s_max_size; | 36 | unsigned long s_max_size; |
37 | 37 | ||
38 | unsigned char s_high_sierra; /* A simple flag */ | ||
39 | unsigned char s_mapping; | ||
40 | int s_rock_offset; /* offset of SUSP fields within SU area */ | 38 | int s_rock_offset; /* offset of SUSP fields within SU area */ |
41 | unsigned char s_rock; | ||
42 | unsigned char s_joliet_level; | 39 | unsigned char s_joliet_level; |
43 | unsigned char s_utf8; | 40 | unsigned char s_mapping; |
44 | unsigned char s_cruft; /* Broken disks with high | 41 | unsigned int s_high_sierra:1; |
45 | byte of length containing | 42 | unsigned int s_rock:2; |
46 | junk */ | 43 | unsigned int s_utf8:1; |
47 | unsigned char s_unhide; | 44 | unsigned int s_cruft:1; /* Broken disks with high byte of length |
48 | unsigned char s_nosuid; | 45 | * containing junk */ |
49 | unsigned char s_nodev; | 46 | unsigned int s_nocompress:1; |
50 | unsigned char s_nocompress; | 47 | unsigned int s_hide:1; |
51 | unsigned char s_hide; | 48 | unsigned int s_showassoc:1; |
52 | unsigned char s_showassoc; | 49 | unsigned int s_overriderockperm:1; |
50 | unsigned int s_uid_set:1; | ||
51 | unsigned int s_gid_set:1; | ||
53 | 52 | ||
54 | mode_t s_fmode; | 53 | mode_t s_fmode; |
55 | mode_t s_dmode; | 54 | mode_t s_dmode; |
@@ -58,6 +57,8 @@ struct isofs_sb_info { | |||
58 | struct nls_table *s_nls_iocharset; /* Native language support table */ | 57 | struct nls_table *s_nls_iocharset; /* Native language support table */ |
59 | }; | 58 | }; |
60 | 59 | ||
60 | #define ISOFS_INVALID_MODE ((mode_t) -1) | ||
61 | |||
61 | static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) | 62 | static inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb) |
62 | { | 63 | { |
63 | return sb->s_fs_info; | 64 | return sb->s_fs_info; |
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c index 92c14b850e9c..a048de81c093 100644 --- a/fs/isofs/joliet.c +++ b/fs/isofs/joliet.c | |||
@@ -37,37 +37,6 @@ uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls) | |||
37 | return (op - ascii); | 37 | return (op - ascii); |
38 | } | 38 | } |
39 | 39 | ||
40 | /* Convert big endian wide character string to utf8 */ | ||
41 | static int | ||
42 | wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen) | ||
43 | { | ||
44 | const __u8 *ip; | ||
45 | __u8 *op; | ||
46 | int size; | ||
47 | __u16 c; | ||
48 | |||
49 | op = s; | ||
50 | ip = pwcs; | ||
51 | while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) { | ||
52 | c = (*ip << 8) | ip[1]; | ||
53 | if (c > 0x7f) { | ||
54 | size = utf8_wctomb(op, c, maxlen); | ||
55 | if (size == -1) { | ||
56 | /* Ignore character and move on */ | ||
57 | maxlen--; | ||
58 | } else { | ||
59 | op += size; | ||
60 | maxlen -= size; | ||
61 | } | ||
62 | } else { | ||
63 | *op++ = (__u8) c; | ||
64 | } | ||
65 | ip += 2; | ||
66 | inlen--; | ||
67 | } | ||
68 | return (op - s); | ||
69 | } | ||
70 | |||
71 | int | 40 | int |
72 | get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode) | 41 | get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode) |
73 | { | 42 | { |
@@ -79,8 +48,9 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st | |||
79 | nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset; | 48 | nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset; |
80 | 49 | ||
81 | if (utf8) { | 50 | if (utf8) { |
82 | len = wcsntombs_be(outname, de->name, | 51 | len = utf16s_to_utf8s((const wchar_t *) de->name, |
83 | de->name_len[0] >> 1, PAGE_SIZE); | 52 | de->name_len[0] >> 1, UTF16_BIG_ENDIAN, |
53 | outname, PAGE_SIZE); | ||
84 | } else { | 54 | } else { |
85 | len = uni16_to_x8(outname, (__be16 *) de->name, | 55 | len = uni16_to_x8(outname, (__be16 *) de->name, |
86 | de->name_len[0] >> 1, nls); | 56 | de->name_len[0] >> 1, nls); |
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 8299889a835e..eaa831311c9c 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c | |||
@@ -142,9 +142,9 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, | |||
142 | */ | 142 | */ |
143 | match = 0; | 143 | match = 0; |
144 | if (dlen > 0 && | 144 | if (dlen > 0 && |
145 | (sbi->s_hide =='n' || | 145 | (!sbi->s_hide || |
146 | (!(de->flags[-sbi->s_high_sierra] & 1))) && | 146 | (!(de->flags[-sbi->s_high_sierra] & 1))) && |
147 | (sbi->s_showassoc =='y' || | 147 | (sbi->s_showassoc || |
148 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { | 148 | (!(de->flags[-sbi->s_high_sierra] & 4)))) { |
149 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); | 149 | match = (isofs_cmp(dentry, dpnt, dlen) == 0); |
150 | } | 150 | } |
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 737f7246a4b5..f96f85092d1c 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c | |||
@@ -287,6 +287,7 @@ int journal_write_metadata_buffer(transaction_t *transaction, | |||
287 | struct page *new_page; | 287 | struct page *new_page; |
288 | unsigned int new_offset; | 288 | unsigned int new_offset; |
289 | struct buffer_head *bh_in = jh2bh(jh_in); | 289 | struct buffer_head *bh_in = jh2bh(jh_in); |
290 | journal_t *journal = transaction->t_journal; | ||
290 | 291 | ||
291 | /* | 292 | /* |
292 | * The buffer really shouldn't be locked: only the current committing | 293 | * The buffer really shouldn't be locked: only the current committing |
@@ -300,6 +301,11 @@ int journal_write_metadata_buffer(transaction_t *transaction, | |||
300 | J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); | 301 | J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); |
301 | 302 | ||
302 | new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); | 303 | new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); |
304 | /* keep subsequent assertions sane */ | ||
305 | new_bh->b_state = 0; | ||
306 | init_buffer(new_bh, NULL, NULL); | ||
307 | atomic_set(&new_bh->b_count, 1); | ||
308 | new_jh = journal_add_journal_head(new_bh); /* This sleeps */ | ||
303 | 309 | ||
304 | /* | 310 | /* |
305 | * If a new transaction has already done a buffer copy-out, then | 311 | * If a new transaction has already done a buffer copy-out, then |
@@ -361,14 +367,6 @@ repeat: | |||
361 | kunmap_atomic(mapped_data, KM_USER0); | 367 | kunmap_atomic(mapped_data, KM_USER0); |
362 | } | 368 | } |
363 | 369 | ||
364 | /* keep subsequent assertions sane */ | ||
365 | new_bh->b_state = 0; | ||
366 | init_buffer(new_bh, NULL, NULL); | ||
367 | atomic_set(&new_bh->b_count, 1); | ||
368 | jbd_unlock_bh_state(bh_in); | ||
369 | |||
370 | new_jh = journal_add_journal_head(new_bh); /* This sleeps */ | ||
371 | |||
372 | set_bh_page(new_bh, new_page, new_offset); | 370 | set_bh_page(new_bh, new_page, new_offset); |
373 | new_jh->b_transaction = NULL; | 371 | new_jh->b_transaction = NULL; |
374 | new_bh->b_size = jh2bh(jh_in)->b_size; | 372 | new_bh->b_size = jh2bh(jh_in)->b_size; |
@@ -385,7 +383,11 @@ repeat: | |||
385 | * copying is moved to the transaction's shadow queue. | 383 | * copying is moved to the transaction's shadow queue. |
386 | */ | 384 | */ |
387 | JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); | 385 | JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); |
388 | journal_file_buffer(jh_in, transaction, BJ_Shadow); | 386 | spin_lock(&journal->j_list_lock); |
387 | __journal_file_buffer(jh_in, transaction, BJ_Shadow); | ||
388 | spin_unlock(&journal->j_list_lock); | ||
389 | jbd_unlock_bh_state(bh_in); | ||
390 | |||
389 | JBUFFER_TRACE(new_jh, "file as BJ_IO"); | 391 | JBUFFER_TRACE(new_jh, "file as BJ_IO"); |
390 | journal_file_buffer(new_jh, transaction, BJ_IO); | 392 | journal_file_buffer(new_jh, transaction, BJ_IO); |
391 | 393 | ||
@@ -848,6 +850,12 @@ static int journal_reset(journal_t *journal) | |||
848 | 850 | ||
849 | first = be32_to_cpu(sb->s_first); | 851 | first = be32_to_cpu(sb->s_first); |
850 | last = be32_to_cpu(sb->s_maxlen); | 852 | last = be32_to_cpu(sb->s_maxlen); |
853 | if (first + JFS_MIN_JOURNAL_BLOCKS > last + 1) { | ||
854 | printk(KERN_ERR "JBD: Journal too short (blocks %lu-%lu).\n", | ||
855 | first, last); | ||
856 | journal_fail_superblock(journal); | ||
857 | return -EINVAL; | ||
858 | } | ||
851 | 859 | ||
852 | journal->j_first = first; | 860 | journal->j_first = first; |
853 | journal->j_last = last; | 861 | journal->j_last = last; |
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index ed886e6db399..c03ac11f74be 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
@@ -489,34 +489,15 @@ void journal_unlock_updates (journal_t *journal) | |||
489 | wake_up(&journal->j_wait_transaction_locked); | 489 | wake_up(&journal->j_wait_transaction_locked); |
490 | } | 490 | } |
491 | 491 | ||
492 | /* | 492 | static void warn_dirty_buffer(struct buffer_head *bh) |
493 | * Report any unexpected dirty buffers which turn up. Normally those | ||
494 | * indicate an error, but they can occur if the user is running (say) | ||
495 | * tune2fs to modify the live filesystem, so we need the option of | ||
496 | * continuing as gracefully as possible. # | ||
497 | * | ||
498 | * The caller should already hold the journal lock and | ||
499 | * j_list_lock spinlock: most callers will need those anyway | ||
500 | * in order to probe the buffer's journaling state safely. | ||
501 | */ | ||
502 | static void jbd_unexpected_dirty_buffer(struct journal_head *jh) | ||
503 | { | 493 | { |
504 | int jlist; | 494 | char b[BDEVNAME_SIZE]; |
505 | |||
506 | /* If this buffer is one which might reasonably be dirty | ||
507 | * --- ie. data, or not part of this journal --- then | ||
508 | * we're OK to leave it alone, but otherwise we need to | ||
509 | * move the dirty bit to the journal's own internal | ||
510 | * JBDDirty bit. */ | ||
511 | jlist = jh->b_jlist; | ||
512 | |||
513 | if (jlist == BJ_Metadata || jlist == BJ_Reserved || | ||
514 | jlist == BJ_Shadow || jlist == BJ_Forget) { | ||
515 | struct buffer_head *bh = jh2bh(jh); | ||
516 | 495 | ||
517 | if (test_clear_buffer_dirty(bh)) | 496 | printk(KERN_WARNING |
518 | set_buffer_jbddirty(bh); | 497 | "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). " |
519 | } | 498 | "There's a risk of filesystem corruption in case of system " |
499 | "crash.\n", | ||
500 | bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr); | ||
520 | } | 501 | } |
521 | 502 | ||
522 | /* | 503 | /* |
@@ -583,14 +564,16 @@ repeat: | |||
583 | if (jh->b_next_transaction) | 564 | if (jh->b_next_transaction) |
584 | J_ASSERT_JH(jh, jh->b_next_transaction == | 565 | J_ASSERT_JH(jh, jh->b_next_transaction == |
585 | transaction); | 566 | transaction); |
567 | warn_dirty_buffer(bh); | ||
586 | } | 568 | } |
587 | /* | 569 | /* |
588 | * In any case we need to clean the dirty flag and we must | 570 | * In any case we need to clean the dirty flag and we must |
589 | * do it under the buffer lock to be sure we don't race | 571 | * do it under the buffer lock to be sure we don't race |
590 | * with running write-out. | 572 | * with running write-out. |
591 | */ | 573 | */ |
592 | JBUFFER_TRACE(jh, "Unexpected dirty buffer"); | 574 | JBUFFER_TRACE(jh, "Journalling dirty buffer"); |
593 | jbd_unexpected_dirty_buffer(jh); | 575 | clear_buffer_dirty(bh); |
576 | set_buffer_jbddirty(bh); | ||
594 | } | 577 | } |
595 | 578 | ||
596 | unlock_buffer(bh); | 579 | unlock_buffer(bh); |
@@ -826,6 +809,15 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) | |||
826 | J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); | 809 | J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); |
827 | 810 | ||
828 | if (jh->b_transaction == NULL) { | 811 | if (jh->b_transaction == NULL) { |
812 | /* | ||
813 | * Previous journal_forget() could have left the buffer | ||
814 | * with jbddirty bit set because it was being committed. When | ||
815 | * the commit finished, we've filed the buffer for | ||
816 | * checkpointing and marked it dirty. Now we are reallocating | ||
817 | * the buffer so the transaction freeing it must have | ||
818 | * committed and so it's safe to clear the dirty bit. | ||
819 | */ | ||
820 | clear_buffer_dirty(jh2bh(jh)); | ||
829 | jh->b_transaction = transaction; | 821 | jh->b_transaction = transaction; |
830 | 822 | ||
831 | /* first access by this transaction */ | 823 | /* first access by this transaction */ |
@@ -1686,35 +1678,6 @@ out: | |||
1686 | return; | 1678 | return; |
1687 | } | 1679 | } |
1688 | 1680 | ||
1689 | /* | ||
1690 | * journal_try_to_free_buffers() could race with journal_commit_transaction() | ||
1691 | * The latter might still hold the a count on buffers when inspecting | ||
1692 | * them on t_syncdata_list or t_locked_list. | ||
1693 | * | ||
1694 | * journal_try_to_free_buffers() will call this function to | ||
1695 | * wait for the current transaction to finish syncing data buffers, before | ||
1696 | * tryinf to free that buffer. | ||
1697 | * | ||
1698 | * Called with journal->j_state_lock held. | ||
1699 | */ | ||
1700 | static void journal_wait_for_transaction_sync_data(journal_t *journal) | ||
1701 | { | ||
1702 | transaction_t *transaction = NULL; | ||
1703 | tid_t tid; | ||
1704 | |||
1705 | spin_lock(&journal->j_state_lock); | ||
1706 | transaction = journal->j_committing_transaction; | ||
1707 | |||
1708 | if (!transaction) { | ||
1709 | spin_unlock(&journal->j_state_lock); | ||
1710 | return; | ||
1711 | } | ||
1712 | |||
1713 | tid = transaction->t_tid; | ||
1714 | spin_unlock(&journal->j_state_lock); | ||
1715 | log_wait_commit(journal, tid); | ||
1716 | } | ||
1717 | |||
1718 | /** | 1681 | /** |
1719 | * int journal_try_to_free_buffers() - try to free page buffers. | 1682 | * int journal_try_to_free_buffers() - try to free page buffers. |
1720 | * @journal: journal for operation | 1683 | * @journal: journal for operation |
@@ -1786,25 +1749,6 @@ int journal_try_to_free_buffers(journal_t *journal, | |||
1786 | 1749 | ||
1787 | ret = try_to_free_buffers(page); | 1750 | ret = try_to_free_buffers(page); |
1788 | 1751 | ||
1789 | /* | ||
1790 | * There are a number of places where journal_try_to_free_buffers() | ||
1791 | * could race with journal_commit_transaction(), the later still | ||
1792 | * holds the reference to the buffers to free while processing them. | ||
1793 | * try_to_free_buffers() failed to free those buffers. Some of the | ||
1794 | * caller of releasepage() request page buffers to be dropped, otherwise | ||
1795 | * treat the fail-to-free as errors (such as generic_file_direct_IO()) | ||
1796 | * | ||
1797 | * So, if the caller of try_to_release_page() wants the synchronous | ||
1798 | * behaviour(i.e make sure buffers are dropped upon return), | ||
1799 | * let's wait for the current transaction to finish flush of | ||
1800 | * dirty data buffers, then try to free those buffers again, | ||
1801 | * with the journal locked. | ||
1802 | */ | ||
1803 | if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { | ||
1804 | journal_wait_for_transaction_sync_data(journal); | ||
1805 | ret = try_to_free_buffers(page); | ||
1806 | } | ||
1807 | |||
1808 | busy: | 1752 | busy: |
1809 | return ret; | 1753 | return ret; |
1810 | } | 1754 | } |
@@ -1830,8 +1774,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) | |||
1830 | 1774 | ||
1831 | if (jh->b_cp_transaction) { | 1775 | if (jh->b_cp_transaction) { |
1832 | JBUFFER_TRACE(jh, "on running+cp transaction"); | 1776 | JBUFFER_TRACE(jh, "on running+cp transaction"); |
1777 | /* | ||
1778 | * We don't want to write the buffer anymore, clear the | ||
1779 | * bit so that we don't confuse checks in | ||
1780 | * __journal_file_buffer | ||
1781 | */ | ||
1782 | clear_buffer_dirty(bh); | ||
1833 | __journal_file_buffer(jh, transaction, BJ_Forget); | 1783 | __journal_file_buffer(jh, transaction, BJ_Forget); |
1834 | clear_buffer_jbddirty(bh); | ||
1835 | may_free = 0; | 1784 | may_free = 0; |
1836 | } else { | 1785 | } else { |
1837 | JBUFFER_TRACE(jh, "on running transaction"); | 1786 | JBUFFER_TRACE(jh, "on running transaction"); |
@@ -2089,12 +2038,17 @@ void __journal_file_buffer(struct journal_head *jh, | |||
2089 | if (jh->b_transaction && jh->b_jlist == jlist) | 2038 | if (jh->b_transaction && jh->b_jlist == jlist) |
2090 | return; | 2039 | return; |
2091 | 2040 | ||
2092 | /* The following list of buffer states needs to be consistent | ||
2093 | * with __jbd_unexpected_dirty_buffer()'s handling of dirty | ||
2094 | * state. */ | ||
2095 | |||
2096 | if (jlist == BJ_Metadata || jlist == BJ_Reserved || | 2041 | if (jlist == BJ_Metadata || jlist == BJ_Reserved || |
2097 | jlist == BJ_Shadow || jlist == BJ_Forget) { | 2042 | jlist == BJ_Shadow || jlist == BJ_Forget) { |
2043 | /* | ||
2044 | * For metadata buffers, we track dirty bit in buffer_jbddirty | ||
2045 | * instead of buffer_dirty. We should not see a dirty bit set | ||
2046 | * here because we clear it in do_get_write_access but e.g. | ||
2047 | * tune2fs can modify the sb and set the dirty bit at any time | ||
2048 | * so we try to gracefully handle that. | ||
2049 | */ | ||
2050 | if (buffer_dirty(bh)) | ||
2051 | warn_dirty_buffer(bh); | ||
2098 | if (test_clear_buffer_dirty(bh) || | 2052 | if (test_clear_buffer_dirty(bh) || |
2099 | test_clear_buffer_jbddirty(bh)) | 2053 | test_clear_buffer_jbddirty(bh)) |
2100 | was_dirty = 1; | 2054 | was_dirty = 1; |
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 17159cacbd9e..5d70b3e6d49b 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -20,9 +20,9 @@ | |||
20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
21 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
22 | #include <linux/jbd2.h> | 22 | #include <linux/jbd2.h> |
23 | #include <linux/marker.h> | ||
24 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <trace/events/jbd2.h> | ||
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Unlink a buffer from a transaction checkpoint list. | 28 | * Unlink a buffer from a transaction checkpoint list. |
@@ -358,8 +358,7 @@ int jbd2_log_do_checkpoint(journal_t *journal) | |||
358 | * journal straight away. | 358 | * journal straight away. |
359 | */ | 359 | */ |
360 | result = jbd2_cleanup_journal_tail(journal); | 360 | result = jbd2_cleanup_journal_tail(journal); |
361 | trace_mark(jbd2_checkpoint, "dev %s need_checkpoint %d", | 361 | trace_jbd2_checkpoint(journal, result); |
362 | journal->j_devname, result); | ||
363 | jbd_debug(1, "cleanup_journal_tail returned %d\n", result); | 362 | jbd_debug(1, "cleanup_journal_tail returned %d\n", result); |
364 | if (result <= 0) | 363 | if (result <= 0) |
365 | return result; | 364 | return result; |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 0b7d3b8226fd..7b4088b2364d 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/time.h> | 16 | #include <linux/time.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/jbd2.h> | 18 | #include <linux/jbd2.h> |
19 | #include <linux/marker.h> | ||
20 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
21 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
22 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
@@ -26,6 +25,7 @@ | |||
26 | #include <linux/writeback.h> | 25 | #include <linux/writeback.h> |
27 | #include <linux/backing-dev.h> | 26 | #include <linux/backing-dev.h> |
28 | #include <linux/bio.h> | 27 | #include <linux/bio.h> |
28 | #include <trace/events/jbd2.h> | ||
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Default IO end handler for temporary BJ_IO buffer_heads. | 31 | * Default IO end handler for temporary BJ_IO buffer_heads. |
@@ -253,6 +253,7 @@ static int journal_submit_data_buffers(journal_t *journal, | |||
253 | * block allocation with delalloc. We need to write | 253 | * block allocation with delalloc. We need to write |
254 | * only allocated blocks here. | 254 | * only allocated blocks here. |
255 | */ | 255 | */ |
256 | trace_jbd2_submit_inode_data(jinode->i_vfs_inode); | ||
256 | err = journal_submit_inode_data_buffers(mapping); | 257 | err = journal_submit_inode_data_buffers(mapping); |
257 | if (!ret) | 258 | if (!ret) |
258 | ret = err; | 259 | ret = err; |
@@ -394,8 +395,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
394 | commit_transaction = journal->j_running_transaction; | 395 | commit_transaction = journal->j_running_transaction; |
395 | J_ASSERT(commit_transaction->t_state == T_RUNNING); | 396 | J_ASSERT(commit_transaction->t_state == T_RUNNING); |
396 | 397 | ||
397 | trace_mark(jbd2_start_commit, "dev %s transaction %d", | 398 | trace_jbd2_start_commit(journal, commit_transaction); |
398 | journal->j_devname, commit_transaction->t_tid); | ||
399 | jbd_debug(1, "JBD: starting commit of transaction %d\n", | 399 | jbd_debug(1, "JBD: starting commit of transaction %d\n", |
400 | commit_transaction->t_tid); | 400 | commit_transaction->t_tid); |
401 | 401 | ||
@@ -409,6 +409,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
409 | */ | 409 | */ |
410 | if (commit_transaction->t_synchronous_commit) | 410 | if (commit_transaction->t_synchronous_commit) |
411 | write_op = WRITE_SYNC_PLUG; | 411 | write_op = WRITE_SYNC_PLUG; |
412 | trace_jbd2_commit_locking(journal, commit_transaction); | ||
412 | stats.u.run.rs_wait = commit_transaction->t_max_wait; | 413 | stats.u.run.rs_wait = commit_transaction->t_max_wait; |
413 | stats.u.run.rs_locked = jiffies; | 414 | stats.u.run.rs_locked = jiffies; |
414 | stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start, | 415 | stats.u.run.rs_running = jbd2_time_diff(commit_transaction->t_start, |
@@ -484,6 +485,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
484 | */ | 485 | */ |
485 | jbd2_journal_switch_revoke_table(journal); | 486 | jbd2_journal_switch_revoke_table(journal); |
486 | 487 | ||
488 | trace_jbd2_commit_flushing(journal, commit_transaction); | ||
487 | stats.u.run.rs_flushing = jiffies; | 489 | stats.u.run.rs_flushing = jiffies; |
488 | stats.u.run.rs_locked = jbd2_time_diff(stats.u.run.rs_locked, | 490 | stats.u.run.rs_locked = jbd2_time_diff(stats.u.run.rs_locked, |
489 | stats.u.run.rs_flushing); | 491 | stats.u.run.rs_flushing); |
@@ -520,6 +522,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
520 | commit_transaction->t_state = T_COMMIT; | 522 | commit_transaction->t_state = T_COMMIT; |
521 | spin_unlock(&journal->j_state_lock); | 523 | spin_unlock(&journal->j_state_lock); |
522 | 524 | ||
525 | trace_jbd2_commit_logging(journal, commit_transaction); | ||
523 | stats.u.run.rs_logging = jiffies; | 526 | stats.u.run.rs_logging = jiffies; |
524 | stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing, | 527 | stats.u.run.rs_flushing = jbd2_time_diff(stats.u.run.rs_flushing, |
525 | stats.u.run.rs_logging); | 528 | stats.u.run.rs_logging); |
@@ -1054,9 +1057,7 @@ restart_loop: | |||
1054 | if (journal->j_commit_callback) | 1057 | if (journal->j_commit_callback) |
1055 | journal->j_commit_callback(journal, commit_transaction); | 1058 | journal->j_commit_callback(journal, commit_transaction); |
1056 | 1059 | ||
1057 | trace_mark(jbd2_end_commit, "dev %s transaction %d head %d", | 1060 | trace_jbd2_end_commit(journal, commit_transaction); |
1058 | journal->j_devname, commit_transaction->t_tid, | ||
1059 | journal->j_tail_sequence); | ||
1060 | jbd_debug(1, "JBD: commit %d complete, head %d\n", | 1061 | jbd_debug(1, "JBD: commit %d complete, head %d\n", |
1061 | journal->j_commit_sequence, journal->j_tail_sequence); | 1062 | journal->j_commit_sequence, journal->j_tail_sequence); |
1062 | if (to_free) | 1063 | if (to_free) |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 62be7d294ec2..e378cb383979 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -38,6 +38,10 @@ | |||
38 | #include <linux/debugfs.h> | 38 | #include <linux/debugfs.h> |
39 | #include <linux/seq_file.h> | 39 | #include <linux/seq_file.h> |
40 | #include <linux/math64.h> | 40 | #include <linux/math64.h> |
41 | #include <linux/hash.h> | ||
42 | |||
43 | #define CREATE_TRACE_POINTS | ||
44 | #include <trace/events/jbd2.h> | ||
41 | 45 | ||
42 | #include <asm/uaccess.h> | 46 | #include <asm/uaccess.h> |
43 | #include <asm/page.h> | 47 | #include <asm/page.h> |
@@ -293,6 +297,7 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction, | |||
293 | unsigned int new_offset; | 297 | unsigned int new_offset; |
294 | struct buffer_head *bh_in = jh2bh(jh_in); | 298 | struct buffer_head *bh_in = jh2bh(jh_in); |
295 | struct jbd2_buffer_trigger_type *triggers; | 299 | struct jbd2_buffer_trigger_type *triggers; |
300 | journal_t *journal = transaction->t_journal; | ||
296 | 301 | ||
297 | /* | 302 | /* |
298 | * The buffer really shouldn't be locked: only the current committing | 303 | * The buffer really shouldn't be locked: only the current committing |
@@ -306,6 +311,11 @@ int jbd2_journal_write_metadata_buffer(transaction_t *transaction, | |||
306 | J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); | 311 | J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); |
307 | 312 | ||
308 | new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); | 313 | new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); |
314 | /* keep subsequent assertions sane */ | ||
315 | new_bh->b_state = 0; | ||
316 | init_buffer(new_bh, NULL, NULL); | ||
317 | atomic_set(&new_bh->b_count, 1); | ||
318 | new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */ | ||
309 | 319 | ||
310 | /* | 320 | /* |
311 | * If a new transaction has already done a buffer copy-out, then | 321 | * If a new transaction has already done a buffer copy-out, then |
@@ -384,14 +394,6 @@ repeat: | |||
384 | kunmap_atomic(mapped_data, KM_USER0); | 394 | kunmap_atomic(mapped_data, KM_USER0); |
385 | } | 395 | } |
386 | 396 | ||
387 | /* keep subsequent assertions sane */ | ||
388 | new_bh->b_state = 0; | ||
389 | init_buffer(new_bh, NULL, NULL); | ||
390 | atomic_set(&new_bh->b_count, 1); | ||
391 | jbd_unlock_bh_state(bh_in); | ||
392 | |||
393 | new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */ | ||
394 | |||
395 | set_bh_page(new_bh, new_page, new_offset); | 397 | set_bh_page(new_bh, new_page, new_offset); |
396 | new_jh->b_transaction = NULL; | 398 | new_jh->b_transaction = NULL; |
397 | new_bh->b_size = jh2bh(jh_in)->b_size; | 399 | new_bh->b_size = jh2bh(jh_in)->b_size; |
@@ -408,7 +410,11 @@ repeat: | |||
408 | * copying is moved to the transaction's shadow queue. | 410 | * copying is moved to the transaction's shadow queue. |
409 | */ | 411 | */ |
410 | JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); | 412 | JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); |
411 | jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow); | 413 | spin_lock(&journal->j_list_lock); |
414 | __jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow); | ||
415 | spin_unlock(&journal->j_list_lock); | ||
416 | jbd_unlock_bh_state(bh_in); | ||
417 | |||
412 | JBUFFER_TRACE(new_jh, "file as BJ_IO"); | 418 | JBUFFER_TRACE(new_jh, "file as BJ_IO"); |
413 | jbd2_journal_file_buffer(new_jh, transaction, BJ_IO); | 419 | jbd2_journal_file_buffer(new_jh, transaction, BJ_IO); |
414 | 420 | ||
@@ -2377,6 +2383,72 @@ static void __exit journal_exit(void) | |||
2377 | jbd2_journal_destroy_caches(); | 2383 | jbd2_journal_destroy_caches(); |
2378 | } | 2384 | } |
2379 | 2385 | ||
2386 | /* | ||
2387 | * jbd2_dev_to_name is a utility function used by the jbd2 and ext4 | ||
2388 | * tracing infrastructure to map a dev_t to a device name. | ||
2389 | * | ||
2390 | * The caller should use rcu_read_lock() in order to make sure the | ||
2391 | * device name stays valid until its done with it. We use | ||
2392 | * rcu_read_lock() as well to make sure we're safe in case the caller | ||
2393 | * gets sloppy, and because rcu_read_lock() is cheap and can be safely | ||
2394 | * nested. | ||
2395 | */ | ||
2396 | struct devname_cache { | ||
2397 | struct rcu_head rcu; | ||
2398 | dev_t device; | ||
2399 | char devname[BDEVNAME_SIZE]; | ||
2400 | }; | ||
2401 | #define CACHE_SIZE_BITS 6 | ||
2402 | static struct devname_cache *devcache[1 << CACHE_SIZE_BITS]; | ||
2403 | static DEFINE_SPINLOCK(devname_cache_lock); | ||
2404 | |||
2405 | static void free_devcache(struct rcu_head *rcu) | ||
2406 | { | ||
2407 | kfree(rcu); | ||
2408 | } | ||
2409 | |||
2410 | const char *jbd2_dev_to_name(dev_t device) | ||
2411 | { | ||
2412 | int i = hash_32(device, CACHE_SIZE_BITS); | ||
2413 | char *ret; | ||
2414 | struct block_device *bd; | ||
2415 | static struct devname_cache *new_dev; | ||
2416 | |||
2417 | rcu_read_lock(); | ||
2418 | if (devcache[i] && devcache[i]->device == device) { | ||
2419 | ret = devcache[i]->devname; | ||
2420 | rcu_read_unlock(); | ||
2421 | return ret; | ||
2422 | } | ||
2423 | rcu_read_unlock(); | ||
2424 | |||
2425 | new_dev = kmalloc(sizeof(struct devname_cache), GFP_KERNEL); | ||
2426 | if (!new_dev) | ||
2427 | return "NODEV-ALLOCFAILURE"; /* Something non-NULL */ | ||
2428 | spin_lock(&devname_cache_lock); | ||
2429 | if (devcache[i]) { | ||
2430 | if (devcache[i]->device == device) { | ||
2431 | kfree(new_dev); | ||
2432 | ret = devcache[i]->devname; | ||
2433 | spin_unlock(&devname_cache_lock); | ||
2434 | return ret; | ||
2435 | } | ||
2436 | call_rcu(&devcache[i]->rcu, free_devcache); | ||
2437 | } | ||
2438 | devcache[i] = new_dev; | ||
2439 | devcache[i]->device = device; | ||
2440 | bd = bdget(device); | ||
2441 | if (bd) { | ||
2442 | bdevname(bd, devcache[i]->devname); | ||
2443 | bdput(bd); | ||
2444 | } else | ||
2445 | __bdevname(device, devcache[i]->devname); | ||
2446 | ret = devcache[i]->devname; | ||
2447 | spin_unlock(&devname_cache_lock); | ||
2448 | return ret; | ||
2449 | } | ||
2450 | EXPORT_SYMBOL(jbd2_dev_to_name); | ||
2451 | |||
2380 | MODULE_LICENSE("GPL"); | 2452 | MODULE_LICENSE("GPL"); |
2381 | module_init(journal_init); | 2453 | module_init(journal_init); |
2382 | module_exit(journal_exit); | 2454 | module_exit(journal_exit); |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 996ffda06bf3..6213ac728f30 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -499,34 +499,15 @@ void jbd2_journal_unlock_updates (journal_t *journal) | |||
499 | wake_up(&journal->j_wait_transaction_locked); | 499 | wake_up(&journal->j_wait_transaction_locked); |
500 | } | 500 | } |
501 | 501 | ||
502 | /* | 502 | static void warn_dirty_buffer(struct buffer_head *bh) |
503 | * Report any unexpected dirty buffers which turn up. Normally those | ||
504 | * indicate an error, but they can occur if the user is running (say) | ||
505 | * tune2fs to modify the live filesystem, so we need the option of | ||
506 | * continuing as gracefully as possible. # | ||
507 | * | ||
508 | * The caller should already hold the journal lock and | ||
509 | * j_list_lock spinlock: most callers will need those anyway | ||
510 | * in order to probe the buffer's journaling state safely. | ||
511 | */ | ||
512 | static void jbd_unexpected_dirty_buffer(struct journal_head *jh) | ||
513 | { | 503 | { |
514 | int jlist; | 504 | char b[BDEVNAME_SIZE]; |
515 | |||
516 | /* If this buffer is one which might reasonably be dirty | ||
517 | * --- ie. data, or not part of this journal --- then | ||
518 | * we're OK to leave it alone, but otherwise we need to | ||
519 | * move the dirty bit to the journal's own internal | ||
520 | * JBDDirty bit. */ | ||
521 | jlist = jh->b_jlist; | ||
522 | |||
523 | if (jlist == BJ_Metadata || jlist == BJ_Reserved || | ||
524 | jlist == BJ_Shadow || jlist == BJ_Forget) { | ||
525 | struct buffer_head *bh = jh2bh(jh); | ||
526 | 505 | ||
527 | if (test_clear_buffer_dirty(bh)) | 506 | printk(KERN_WARNING |
528 | set_buffer_jbddirty(bh); | 507 | "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). " |
529 | } | 508 | "There's a risk of filesystem corruption in case of system " |
509 | "crash.\n", | ||
510 | bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr); | ||
530 | } | 511 | } |
531 | 512 | ||
532 | /* | 513 | /* |
@@ -593,14 +574,16 @@ repeat: | |||
593 | if (jh->b_next_transaction) | 574 | if (jh->b_next_transaction) |
594 | J_ASSERT_JH(jh, jh->b_next_transaction == | 575 | J_ASSERT_JH(jh, jh->b_next_transaction == |
595 | transaction); | 576 | transaction); |
577 | warn_dirty_buffer(bh); | ||
596 | } | 578 | } |
597 | /* | 579 | /* |
598 | * In any case we need to clean the dirty flag and we must | 580 | * In any case we need to clean the dirty flag and we must |
599 | * do it under the buffer lock to be sure we don't race | 581 | * do it under the buffer lock to be sure we don't race |
600 | * with running write-out. | 582 | * with running write-out. |
601 | */ | 583 | */ |
602 | JBUFFER_TRACE(jh, "Unexpected dirty buffer"); | 584 | JBUFFER_TRACE(jh, "Journalling dirty buffer"); |
603 | jbd_unexpected_dirty_buffer(jh); | 585 | clear_buffer_dirty(bh); |
586 | set_buffer_jbddirty(bh); | ||
604 | } | 587 | } |
605 | 588 | ||
606 | unlock_buffer(bh); | 589 | unlock_buffer(bh); |
@@ -843,6 +826,15 @@ int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) | |||
843 | J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); | 826 | J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); |
844 | 827 | ||
845 | if (jh->b_transaction == NULL) { | 828 | if (jh->b_transaction == NULL) { |
829 | /* | ||
830 | * Previous jbd2_journal_forget() could have left the buffer | ||
831 | * with jbddirty bit set because it was being committed. When | ||
832 | * the commit finished, we've filed the buffer for | ||
833 | * checkpointing and marked it dirty. Now we are reallocating | ||
834 | * the buffer so the transaction freeing it must have | ||
835 | * committed and so it's safe to clear the dirty bit. | ||
836 | */ | ||
837 | clear_buffer_dirty(jh2bh(jh)); | ||
846 | jh->b_transaction = transaction; | 838 | jh->b_transaction = transaction; |
847 | 839 | ||
848 | /* first access by this transaction */ | 840 | /* first access by this transaction */ |
@@ -1547,36 +1539,6 @@ out: | |||
1547 | return; | 1539 | return; |
1548 | } | 1540 | } |
1549 | 1541 | ||
1550 | /* | ||
1551 | * jbd2_journal_try_to_free_buffers() could race with | ||
1552 | * jbd2_journal_commit_transaction(). The later might still hold the | ||
1553 | * reference count to the buffers when inspecting them on | ||
1554 | * t_syncdata_list or t_locked_list. | ||
1555 | * | ||
1556 | * jbd2_journal_try_to_free_buffers() will call this function to | ||
1557 | * wait for the current transaction to finish syncing data buffers, before | ||
1558 | * try to free that buffer. | ||
1559 | * | ||
1560 | * Called with journal->j_state_lock hold. | ||
1561 | */ | ||
1562 | static void jbd2_journal_wait_for_transaction_sync_data(journal_t *journal) | ||
1563 | { | ||
1564 | transaction_t *transaction; | ||
1565 | tid_t tid; | ||
1566 | |||
1567 | spin_lock(&journal->j_state_lock); | ||
1568 | transaction = journal->j_committing_transaction; | ||
1569 | |||
1570 | if (!transaction) { | ||
1571 | spin_unlock(&journal->j_state_lock); | ||
1572 | return; | ||
1573 | } | ||
1574 | |||
1575 | tid = transaction->t_tid; | ||
1576 | spin_unlock(&journal->j_state_lock); | ||
1577 | jbd2_log_wait_commit(journal, tid); | ||
1578 | } | ||
1579 | |||
1580 | /** | 1542 | /** |
1581 | * int jbd2_journal_try_to_free_buffers() - try to free page buffers. | 1543 | * int jbd2_journal_try_to_free_buffers() - try to free page buffers. |
1582 | * @journal: journal for operation | 1544 | * @journal: journal for operation |
@@ -1649,25 +1611,6 @@ int jbd2_journal_try_to_free_buffers(journal_t *journal, | |||
1649 | 1611 | ||
1650 | ret = try_to_free_buffers(page); | 1612 | ret = try_to_free_buffers(page); |
1651 | 1613 | ||
1652 | /* | ||
1653 | * There are a number of places where jbd2_journal_try_to_free_buffers() | ||
1654 | * could race with jbd2_journal_commit_transaction(), the later still | ||
1655 | * holds the reference to the buffers to free while processing them. | ||
1656 | * try_to_free_buffers() failed to free those buffers. Some of the | ||
1657 | * caller of releasepage() request page buffers to be dropped, otherwise | ||
1658 | * treat the fail-to-free as errors (such as generic_file_direct_IO()) | ||
1659 | * | ||
1660 | * So, if the caller of try_to_release_page() wants the synchronous | ||
1661 | * behaviour(i.e make sure buffers are dropped upon return), | ||
1662 | * let's wait for the current transaction to finish flush of | ||
1663 | * dirty data buffers, then try to free those buffers again, | ||
1664 | * with the journal locked. | ||
1665 | */ | ||
1666 | if (ret == 0 && (gfp_mask & __GFP_WAIT) && (gfp_mask & __GFP_FS)) { | ||
1667 | jbd2_journal_wait_for_transaction_sync_data(journal); | ||
1668 | ret = try_to_free_buffers(page); | ||
1669 | } | ||
1670 | |||
1671 | busy: | 1614 | busy: |
1672 | return ret; | 1615 | return ret; |
1673 | } | 1616 | } |
@@ -1693,8 +1636,13 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) | |||
1693 | 1636 | ||
1694 | if (jh->b_cp_transaction) { | 1637 | if (jh->b_cp_transaction) { |
1695 | JBUFFER_TRACE(jh, "on running+cp transaction"); | 1638 | JBUFFER_TRACE(jh, "on running+cp transaction"); |
1639 | /* | ||
1640 | * We don't want to write the buffer anymore, clear the | ||
1641 | * bit so that we don't confuse checks in | ||
1642 | * __journal_file_buffer | ||
1643 | */ | ||
1644 | clear_buffer_dirty(bh); | ||
1696 | __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); | 1645 | __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); |
1697 | clear_buffer_jbddirty(bh); | ||
1698 | may_free = 0; | 1646 | may_free = 0; |
1699 | } else { | 1647 | } else { |
1700 | JBUFFER_TRACE(jh, "on running transaction"); | 1648 | JBUFFER_TRACE(jh, "on running transaction"); |
@@ -1945,12 +1893,17 @@ void __jbd2_journal_file_buffer(struct journal_head *jh, | |||
1945 | if (jh->b_transaction && jh->b_jlist == jlist) | 1893 | if (jh->b_transaction && jh->b_jlist == jlist) |
1946 | return; | 1894 | return; |
1947 | 1895 | ||
1948 | /* The following list of buffer states needs to be consistent | ||
1949 | * with __jbd_unexpected_dirty_buffer()'s handling of dirty | ||
1950 | * state. */ | ||
1951 | |||
1952 | if (jlist == BJ_Metadata || jlist == BJ_Reserved || | 1896 | if (jlist == BJ_Metadata || jlist == BJ_Reserved || |
1953 | jlist == BJ_Shadow || jlist == BJ_Forget) { | 1897 | jlist == BJ_Shadow || jlist == BJ_Forget) { |
1898 | /* | ||
1899 | * For metadata buffers, we track dirty bit in buffer_jbddirty | ||
1900 | * instead of buffer_dirty. We should not see a dirty bit set | ||
1901 | * here because we clear it in do_get_write_access but e.g. | ||
1902 | * tune2fs can modify the sb and set the dirty bit at any time | ||
1903 | * so we try to gracefully handle that. | ||
1904 | */ | ||
1905 | if (buffer_dirty(bh)) | ||
1906 | warn_dirty_buffer(bh); | ||
1954 | if (test_clear_buffer_dirty(bh) || | 1907 | if (test_clear_buffer_dirty(bh) || |
1955 | test_clear_buffer_jbddirty(bh)) | 1908 | test_clear_buffer_jbddirty(bh)) |
1956 | was_dirty = 1; | 1909 | was_dirty = 1; |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 043740dde20c..8fcb6239218e 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
@@ -156,48 +156,25 @@ static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size) | |||
156 | return ERR_PTR(-EINVAL); | 156 | return ERR_PTR(-EINVAL); |
157 | } | 157 | } |
158 | 158 | ||
159 | static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl) | ||
160 | { | ||
161 | struct posix_acl *acl = JFFS2_ACL_NOT_CACHED; | ||
162 | |||
163 | spin_lock(&inode->i_lock); | ||
164 | if (*i_acl != JFFS2_ACL_NOT_CACHED) | ||
165 | acl = posix_acl_dup(*i_acl); | ||
166 | spin_unlock(&inode->i_lock); | ||
167 | return acl; | ||
168 | } | ||
169 | |||
170 | static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl) | ||
171 | { | ||
172 | spin_lock(&inode->i_lock); | ||
173 | if (*i_acl != JFFS2_ACL_NOT_CACHED) | ||
174 | posix_acl_release(*i_acl); | ||
175 | *i_acl = posix_acl_dup(acl); | ||
176 | spin_unlock(&inode->i_lock); | ||
177 | } | ||
178 | |||
179 | static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | 159 | static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) |
180 | { | 160 | { |
181 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
182 | struct posix_acl *acl; | 161 | struct posix_acl *acl; |
183 | char *value = NULL; | 162 | char *value = NULL; |
184 | int rc, xprefix; | 163 | int rc, xprefix; |
185 | 164 | ||
165 | acl = get_cached_acl(inode, type); | ||
166 | if (acl != ACL_NOT_CACHED) | ||
167 | return acl; | ||
168 | |||
186 | switch (type) { | 169 | switch (type) { |
187 | case ACL_TYPE_ACCESS: | 170 | case ACL_TYPE_ACCESS: |
188 | acl = jffs2_iget_acl(inode, &f->i_acl_access); | ||
189 | if (acl != JFFS2_ACL_NOT_CACHED) | ||
190 | return acl; | ||
191 | xprefix = JFFS2_XPREFIX_ACL_ACCESS; | 171 | xprefix = JFFS2_XPREFIX_ACL_ACCESS; |
192 | break; | 172 | break; |
193 | case ACL_TYPE_DEFAULT: | 173 | case ACL_TYPE_DEFAULT: |
194 | acl = jffs2_iget_acl(inode, &f->i_acl_default); | ||
195 | if (acl != JFFS2_ACL_NOT_CACHED) | ||
196 | return acl; | ||
197 | xprefix = JFFS2_XPREFIX_ACL_DEFAULT; | 174 | xprefix = JFFS2_XPREFIX_ACL_DEFAULT; |
198 | break; | 175 | break; |
199 | default: | 176 | default: |
200 | return ERR_PTR(-EINVAL); | 177 | BUG(); |
201 | } | 178 | } |
202 | rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); | 179 | rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0); |
203 | if (rc > 0) { | 180 | if (rc > 0) { |
@@ -215,16 +192,8 @@ static struct posix_acl *jffs2_get_acl(struct inode *inode, int type) | |||
215 | } | 192 | } |
216 | if (value) | 193 | if (value) |
217 | kfree(value); | 194 | kfree(value); |
218 | if (!IS_ERR(acl)) { | 195 | if (!IS_ERR(acl)) |
219 | switch (type) { | 196 | set_cached_acl(inode, type, acl); |
220 | case ACL_TYPE_ACCESS: | ||
221 | jffs2_iset_acl(inode, &f->i_acl_access, acl); | ||
222 | break; | ||
223 | case ACL_TYPE_DEFAULT: | ||
224 | jffs2_iset_acl(inode, &f->i_acl_default, acl); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | return acl; | 197 | return acl; |
229 | } | 198 | } |
230 | 199 | ||
@@ -249,7 +218,6 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a | |||
249 | 218 | ||
250 | static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 219 | static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) |
251 | { | 220 | { |
252 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
253 | int rc, xprefix; | 221 | int rc, xprefix; |
254 | 222 | ||
255 | if (S_ISLNK(inode->i_mode)) | 223 | if (S_ISLNK(inode->i_mode)) |
@@ -285,16 +253,8 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
285 | return -EINVAL; | 253 | return -EINVAL; |
286 | } | 254 | } |
287 | rc = __jffs2_set_acl(inode, xprefix, acl); | 255 | rc = __jffs2_set_acl(inode, xprefix, acl); |
288 | if (!rc) { | 256 | if (!rc) |
289 | switch(type) { | 257 | set_cached_acl(inode, type, acl); |
290 | case ACL_TYPE_ACCESS: | ||
291 | jffs2_iset_acl(inode, &f->i_acl_access, acl); | ||
292 | break; | ||
293 | case ACL_TYPE_DEFAULT: | ||
294 | jffs2_iset_acl(inode, &f->i_acl_default, acl); | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | return rc; | 258 | return rc; |
299 | } | 259 | } |
300 | 260 | ||
@@ -321,12 +281,10 @@ int jffs2_permission(struct inode *inode, int mask) | |||
321 | 281 | ||
322 | int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | 282 | int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) |
323 | { | 283 | { |
324 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
325 | struct posix_acl *acl, *clone; | 284 | struct posix_acl *acl, *clone; |
326 | int rc; | 285 | int rc; |
327 | 286 | ||
328 | f->i_acl_default = NULL; | 287 | cache_no_acl(inode); |
329 | f->i_acl_access = NULL; | ||
330 | 288 | ||
331 | if (S_ISLNK(*i_mode)) | 289 | if (S_ISLNK(*i_mode)) |
332 | return 0; /* Symlink always has no-ACL */ | 290 | return 0; /* Symlink always has no-ACL */ |
@@ -339,7 +297,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
339 | *i_mode &= ~current_umask(); | 297 | *i_mode &= ~current_umask(); |
340 | } else { | 298 | } else { |
341 | if (S_ISDIR(*i_mode)) | 299 | if (S_ISDIR(*i_mode)) |
342 | jffs2_iset_acl(inode, &f->i_acl_default, acl); | 300 | set_cached_acl(inode, ACL_TYPE_DEFAULT, acl); |
343 | 301 | ||
344 | clone = posix_acl_clone(acl, GFP_KERNEL); | 302 | clone = posix_acl_clone(acl, GFP_KERNEL); |
345 | if (!clone) | 303 | if (!clone) |
@@ -350,7 +308,7 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
350 | return rc; | 308 | return rc; |
351 | } | 309 | } |
352 | if (rc > 0) | 310 | if (rc > 0) |
353 | jffs2_iset_acl(inode, &f->i_acl_access, clone); | 311 | set_cached_acl(inode, ACL_TYPE_ACCESS, clone); |
354 | 312 | ||
355 | posix_acl_release(clone); | 313 | posix_acl_release(clone); |
356 | } | 314 | } |
@@ -359,17 +317,16 @@ int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode) | |||
359 | 317 | ||
360 | int jffs2_init_acl_post(struct inode *inode) | 318 | int jffs2_init_acl_post(struct inode *inode) |
361 | { | 319 | { |
362 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | ||
363 | int rc; | 320 | int rc; |
364 | 321 | ||
365 | if (f->i_acl_default) { | 322 | if (inode->i_default_acl) { |
366 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, f->i_acl_default); | 323 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl); |
367 | if (rc) | 324 | if (rc) |
368 | return rc; | 325 | return rc; |
369 | } | 326 | } |
370 | 327 | ||
371 | if (f->i_acl_access) { | 328 | if (inode->i_acl) { |
372 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, f->i_acl_access); | 329 | rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl); |
373 | if (rc) | 330 | if (rc) |
374 | return rc; | 331 | return rc; |
375 | } | 332 | } |
@@ -377,18 +334,6 @@ int jffs2_init_acl_post(struct inode *inode) | |||
377 | return 0; | 334 | return 0; |
378 | } | 335 | } |
379 | 336 | ||
380 | void jffs2_clear_acl(struct jffs2_inode_info *f) | ||
381 | { | ||
382 | if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) { | ||
383 | posix_acl_release(f->i_acl_access); | ||
384 | f->i_acl_access = JFFS2_ACL_NOT_CACHED; | ||
385 | } | ||
386 | if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) { | ||
387 | posix_acl_release(f->i_acl_default); | ||
388 | f->i_acl_default = JFFS2_ACL_NOT_CACHED; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | int jffs2_acl_chmod(struct inode *inode) | 337 | int jffs2_acl_chmod(struct inode *inode) |
393 | { | 338 | { |
394 | struct posix_acl *acl, *clone; | 339 | struct posix_acl *acl, *clone; |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 8ca058aed384..fc929f2a14f6 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
@@ -26,13 +26,10 @@ struct jffs2_acl_header { | |||
26 | 26 | ||
27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | 27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
28 | 28 | ||
29 | #define JFFS2_ACL_NOT_CACHED ((void *)-1) | ||
30 | |||
31 | extern int jffs2_permission(struct inode *, int); | 29 | extern int jffs2_permission(struct inode *, int); |
32 | extern int jffs2_acl_chmod(struct inode *); | 30 | extern int jffs2_acl_chmod(struct inode *); |
33 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); | 31 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); |
34 | extern int jffs2_init_acl_post(struct inode *); | 32 | extern int jffs2_init_acl_post(struct inode *); |
35 | extern void jffs2_clear_acl(struct jffs2_inode_info *); | ||
36 | 33 | ||
37 | extern struct xattr_handler jffs2_acl_access_xattr_handler; | 34 | extern struct xattr_handler jffs2_acl_access_xattr_handler; |
38 | extern struct xattr_handler jffs2_acl_default_xattr_handler; | 35 | extern struct xattr_handler jffs2_acl_default_xattr_handler; |
@@ -43,6 +40,5 @@ extern struct xattr_handler jffs2_acl_default_xattr_handler; | |||
43 | #define jffs2_acl_chmod(inode) (0) | 40 | #define jffs2_acl_chmod(inode) (0) |
44 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) | 41 | #define jffs2_init_acl_pre(dir_i,inode,mode) (0) |
45 | #define jffs2_init_acl_post(inode) (0) | 42 | #define jffs2_init_acl_post(inode) (0) |
46 | #define jffs2_clear_acl(f) | ||
47 | 43 | ||
48 | #endif /* CONFIG_JFFS2_FS_POSIX_ACL */ | 44 | #endif /* CONFIG_JFFS2_FS_POSIX_ACL */ |
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a0244740b75a..b47679be118a 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
@@ -270,19 +270,21 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, | |||
270 | D2({ | 270 | D2({ |
271 | int i=0; | 271 | int i=0; |
272 | struct jffs2_raw_node_ref *this; | 272 | struct jffs2_raw_node_ref *this; |
273 | printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); | 273 | printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n"); |
274 | 274 | ||
275 | this = ic->nodes; | 275 | this = ic->nodes; |
276 | 276 | ||
277 | printk(KERN_DEBUG); | ||
277 | while(this) { | 278 | while(this) { |
278 | printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); | 279 | printk(KERN_CONT "0x%08x(%d)->", |
280 | ref_offset(this), ref_flags(this)); | ||
279 | if (++i == 5) { | 281 | if (++i == 5) { |
280 | printk("\n" KERN_DEBUG); | 282 | printk(KERN_DEBUG); |
281 | i=0; | 283 | i=0; |
282 | } | 284 | } |
283 | this = this->next_in_ino; | 285 | this = this->next_in_ino; |
284 | } | 286 | } |
285 | printk("\n"); | 287 | printk(KERN_CONT "\n"); |
286 | }); | 288 | }); |
287 | 289 | ||
288 | switch (ic->class) { | 290 | switch (ic->class) { |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 5edc2bf20581..23c947539864 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
@@ -99,7 +99,7 @@ static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) | |||
99 | kunmap(pg); | 99 | kunmap(pg); |
100 | 100 | ||
101 | D2(printk(KERN_DEBUG "readpage finished\n")); | 101 | D2(printk(KERN_DEBUG "readpage finished\n")); |
102 | return 0; | 102 | return ret; |
103 | } | 103 | } |
104 | 104 | ||
105 | int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) | 105 | int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index 4c41db91eaa4..c6923da98263 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
@@ -50,10 +50,6 @@ struct jffs2_inode_info { | |||
50 | uint16_t flags; | 50 | uint16_t flags; |
51 | uint8_t usercompr; | 51 | uint8_t usercompr; |
52 | struct inode vfs_inode; | 52 | struct inode vfs_inode; |
53 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | ||
54 | struct posix_acl *i_acl_access; | ||
55 | struct posix_acl *i_acl_default; | ||
56 | #endif | ||
57 | }; | 53 | }; |
58 | 54 | ||
59 | #endif /* _JFFS2_FS_I */ | 55 | #endif /* _JFFS2_FS_I */ |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 2228380c47b9..a7f03b7ebcb3 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
@@ -56,10 +56,6 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) | |||
56 | f->target = NULL; | 56 | f->target = NULL; |
57 | f->flags = 0; | 57 | f->flags = 0; |
58 | f->usercompr = 0; | 58 | f->usercompr = 0; |
59 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | ||
60 | f->i_acl_access = JFFS2_ACL_NOT_CACHED; | ||
61 | f->i_acl_default = JFFS2_ACL_NOT_CACHED; | ||
62 | #endif | ||
63 | } | 59 | } |
64 | 60 | ||
65 | 61 | ||
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 1fc1e92356ee..1a80301004b8 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -1424,7 +1424,6 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
1424 | struct jffs2_full_dirent *fd, *fds; | 1424 | struct jffs2_full_dirent *fd, *fds; |
1425 | int deleted; | 1425 | int deleted; |
1426 | 1426 | ||
1427 | jffs2_clear_acl(f); | ||
1428 | jffs2_xattr_delete_inode(c, f->inocache); | 1427 | jffs2_xattr_delete_inode(c, f->inocache); |
1429 | mutex_lock(&f->sem); | 1428 | mutex_lock(&f->sem); |
1430 | deleted = f->inocache && !f->inocache->pino_nlink; | 1429 | deleted = f->inocache && !f->inocache->pino_nlink; |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 1d437de1e9a8..696686cc206e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -130,9 +130,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
130 | if (jffs2_sum_active()) { | 130 | if (jffs2_sum_active()) { |
131 | s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); | 131 | s = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL); |
132 | if (!s) { | 132 | if (!s) { |
133 | kfree(flashbuf); | ||
134 | JFFS2_WARNING("Can't allocate memory for summary\n"); | 133 | JFFS2_WARNING("Can't allocate memory for summary\n"); |
135 | return -ENOMEM; | 134 | ret = -ENOMEM; |
135 | goto out; | ||
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
@@ -196,7 +196,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
196 | if (c->nextblock) { | 196 | if (c->nextblock) { |
197 | ret = file_dirty(c, c->nextblock); | 197 | ret = file_dirty(c, c->nextblock); |
198 | if (ret) | 198 | if (ret) |
199 | return ret; | 199 | goto out; |
200 | /* deleting summary information of the old nextblock */ | 200 | /* deleting summary information of the old nextblock */ |
201 | jffs2_sum_reset_collected(c->summary); | 201 | jffs2_sum_reset_collected(c->summary); |
202 | } | 202 | } |
@@ -207,7 +207,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) | |||
207 | } else { | 207 | } else { |
208 | ret = file_dirty(c, jeb); | 208 | ret = file_dirty(c, jeb); |
209 | if (ret) | 209 | if (ret) |
210 | return ret; | 210 | goto out; |
211 | } | 211 | } |
212 | break; | 212 | break; |
213 | 213 | ||
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 07a22caf2687..0035c021395a 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/smp_lock.h> | ||
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/list.h> | 17 | #include <linux/list.h> |
17 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 06ca1b8d2054..a29c7c3e3fb8 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
@@ -31,27 +31,24 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
31 | { | 31 | { |
32 | struct posix_acl *acl; | 32 | struct posix_acl *acl; |
33 | char *ea_name; | 33 | char *ea_name; |
34 | struct jfs_inode_info *ji = JFS_IP(inode); | ||
35 | struct posix_acl **p_acl; | ||
36 | int size; | 34 | int size; |
37 | char *value = NULL; | 35 | char *value = NULL; |
38 | 36 | ||
37 | acl = get_cached_acl(inode, type); | ||
38 | if (acl != ACL_NOT_CACHED) | ||
39 | return acl; | ||
40 | |||
39 | switch(type) { | 41 | switch(type) { |
40 | case ACL_TYPE_ACCESS: | 42 | case ACL_TYPE_ACCESS: |
41 | ea_name = POSIX_ACL_XATTR_ACCESS; | 43 | ea_name = POSIX_ACL_XATTR_ACCESS; |
42 | p_acl = &ji->i_acl; | ||
43 | break; | 44 | break; |
44 | case ACL_TYPE_DEFAULT: | 45 | case ACL_TYPE_DEFAULT: |
45 | ea_name = POSIX_ACL_XATTR_DEFAULT; | 46 | ea_name = POSIX_ACL_XATTR_DEFAULT; |
46 | p_acl = &ji->i_default_acl; | ||
47 | break; | 47 | break; |
48 | default: | 48 | default: |
49 | return ERR_PTR(-EINVAL); | 49 | return ERR_PTR(-EINVAL); |
50 | } | 50 | } |
51 | 51 | ||
52 | if (*p_acl != JFS_ACL_NOT_CACHED) | ||
53 | return posix_acl_dup(*p_acl); | ||
54 | |||
55 | size = __jfs_getxattr(inode, ea_name, NULL, 0); | 52 | size = __jfs_getxattr(inode, ea_name, NULL, 0); |
56 | 53 | ||
57 | if (size > 0) { | 54 | if (size > 0) { |
@@ -62,17 +59,16 @@ static struct posix_acl *jfs_get_acl(struct inode *inode, int type) | |||
62 | } | 59 | } |
63 | 60 | ||
64 | if (size < 0) { | 61 | if (size < 0) { |
65 | if (size == -ENODATA) { | 62 | if (size == -ENODATA) |
66 | *p_acl = NULL; | ||
67 | acl = NULL; | 63 | acl = NULL; |
68 | } else | 64 | else |
69 | acl = ERR_PTR(size); | 65 | acl = ERR_PTR(size); |
70 | } else { | 66 | } else { |
71 | acl = posix_acl_from_xattr(value, size); | 67 | acl = posix_acl_from_xattr(value, size); |
72 | if (!IS_ERR(acl)) | ||
73 | *p_acl = posix_acl_dup(acl); | ||
74 | } | 68 | } |
75 | kfree(value); | 69 | kfree(value); |
70 | if (!IS_ERR(acl)) | ||
71 | set_cached_acl(inode, type, acl); | ||
76 | return acl; | 72 | return acl; |
77 | } | 73 | } |
78 | 74 | ||
@@ -80,8 +76,6 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, | |||
80 | struct posix_acl *acl) | 76 | struct posix_acl *acl) |
81 | { | 77 | { |
82 | char *ea_name; | 78 | char *ea_name; |
83 | struct jfs_inode_info *ji = JFS_IP(inode); | ||
84 | struct posix_acl **p_acl; | ||
85 | int rc; | 79 | int rc; |
86 | int size = 0; | 80 | int size = 0; |
87 | char *value = NULL; | 81 | char *value = NULL; |
@@ -92,11 +86,9 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, | |||
92 | switch(type) { | 86 | switch(type) { |
93 | case ACL_TYPE_ACCESS: | 87 | case ACL_TYPE_ACCESS: |
94 | ea_name = POSIX_ACL_XATTR_ACCESS; | 88 | ea_name = POSIX_ACL_XATTR_ACCESS; |
95 | p_acl = &ji->i_acl; | ||
96 | break; | 89 | break; |
97 | case ACL_TYPE_DEFAULT: | 90 | case ACL_TYPE_DEFAULT: |
98 | ea_name = POSIX_ACL_XATTR_DEFAULT; | 91 | ea_name = POSIX_ACL_XATTR_DEFAULT; |
99 | p_acl = &ji->i_default_acl; | ||
100 | if (!S_ISDIR(inode->i_mode)) | 92 | if (!S_ISDIR(inode->i_mode)) |
101 | return acl ? -EACCES : 0; | 93 | return acl ? -EACCES : 0; |
102 | break; | 94 | break; |
@@ -116,27 +108,24 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type, | |||
116 | out: | 108 | out: |
117 | kfree(value); | 109 | kfree(value); |
118 | 110 | ||
119 | if (!rc) { | 111 | if (!rc) |
120 | if (*p_acl && (*p_acl != JFS_ACL_NOT_CACHED)) | 112 | set_cached_acl(inode, type, acl); |
121 | posix_acl_release(*p_acl); | 113 | |
122 | *p_acl = posix_acl_dup(acl); | ||
123 | } | ||
124 | return rc; | 114 | return rc; |
125 | } | 115 | } |
126 | 116 | ||
127 | static int jfs_check_acl(struct inode *inode, int mask) | 117 | static int jfs_check_acl(struct inode *inode, int mask) |
128 | { | 118 | { |
129 | struct jfs_inode_info *ji = JFS_IP(inode); | 119 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); |
130 | 120 | ||
131 | if (ji->i_acl == JFS_ACL_NOT_CACHED) { | 121 | if (IS_ERR(acl)) |
132 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); | 122 | return PTR_ERR(acl); |
133 | if (IS_ERR(acl)) | 123 | if (acl) { |
134 | return PTR_ERR(acl); | 124 | int error = posix_acl_permission(inode, acl, mask); |
135 | posix_acl_release(acl); | 125 | posix_acl_release(acl); |
126 | return error; | ||
136 | } | 127 | } |
137 | 128 | ||
138 | if (ji->i_acl) | ||
139 | return posix_acl_permission(inode, ji->i_acl, mask); | ||
140 | return -EAGAIN; | 129 | return -EAGAIN; |
141 | } | 130 | } |
142 | 131 | ||
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c index bbbd5f202e37..41d6045dbeb0 100644 --- a/fs/jfs/jfs_extent.c +++ b/fs/jfs/jfs_extent.c | |||
@@ -391,6 +391,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp) | |||
391 | } | 391 | } |
392 | XADaddress(xp, xaddr); | 392 | XADaddress(xp, xaddr); |
393 | XADlength(xp, xlen); | 393 | XADlength(xp, xlen); |
394 | XADoffset(xp, prev); | ||
394 | /* | 395 | /* |
395 | * only preserve the abnr flag within the xad flags | 396 | * only preserve the abnr flag within the xad flags |
396 | * of the returned hint. | 397 | * of the returned hint. |
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index 439901d205fe..1439f119ec83 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h | |||
@@ -74,10 +74,6 @@ struct jfs_inode_info { | |||
74 | /* xattr_sem allows us to access the xattrs without taking i_mutex */ | 74 | /* xattr_sem allows us to access the xattrs without taking i_mutex */ |
75 | struct rw_semaphore xattr_sem; | 75 | struct rw_semaphore xattr_sem; |
76 | lid_t xtlid; /* lid of xtree lock on directory */ | 76 | lid_t xtlid; /* lid of xtree lock on directory */ |
77 | #ifdef CONFIG_JFS_POSIX_ACL | ||
78 | struct posix_acl *i_acl; | ||
79 | struct posix_acl *i_default_acl; | ||
80 | #endif | ||
81 | union { | 77 | union { |
82 | struct { | 78 | struct { |
83 | xtpage_t _xtroot; /* 288: xtree root */ | 79 | xtpage_t _xtroot; /* 288: xtree root */ |
@@ -107,8 +103,6 @@ struct jfs_inode_info { | |||
107 | #define i_inline u.link._inline | 103 | #define i_inline u.link._inline |
108 | #define i_inline_ea u.link._inline_ea | 104 | #define i_inline_ea u.link._inline_ea |
109 | 105 | ||
110 | #define JFS_ACL_NOT_CACHED ((void *)-1) | ||
111 | |||
112 | #define IREAD_LOCK(ip, subclass) \ | 106 | #define IREAD_LOCK(ip, subclass) \ |
113 | down_read_nested(&JFS_IP(ip)->rdwrlock, subclass) | 107 | down_read_nested(&JFS_IP(ip)->rdwrlock, subclass) |
114 | #define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) | 108 | #define IREAD_UNLOCK(ip) up_read(&JFS_IP(ip)->rdwrlock) |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 09b1b6ee2186..37e6dcda8fc8 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -128,18 +128,6 @@ static void jfs_destroy_inode(struct inode *inode) | |||
128 | ji->active_ag = -1; | 128 | ji->active_ag = -1; |
129 | } | 129 | } |
130 | spin_unlock_irq(&ji->ag_lock); | 130 | spin_unlock_irq(&ji->ag_lock); |
131 | |||
132 | #ifdef CONFIG_JFS_POSIX_ACL | ||
133 | if (ji->i_acl != JFS_ACL_NOT_CACHED) { | ||
134 | posix_acl_release(ji->i_acl); | ||
135 | ji->i_acl = JFS_ACL_NOT_CACHED; | ||
136 | } | ||
137 | if (ji->i_default_acl != JFS_ACL_NOT_CACHED) { | ||
138 | posix_acl_release(ji->i_default_acl); | ||
139 | ji->i_default_acl = JFS_ACL_NOT_CACHED; | ||
140 | } | ||
141 | #endif | ||
142 | |||
143 | kmem_cache_free(jfs_inode_cachep, ji); | 131 | kmem_cache_free(jfs_inode_cachep, ji); |
144 | } | 132 | } |
145 | 133 | ||
@@ -798,10 +786,6 @@ static void init_once(void *foo) | |||
798 | init_rwsem(&jfs_ip->xattr_sem); | 786 | init_rwsem(&jfs_ip->xattr_sem); |
799 | spin_lock_init(&jfs_ip->ag_lock); | 787 | spin_lock_init(&jfs_ip->ag_lock); |
800 | jfs_ip->active_ag = -1; | 788 | jfs_ip->active_ag = -1; |
801 | #ifdef CONFIG_JFS_POSIX_ACL | ||
802 | jfs_ip->i_acl = JFS_ACL_NOT_CACHED; | ||
803 | jfs_ip->i_default_acl = JFS_ACL_NOT_CACHED; | ||
804 | #endif | ||
805 | inode_init_once(&jfs_ip->vfs_inode); | 789 | inode_init_once(&jfs_ip->vfs_inode); |
806 | } | 790 | } |
807 | 791 | ||
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index 61dfa8173ebc..fad364548bc9 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c | |||
@@ -727,10 +727,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
727 | /* | 727 | /* |
728 | * We're changing the ACL. Get rid of the cached one | 728 | * We're changing the ACL. Get rid of the cached one |
729 | */ | 729 | */ |
730 | acl =JFS_IP(inode)->i_acl; | 730 | forget_cached_acl(inode, ACL_TYPE_ACCESS); |
731 | if (acl != JFS_ACL_NOT_CACHED) | ||
732 | posix_acl_release(acl); | ||
733 | JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED; | ||
734 | 731 | ||
735 | return 0; | 732 | return 0; |
736 | } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { | 733 | } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) { |
@@ -746,10 +743,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
746 | /* | 743 | /* |
747 | * We're changing the default ACL. Get rid of the cached one | 744 | * We're changing the default ACL. Get rid of the cached one |
748 | */ | 745 | */ |
749 | acl =JFS_IP(inode)->i_default_acl; | 746 | forget_cached_acl(inode, ACL_TYPE_DEFAULT); |
750 | if (acl && (acl != JFS_ACL_NOT_CACHED)) | ||
751 | posix_acl_release(acl); | ||
752 | JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED; | ||
753 | 747 | ||
754 | return 0; | 748 | return 0; |
755 | } | 749 | } |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index dd7957064a8c..4336adba952a 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/smp_lock.h> | ||
10 | #include <linux/types.h> | 11 | #include <linux/types.h> |
11 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
12 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
@@ -126,7 +127,6 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) | |||
126 | struct nlm_lock *lock = &argp->lock; | 127 | struct nlm_lock *lock = &argp->lock; |
127 | 128 | ||
128 | nlmclnt_next_cookie(&argp->cookie); | 129 | nlmclnt_next_cookie(&argp->cookie); |
129 | argp->state = nsm_local_state; | ||
130 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); | 130 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_path.dentry->d_inode), sizeof(struct nfs_fh)); |
131 | lock->caller = utsname()->nodename; | 131 | lock->caller = utsname()->nodename; |
132 | lock->oh.data = req->a_owner; | 132 | lock->oh.data = req->a_owner; |
@@ -165,6 +165,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
165 | /* Set up the argument struct */ | 165 | /* Set up the argument struct */ |
166 | nlmclnt_setlockargs(call, fl); | 166 | nlmclnt_setlockargs(call, fl); |
167 | 167 | ||
168 | lock_kernel(); | ||
168 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 169 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
169 | if (fl->fl_type != F_UNLCK) { | 170 | if (fl->fl_type != F_UNLCK) { |
170 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 171 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -178,6 +179,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
178 | 179 | ||
179 | fl->fl_ops->fl_release_private(fl); | 180 | fl->fl_ops->fl_release_private(fl); |
180 | fl->fl_ops = NULL; | 181 | fl->fl_ops = NULL; |
182 | unlock_kernel(); | ||
181 | 183 | ||
182 | dprintk("lockd: clnt proc returns %d\n", status); | 184 | dprintk("lockd: clnt proc returns %d\n", status); |
183 | return status; | 185 | return status; |
@@ -519,6 +521,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
519 | 521 | ||
520 | if (nsm_monitor(host) < 0) | 522 | if (nsm_monitor(host) < 0) |
521 | goto out; | 523 | goto out; |
524 | req->a_args.state = nsm_local_state; | ||
522 | 525 | ||
523 | fl->fl_flags |= FL_ACCESS; | 526 | fl->fl_flags |= FL_ACCESS; |
524 | status = do_vfs_lock(fl); | 527 | status = do_vfs_lock(fl); |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 6d5d4a4169e5..7fce1b525849 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -53,7 +53,7 @@ static DEFINE_SPINLOCK(nsm_lock); | |||
53 | /* | 53 | /* |
54 | * Local NSM state | 54 | * Local NSM state |
55 | */ | 55 | */ |
56 | int __read_mostly nsm_local_state; | 56 | u32 __read_mostly nsm_local_state; |
57 | int __read_mostly nsm_use_hostnames; | 57 | int __read_mostly nsm_use_hostnames; |
58 | 58 | ||
59 | static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) | 59 | static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm) |
@@ -112,6 +112,7 @@ static struct rpc_clnt *nsm_create(void) | |||
112 | .program = &nsm_program, | 112 | .program = &nsm_program, |
113 | .version = NSM_VERSION, | 113 | .version = NSM_VERSION, |
114 | .authflavor = RPC_AUTH_NULL, | 114 | .authflavor = RPC_AUTH_NULL, |
115 | .flags = RPC_CLNT_CREATE_NOPING, | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | return rpc_create(&args); | 118 | return rpc_create(&args); |
@@ -184,13 +185,19 @@ int nsm_monitor(const struct nlm_host *host) | |||
184 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | 185 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; |
185 | 186 | ||
186 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); | 187 | status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); |
187 | if (res.status != 0) | 188 | if (unlikely(res.status != 0)) |
188 | status = -EIO; | 189 | status = -EIO; |
189 | if (status < 0) | 190 | if (unlikely(status < 0)) { |
190 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); | 191 | printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name); |
191 | else | 192 | return status; |
192 | nsm->sm_monitored = 1; | 193 | } |
193 | return status; | 194 | |
195 | nsm->sm_monitored = 1; | ||
196 | if (unlikely(nsm_local_state != res.state)) { | ||
197 | nsm_local_state = res.state; | ||
198 | dprintk("lockd: NSM state changed to %d\n", nsm_local_state); | ||
199 | } | ||
200 | return 0; | ||
194 | } | 201 | } |
195 | 202 | ||
196 | /** | 203 | /** |
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 1725037374c5..bd173a6ca3b1 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <linux/time.h> | 11 | #include <linux/time.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/smp_lock.h> | ||
13 | #include <linux/in.h> | 14 | #include <linux/in.h> |
14 | #include <linux/sunrpc/svc.h> | 15 | #include <linux/sunrpc/svc.h> |
15 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 83ee34203bd7..e577a78d7bac 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -326,6 +326,8 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call) | |||
326 | { | 326 | { |
327 | if (call->a_args.lock.oh.data != call->a_owner) | 327 | if (call->a_args.lock.oh.data != call->a_owner) |
328 | kfree(call->a_args.lock.oh.data); | 328 | kfree(call->a_args.lock.oh.data); |
329 | |||
330 | locks_release_private(&call->a_args.lock.fl); | ||
329 | } | 331 | } |
330 | 332 | ||
331 | /* | 333 | /* |
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 3688e55901fc..e1d28ddd2169 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <linux/time.h> | 11 | #include <linux/time.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/smp_lock.h> | ||
13 | #include <linux/in.h> | 14 | #include <linux/in.h> |
14 | #include <linux/sunrpc/svc.h> | 15 | #include <linux/sunrpc/svc.h> |
15 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
diff --git a/fs/locks.c b/fs/locks.c index ec3deea29e37..b6440f52178f 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -151,7 +151,7 @@ static struct file_lock *locks_alloc_lock(void) | |||
151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); | 151 | return kmem_cache_alloc(filelock_cache, GFP_KERNEL); |
152 | } | 152 | } |
153 | 153 | ||
154 | static void locks_release_private(struct file_lock *fl) | 154 | void locks_release_private(struct file_lock *fl) |
155 | { | 155 | { |
156 | if (fl->fl_ops) { | 156 | if (fl->fl_ops) { |
157 | if (fl->fl_ops->fl_release_private) | 157 | if (fl->fl_ops->fl_release_private) |
@@ -165,6 +165,7 @@ static void locks_release_private(struct file_lock *fl) | |||
165 | } | 165 | } |
166 | 166 | ||
167 | } | 167 | } |
168 | EXPORT_SYMBOL_GPL(locks_release_private); | ||
168 | 169 | ||
169 | /* Free a lock which is not in use. */ | 170 | /* Free a lock which is not in use. */ |
170 | static void locks_free_lock(struct file_lock *fl) | 171 | static void locks_free_lock(struct file_lock *fl) |
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index 3aebe322271a..6ac693faae49 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c | |||
@@ -12,13 +12,14 @@ | |||
12 | /* bitmap.c contains the code that handles the inode and block bitmaps */ | 12 | /* bitmap.c contains the code that handles the inode and block bitmaps */ |
13 | 13 | ||
14 | #include "minix.h" | 14 | #include "minix.h" |
15 | #include <linux/smp_lock.h> | ||
16 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
17 | #include <linux/bitops.h> | 16 | #include <linux/bitops.h> |
18 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
19 | 18 | ||
20 | static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 }; | 19 | static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 }; |
21 | 20 | ||
21 | static DEFINE_SPINLOCK(bitmap_lock); | ||
22 | |||
22 | static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits) | 23 | static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits) |
23 | { | 24 | { |
24 | unsigned i, j, sum = 0; | 25 | unsigned i, j, sum = 0; |
@@ -69,11 +70,11 @@ void minix_free_block(struct inode *inode, unsigned long block) | |||
69 | return; | 70 | return; |
70 | } | 71 | } |
71 | bh = sbi->s_zmap[zone]; | 72 | bh = sbi->s_zmap[zone]; |
72 | lock_kernel(); | 73 | spin_lock(&bitmap_lock); |
73 | if (!minix_test_and_clear_bit(bit, bh->b_data)) | 74 | if (!minix_test_and_clear_bit(bit, bh->b_data)) |
74 | printk("minix_free_block (%s:%lu): bit already cleared\n", | 75 | printk("minix_free_block (%s:%lu): bit already cleared\n", |
75 | sb->s_id, block); | 76 | sb->s_id, block); |
76 | unlock_kernel(); | 77 | spin_unlock(&bitmap_lock); |
77 | mark_buffer_dirty(bh); | 78 | mark_buffer_dirty(bh); |
78 | return; | 79 | return; |
79 | } | 80 | } |
@@ -88,18 +89,18 @@ int minix_new_block(struct inode * inode) | |||
88 | struct buffer_head *bh = sbi->s_zmap[i]; | 89 | struct buffer_head *bh = sbi->s_zmap[i]; |
89 | int j; | 90 | int j; |
90 | 91 | ||
91 | lock_kernel(); | 92 | spin_lock(&bitmap_lock); |
92 | j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); | 93 | j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); |
93 | if (j < bits_per_zone) { | 94 | if (j < bits_per_zone) { |
94 | minix_set_bit(j, bh->b_data); | 95 | minix_set_bit(j, bh->b_data); |
95 | unlock_kernel(); | 96 | spin_unlock(&bitmap_lock); |
96 | mark_buffer_dirty(bh); | 97 | mark_buffer_dirty(bh); |
97 | j += i * bits_per_zone + sbi->s_firstdatazone-1; | 98 | j += i * bits_per_zone + sbi->s_firstdatazone-1; |
98 | if (j < sbi->s_firstdatazone || j >= sbi->s_nzones) | 99 | if (j < sbi->s_firstdatazone || j >= sbi->s_nzones) |
99 | break; | 100 | break; |
100 | return j; | 101 | return j; |
101 | } | 102 | } |
102 | unlock_kernel(); | 103 | spin_unlock(&bitmap_lock); |
103 | } | 104 | } |
104 | return 0; | 105 | return 0; |
105 | } | 106 | } |
@@ -211,10 +212,10 @@ void minix_free_inode(struct inode * inode) | |||
211 | minix_clear_inode(inode); /* clear on-disk copy */ | 212 | minix_clear_inode(inode); /* clear on-disk copy */ |
212 | 213 | ||
213 | bh = sbi->s_imap[ino]; | 214 | bh = sbi->s_imap[ino]; |
214 | lock_kernel(); | 215 | spin_lock(&bitmap_lock); |
215 | if (!minix_test_and_clear_bit(bit, bh->b_data)) | 216 | if (!minix_test_and_clear_bit(bit, bh->b_data)) |
216 | printk("minix_free_inode: bit %lu already cleared\n", bit); | 217 | printk("minix_free_inode: bit %lu already cleared\n", bit); |
217 | unlock_kernel(); | 218 | spin_unlock(&bitmap_lock); |
218 | mark_buffer_dirty(bh); | 219 | mark_buffer_dirty(bh); |
219 | out: | 220 | out: |
220 | clear_inode(inode); /* clear in-memory copy */ | 221 | clear_inode(inode); /* clear in-memory copy */ |
@@ -237,7 +238,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error) | |||
237 | j = bits_per_zone; | 238 | j = bits_per_zone; |
238 | bh = NULL; | 239 | bh = NULL; |
239 | *error = -ENOSPC; | 240 | *error = -ENOSPC; |
240 | lock_kernel(); | 241 | spin_lock(&bitmap_lock); |
241 | for (i = 0; i < sbi->s_imap_blocks; i++) { | 242 | for (i = 0; i < sbi->s_imap_blocks; i++) { |
242 | bh = sbi->s_imap[i]; | 243 | bh = sbi->s_imap[i]; |
243 | j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); | 244 | j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); |
@@ -245,17 +246,17 @@ struct inode * minix_new_inode(const struct inode * dir, int * error) | |||
245 | break; | 246 | break; |
246 | } | 247 | } |
247 | if (!bh || j >= bits_per_zone) { | 248 | if (!bh || j >= bits_per_zone) { |
248 | unlock_kernel(); | 249 | spin_unlock(&bitmap_lock); |
249 | iput(inode); | 250 | iput(inode); |
250 | return NULL; | 251 | return NULL; |
251 | } | 252 | } |
252 | if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */ | 253 | if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */ |
253 | unlock_kernel(); | 254 | spin_unlock(&bitmap_lock); |
254 | printk("minix_new_inode: bit already set\n"); | 255 | printk("minix_new_inode: bit already set\n"); |
255 | iput(inode); | 256 | iput(inode); |
256 | return NULL; | 257 | return NULL; |
257 | } | 258 | } |
258 | unlock_kernel(); | 259 | spin_unlock(&bitmap_lock); |
259 | mark_buffer_dirty(bh); | 260 | mark_buffer_dirty(bh); |
260 | j += i * bits_per_zone; | 261 | j += i * bits_per_zone; |
261 | if (!j || j > sbi->s_ninodes) { | 262 | if (!j || j > sbi->s_ninodes) { |
diff --git a/fs/minix/dir.c b/fs/minix/dir.c index e5f206467e40..d407e7a0b6fe 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c | |||
@@ -11,7 +11,6 @@ | |||
11 | #include "minix.h" | 11 | #include "minix.h" |
12 | #include <linux/buffer_head.h> | 12 | #include <linux/buffer_head.h> |
13 | #include <linux/highmem.h> | 13 | #include <linux/highmem.h> |
14 | #include <linux/smp_lock.h> | ||
15 | #include <linux/swap.h> | 14 | #include <linux/swap.h> |
16 | 15 | ||
17 | typedef struct minix_dir_entry minix_dirent; | 16 | typedef struct minix_dir_entry minix_dirent; |
@@ -20,6 +19,7 @@ typedef struct minix3_dir_entry minix3_dirent; | |||
20 | static int minix_readdir(struct file *, void *, filldir_t); | 19 | static int minix_readdir(struct file *, void *, filldir_t); |
21 | 20 | ||
22 | const struct file_operations minix_dir_operations = { | 21 | const struct file_operations minix_dir_operations = { |
22 | .llseek = generic_file_llseek, | ||
23 | .read = generic_read_dir, | 23 | .read = generic_read_dir, |
24 | .readdir = minix_readdir, | 24 | .readdir = minix_readdir, |
25 | .fsync = simple_fsync, | 25 | .fsync = simple_fsync, |
@@ -102,8 +102,6 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
102 | char *name; | 102 | char *name; |
103 | __u32 inumber; | 103 | __u32 inumber; |
104 | 104 | ||
105 | lock_kernel(); | ||
106 | |||
107 | pos = (pos + chunk_size-1) & ~(chunk_size-1); | 105 | pos = (pos + chunk_size-1) & ~(chunk_size-1); |
108 | if (pos >= inode->i_size) | 106 | if (pos >= inode->i_size) |
109 | goto done; | 107 | goto done; |
@@ -146,7 +144,6 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
146 | 144 | ||
147 | done: | 145 | done: |
148 | filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; | 146 | filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; |
149 | unlock_kernel(); | ||
150 | return 0; | 147 | return 0; |
151 | } | 148 | } |
152 | 149 | ||
diff --git a/fs/minix/inode.c b/fs/minix/inode.c index f91a23693597..74ea82d72164 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c | |||
@@ -35,8 +35,6 @@ static void minix_put_super(struct super_block *sb) | |||
35 | int i; | 35 | int i; |
36 | struct minix_sb_info *sbi = minix_sb(sb); | 36 | struct minix_sb_info *sbi = minix_sb(sb); |
37 | 37 | ||
38 | lock_kernel(); | ||
39 | |||
40 | if (!(sb->s_flags & MS_RDONLY)) { | 38 | if (!(sb->s_flags & MS_RDONLY)) { |
41 | if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ | 39 | if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ |
42 | sbi->s_ms->s_state = sbi->s_mount_state; | 40 | sbi->s_ms->s_state = sbi->s_mount_state; |
@@ -50,8 +48,6 @@ static void minix_put_super(struct super_block *sb) | |||
50 | kfree(sbi->s_imap); | 48 | kfree(sbi->s_imap); |
51 | sb->s_fs_info = NULL; | 49 | sb->s_fs_info = NULL; |
52 | kfree(sbi); | 50 | kfree(sbi); |
53 | |||
54 | unlock_kernel(); | ||
55 | } | 51 | } |
56 | 52 | ||
57 | static struct kmem_cache * minix_inode_cachep; | 53 | static struct kmem_cache * minix_inode_cachep; |
diff --git a/fs/minix/minix.h b/fs/minix/minix.h index cb7fdd11f9a5..9dcf95b42116 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h | |||
@@ -1,3 +1,6 @@ | |||
1 | #ifndef FS_MINIX_H | ||
2 | #define FS_MINIX_H | ||
3 | |||
1 | #include <linux/fs.h> | 4 | #include <linux/fs.h> |
2 | #include <linux/pagemap.h> | 5 | #include <linux/pagemap.h> |
3 | #include <linux/minix_fs.h> | 6 | #include <linux/minix_fs.h> |
@@ -86,3 +89,5 @@ static inline struct minix_inode_info *minix_i(struct inode *inode) | |||
86 | { | 89 | { |
87 | return list_entry(inode, struct minix_inode_info, vfs_inode); | 90 | return list_entry(inode, struct minix_inode_info, vfs_inode); |
88 | } | 91 | } |
92 | |||
93 | #endif /* FS_MINIX_H */ | ||
diff --git a/fs/namei.c b/fs/namei.c index 527119afb6a5..f3c5b278895a 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1698,8 +1698,11 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1698 | if (error) | 1698 | if (error) |
1699 | return ERR_PTR(error); | 1699 | return ERR_PTR(error); |
1700 | error = path_walk(pathname, &nd); | 1700 | error = path_walk(pathname, &nd); |
1701 | if (error) | 1701 | if (error) { |
1702 | if (nd.root.mnt) | ||
1703 | path_put(&nd.root); | ||
1702 | return ERR_PTR(error); | 1704 | return ERR_PTR(error); |
1705 | } | ||
1703 | if (unlikely(!audit_dummy_context())) | 1706 | if (unlikely(!audit_dummy_context())) |
1704 | audit_inode(pathname, nd.path.dentry); | 1707 | audit_inode(pathname, nd.path.dentry); |
1705 | 1708 | ||
@@ -1758,7 +1761,13 @@ do_last: | |||
1758 | goto exit; | 1761 | goto exit; |
1759 | } | 1762 | } |
1760 | filp = nameidata_to_filp(&nd, open_flag); | 1763 | filp = nameidata_to_filp(&nd, open_flag); |
1764 | if (IS_ERR(filp)) | ||
1765 | ima_counts_put(&nd.path, | ||
1766 | acc_mode & (MAY_READ | MAY_WRITE | | ||
1767 | MAY_EXEC)); | ||
1761 | mnt_drop_write(nd.path.mnt); | 1768 | mnt_drop_write(nd.path.mnt); |
1769 | if (nd.root.mnt) | ||
1770 | path_put(&nd.root); | ||
1762 | return filp; | 1771 | return filp; |
1763 | } | 1772 | } |
1764 | 1773 | ||
@@ -1812,6 +1821,9 @@ ok: | |||
1812 | goto exit; | 1821 | goto exit; |
1813 | } | 1822 | } |
1814 | filp = nameidata_to_filp(&nd, open_flag); | 1823 | filp = nameidata_to_filp(&nd, open_flag); |
1824 | if (IS_ERR(filp)) | ||
1825 | ima_counts_put(&nd.path, | ||
1826 | acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC)); | ||
1815 | /* | 1827 | /* |
1816 | * It is now safe to drop the mnt write | 1828 | * It is now safe to drop the mnt write |
1817 | * because the filp has had a write taken | 1829 | * because the filp has had a write taken |
@@ -1819,6 +1831,8 @@ ok: | |||
1819 | */ | 1831 | */ |
1820 | if (will_write) | 1832 | if (will_write) |
1821 | mnt_drop_write(nd.path.mnt); | 1833 | mnt_drop_write(nd.path.mnt); |
1834 | if (nd.root.mnt) | ||
1835 | path_put(&nd.root); | ||
1822 | return filp; | 1836 | return filp; |
1823 | 1837 | ||
1824 | exit_mutex_unlock: | 1838 | exit_mutex_unlock: |
@@ -1859,6 +1873,8 @@ do_link: | |||
1859 | * with "intent.open". | 1873 | * with "intent.open". |
1860 | */ | 1874 | */ |
1861 | release_open_intent(&nd); | 1875 | release_open_intent(&nd); |
1876 | if (nd.root.mnt) | ||
1877 | path_put(&nd.root); | ||
1862 | return ERR_PTR(error); | 1878 | return ERR_PTR(error); |
1863 | } | 1879 | } |
1864 | nd.flags &= ~LOOKUP_PARENT; | 1880 | nd.flags &= ~LOOKUP_PARENT; |
diff --git a/fs/namespace.c b/fs/namespace.c index 2dd333b0fe7f..7230787d18b0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/mnt_namespace.h> | 23 | #include <linux/mnt_namespace.h> |
24 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
25 | #include <linux/nsproxy.h> | ||
25 | #include <linux/security.h> | 26 | #include <linux/security.h> |
26 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
27 | #include <linux/ramfs.h> | 28 | #include <linux/ramfs.h> |
@@ -42,6 +43,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); | |||
42 | static int event; | 43 | static int event; |
43 | static DEFINE_IDA(mnt_id_ida); | 44 | static DEFINE_IDA(mnt_id_ida); |
44 | static DEFINE_IDA(mnt_group_ida); | 45 | static DEFINE_IDA(mnt_group_ida); |
46 | static int mnt_id_start = 0; | ||
47 | static int mnt_group_start = 1; | ||
45 | 48 | ||
46 | static struct list_head *mount_hashtable __read_mostly; | 49 | static struct list_head *mount_hashtable __read_mostly; |
47 | static struct kmem_cache *mnt_cache __read_mostly; | 50 | static struct kmem_cache *mnt_cache __read_mostly; |
@@ -69,7 +72,9 @@ static int mnt_alloc_id(struct vfsmount *mnt) | |||
69 | retry: | 72 | retry: |
70 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); | 73 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); |
71 | spin_lock(&vfsmount_lock); | 74 | spin_lock(&vfsmount_lock); |
72 | res = ida_get_new(&mnt_id_ida, &mnt->mnt_id); | 75 | res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); |
76 | if (!res) | ||
77 | mnt_id_start = mnt->mnt_id + 1; | ||
73 | spin_unlock(&vfsmount_lock); | 78 | spin_unlock(&vfsmount_lock); |
74 | if (res == -EAGAIN) | 79 | if (res == -EAGAIN) |
75 | goto retry; | 80 | goto retry; |
@@ -79,8 +84,11 @@ retry: | |||
79 | 84 | ||
80 | static void mnt_free_id(struct vfsmount *mnt) | 85 | static void mnt_free_id(struct vfsmount *mnt) |
81 | { | 86 | { |
87 | int id = mnt->mnt_id; | ||
82 | spin_lock(&vfsmount_lock); | 88 | spin_lock(&vfsmount_lock); |
83 | ida_remove(&mnt_id_ida, mnt->mnt_id); | 89 | ida_remove(&mnt_id_ida, id); |
90 | if (mnt_id_start > id) | ||
91 | mnt_id_start = id; | ||
84 | spin_unlock(&vfsmount_lock); | 92 | spin_unlock(&vfsmount_lock); |
85 | } | 93 | } |
86 | 94 | ||
@@ -91,10 +99,18 @@ static void mnt_free_id(struct vfsmount *mnt) | |||
91 | */ | 99 | */ |
92 | static int mnt_alloc_group_id(struct vfsmount *mnt) | 100 | static int mnt_alloc_group_id(struct vfsmount *mnt) |
93 | { | 101 | { |
102 | int res; | ||
103 | |||
94 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) | 104 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) |
95 | return -ENOMEM; | 105 | return -ENOMEM; |
96 | 106 | ||
97 | return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id); | 107 | res = ida_get_new_above(&mnt_group_ida, |
108 | mnt_group_start, | ||
109 | &mnt->mnt_group_id); | ||
110 | if (!res) | ||
111 | mnt_group_start = mnt->mnt_group_id + 1; | ||
112 | |||
113 | return res; | ||
98 | } | 114 | } |
99 | 115 | ||
100 | /* | 116 | /* |
@@ -102,7 +118,10 @@ static int mnt_alloc_group_id(struct vfsmount *mnt) | |||
102 | */ | 118 | */ |
103 | void mnt_release_group_id(struct vfsmount *mnt) | 119 | void mnt_release_group_id(struct vfsmount *mnt) |
104 | { | 120 | { |
105 | ida_remove(&mnt_group_ida, mnt->mnt_group_id); | 121 | int id = mnt->mnt_group_id; |
122 | ida_remove(&mnt_group_ida, id); | ||
123 | if (mnt_group_start > id) | ||
124 | mnt_group_start = id; | ||
106 | mnt->mnt_group_id = 0; | 125 | mnt->mnt_group_id = 0; |
107 | } | 126 | } |
108 | 127 | ||
@@ -297,7 +316,8 @@ EXPORT_SYMBOL_GPL(mnt_clone_write); | |||
297 | */ | 316 | */ |
298 | int mnt_want_write_file(struct file *file) | 317 | int mnt_want_write_file(struct file *file) |
299 | { | 318 | { |
300 | if (!(file->f_mode & FMODE_WRITE)) | 319 | struct inode *inode = file->f_dentry->d_inode; |
320 | if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) | ||
301 | return mnt_want_write(file->f_path.mnt); | 321 | return mnt_want_write(file->f_path.mnt); |
302 | else | 322 | else |
303 | return mnt_clone_write(file->f_path.mnt); | 323 | return mnt_clone_write(file->f_path.mnt); |
@@ -1937,6 +1957,21 @@ dput_out: | |||
1937 | return retval; | 1957 | return retval; |
1938 | } | 1958 | } |
1939 | 1959 | ||
1960 | static struct mnt_namespace *alloc_mnt_ns(void) | ||
1961 | { | ||
1962 | struct mnt_namespace *new_ns; | ||
1963 | |||
1964 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | ||
1965 | if (!new_ns) | ||
1966 | return ERR_PTR(-ENOMEM); | ||
1967 | atomic_set(&new_ns->count, 1); | ||
1968 | new_ns->root = NULL; | ||
1969 | INIT_LIST_HEAD(&new_ns->list); | ||
1970 | init_waitqueue_head(&new_ns->poll); | ||
1971 | new_ns->event = 0; | ||
1972 | return new_ns; | ||
1973 | } | ||
1974 | |||
1940 | /* | 1975 | /* |
1941 | * Allocate a new namespace structure and populate it with contents | 1976 | * Allocate a new namespace structure and populate it with contents |
1942 | * copied from the namespace of the passed in task structure. | 1977 | * copied from the namespace of the passed in task structure. |
@@ -1948,14 +1983,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
1948 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; | 1983 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
1949 | struct vfsmount *p, *q; | 1984 | struct vfsmount *p, *q; |
1950 | 1985 | ||
1951 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1986 | new_ns = alloc_mnt_ns(); |
1952 | if (!new_ns) | 1987 | if (IS_ERR(new_ns)) |
1953 | return ERR_PTR(-ENOMEM); | 1988 | return new_ns; |
1954 | |||
1955 | atomic_set(&new_ns->count, 1); | ||
1956 | INIT_LIST_HEAD(&new_ns->list); | ||
1957 | init_waitqueue_head(&new_ns->poll); | ||
1958 | new_ns->event = 0; | ||
1959 | 1989 | ||
1960 | down_write(&namespace_sem); | 1990 | down_write(&namespace_sem); |
1961 | /* First pass: copy the tree topology */ | 1991 | /* First pass: copy the tree topology */ |
@@ -2019,6 +2049,24 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2019 | return new_ns; | 2049 | return new_ns; |
2020 | } | 2050 | } |
2021 | 2051 | ||
2052 | /** | ||
2053 | * create_mnt_ns - creates a private namespace and adds a root filesystem | ||
2054 | * @mnt: pointer to the new root filesystem mountpoint | ||
2055 | */ | ||
2056 | struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) | ||
2057 | { | ||
2058 | struct mnt_namespace *new_ns; | ||
2059 | |||
2060 | new_ns = alloc_mnt_ns(); | ||
2061 | if (!IS_ERR(new_ns)) { | ||
2062 | mnt->mnt_ns = new_ns; | ||
2063 | new_ns->root = mnt; | ||
2064 | list_add(&new_ns->list, &new_ns->root->mnt_list); | ||
2065 | } | ||
2066 | return new_ns; | ||
2067 | } | ||
2068 | EXPORT_SYMBOL(create_mnt_ns); | ||
2069 | |||
2022 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2070 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
2023 | char __user *, type, unsigned long, flags, void __user *, data) | 2071 | char __user *, type, unsigned long, flags, void __user *, data) |
2024 | { | 2072 | { |
@@ -2194,16 +2242,9 @@ static void __init init_mount_tree(void) | |||
2194 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 2242 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); |
2195 | if (IS_ERR(mnt)) | 2243 | if (IS_ERR(mnt)) |
2196 | panic("Can't create rootfs"); | 2244 | panic("Can't create rootfs"); |
2197 | ns = kmalloc(sizeof(*ns), GFP_KERNEL); | 2245 | ns = create_mnt_ns(mnt); |
2198 | if (!ns) | 2246 | if (IS_ERR(ns)) |
2199 | panic("Can't allocate initial namespace"); | 2247 | panic("Can't allocate initial namespace"); |
2200 | atomic_set(&ns->count, 1); | ||
2201 | INIT_LIST_HEAD(&ns->list); | ||
2202 | init_waitqueue_head(&ns->poll); | ||
2203 | ns->event = 0; | ||
2204 | list_add(&mnt->mnt_list, &ns->list); | ||
2205 | ns->root = mnt; | ||
2206 | mnt->mnt_ns = ns; | ||
2207 | 2248 | ||
2208 | init_task.nsproxy->mnt_ns = ns; | 2249 | init_task.nsproxy->mnt_ns = ns; |
2209 | get_mnt_ns(ns); | 2250 | get_mnt_ns(ns); |
@@ -2246,10 +2287,14 @@ void __init mnt_init(void) | |||
2246 | init_mount_tree(); | 2287 | init_mount_tree(); |
2247 | } | 2288 | } |
2248 | 2289 | ||
2249 | void __put_mnt_ns(struct mnt_namespace *ns) | 2290 | void put_mnt_ns(struct mnt_namespace *ns) |
2250 | { | 2291 | { |
2251 | struct vfsmount *root = ns->root; | 2292 | struct vfsmount *root; |
2252 | LIST_HEAD(umount_list); | 2293 | LIST_HEAD(umount_list); |
2294 | |||
2295 | if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock)) | ||
2296 | return; | ||
2297 | root = ns->root; | ||
2253 | ns->root = NULL; | 2298 | ns->root = NULL; |
2254 | spin_unlock(&vfsmount_lock); | 2299 | spin_unlock(&vfsmount_lock); |
2255 | down_write(&namespace_sem); | 2300 | down_write(&namespace_sem); |
@@ -2260,3 +2305,4 @@ void __put_mnt_ns(struct mnt_namespace *ns) | |||
2260 | release_mounts(&umount_list); | 2305 | release_mounts(&umount_list); |
2261 | kfree(ns); | 2306 | kfree(ns); |
2262 | } | 2307 | } |
2308 | EXPORT_SYMBOL(put_mnt_ns); | ||
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index 97645f112114..0ec6237a5970 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c | |||
@@ -1113,11 +1113,13 @@ ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen, | |||
1113 | 1113 | ||
1114 | if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { | 1114 | if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { |
1115 | int k; | 1115 | int k; |
1116 | unicode_t u; | ||
1116 | 1117 | ||
1117 | k = utf8_mbtowc(&ec, iname, iname_end - iname); | 1118 | k = utf8_to_utf32(iname, iname_end - iname, &u); |
1118 | if (k < 0) | 1119 | if (k < 0 || u > MAX_WCHAR_T) |
1119 | return -EINVAL; | 1120 | return -EINVAL; |
1120 | iname += k; | 1121 | iname += k; |
1122 | ec = u; | ||
1121 | } else { | 1123 | } else { |
1122 | if (*iname == NCP_ESC) { | 1124 | if (*iname == NCP_ESC) { |
1123 | int k; | 1125 | int k; |
@@ -1214,7 +1216,7 @@ ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen, | |||
1214 | if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { | 1216 | if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { |
1215 | int k; | 1217 | int k; |
1216 | 1218 | ||
1217 | k = utf8_wctomb(iname, ec, iname_end - iname); | 1219 | k = utf32_to_utf8(ec, iname, iname_end - iname); |
1218 | if (k < 0) { | 1220 | if (k < 0) { |
1219 | err = -ENAMETOOLONG; | 1221 | err = -ENAMETOOLONG; |
1220 | goto quit; | 1222 | goto quit; |
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index e67f3ec07736..2a77bc25d5af 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config NFS_FS | 1 | config NFS_FS |
2 | tristate "NFS client support" | 2 | tristate "NFS client support" |
3 | depends on INET | 3 | depends on INET && FILE_LOCKING |
4 | select LOCKD | 4 | select LOCKD |
5 | select SUNRPC | 5 | select SUNRPC |
6 | select NFS_ACL_SUPPORT if NFS_V3_ACL | 6 | select NFS_ACL_SUPPORT if NFS_V3_ACL |
@@ -74,6 +74,15 @@ config NFS_V4 | |||
74 | 74 | ||
75 | If unsure, say N. | 75 | If unsure, say N. |
76 | 76 | ||
77 | config NFS_V4_1 | ||
78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | ||
79 | depends on NFS_V4 && EXPERIMENTAL | ||
80 | help | ||
81 | This option enables support for minor version 1 of the NFSv4 protocol | ||
82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | ||
83 | |||
84 | Unless you're an NFS developer, say N. | ||
85 | |||
77 | config ROOT_NFS | 86 | config ROOT_NFS |
78 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
79 | depends on NFS_FS=y && IP_PNP | 88 | depends on NFS_FS=y && IP_PNP |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index a886e692ddd0..7f604c7941fb 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
19 | #include <linux/sunrpc/svcauth_gss.h> | 19 | #include <linux/sunrpc/svcauth_gss.h> |
20 | #if defined(CONFIG_NFS_V4_1) | ||
21 | #include <linux/sunrpc/bc_xprt.h> | ||
22 | #endif | ||
20 | 23 | ||
21 | #include <net/inet_sock.h> | 24 | #include <net/inet_sock.h> |
22 | 25 | ||
@@ -28,11 +31,12 @@ | |||
28 | 31 | ||
29 | struct nfs_callback_data { | 32 | struct nfs_callback_data { |
30 | unsigned int users; | 33 | unsigned int users; |
34 | struct svc_serv *serv; | ||
31 | struct svc_rqst *rqst; | 35 | struct svc_rqst *rqst; |
32 | struct task_struct *task; | 36 | struct task_struct *task; |
33 | }; | 37 | }; |
34 | 38 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 39 | static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; |
36 | static DEFINE_MUTEX(nfs_callback_mutex); | 40 | static DEFINE_MUTEX(nfs_callback_mutex); |
37 | static struct svc_program nfs4_callback_program; | 41 | static struct svc_program nfs4_callback_program; |
38 | 42 | ||
@@ -56,10 +60,10 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
56 | &nfs_callback_set_tcpport, 0644); | 60 | &nfs_callback_set_tcpport, 0644); |
57 | 61 | ||
58 | /* | 62 | /* |
59 | * This is the callback kernel thread. | 63 | * This is the NFSv4 callback kernel thread. |
60 | */ | 64 | */ |
61 | static int | 65 | static int |
62 | nfs_callback_svc(void *vrqstp) | 66 | nfs4_callback_svc(void *vrqstp) |
63 | { | 67 | { |
64 | int err, preverr = 0; | 68 | int err, preverr = 0; |
65 | struct svc_rqst *rqstp = vrqstp; | 69 | struct svc_rqst *rqstp = vrqstp; |
@@ -97,20 +101,12 @@ nfs_callback_svc(void *vrqstp) | |||
97 | } | 101 | } |
98 | 102 | ||
99 | /* | 103 | /* |
100 | * Bring up the callback thread if it is not already up. | 104 | * Prepare to bring up the NFSv4 callback service |
101 | */ | 105 | */ |
102 | int nfs_callback_up(void) | 106 | struct svc_rqst * |
107 | nfs4_callback_up(struct svc_serv *serv) | ||
103 | { | 108 | { |
104 | struct svc_serv *serv = NULL; | 109 | int ret; |
105 | int ret = 0; | ||
106 | |||
107 | mutex_lock(&nfs_callback_mutex); | ||
108 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) | ||
109 | goto out; | ||
110 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
111 | ret = -ENOMEM; | ||
112 | if (!serv) | ||
113 | goto out_err; | ||
114 | 110 | ||
115 | ret = svc_create_xprt(serv, "tcp", PF_INET, | 111 | ret = svc_create_xprt(serv, "tcp", PF_INET, |
116 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 112 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
@@ -127,27 +123,174 @@ int nfs_callback_up(void) | |||
127 | nfs_callback_tcpport6 = ret; | 123 | nfs_callback_tcpport6 = ret; |
128 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 124 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
129 | nfs_callback_tcpport6, PF_INET6); | 125 | nfs_callback_tcpport6, PF_INET6); |
130 | } else if (ret != -EAFNOSUPPORT) | 126 | } else if (ret == -EAFNOSUPPORT) |
127 | ret = 0; | ||
128 | else | ||
131 | goto out_err; | 129 | goto out_err; |
132 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | 130 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ |
133 | 131 | ||
134 | nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); | 132 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
135 | if (IS_ERR(nfs_callback_info.rqst)) { | 133 | |
136 | ret = PTR_ERR(nfs_callback_info.rqst); | 134 | out_err: |
137 | nfs_callback_info.rqst = NULL; | 135 | if (ret == 0) |
136 | ret = -ENOMEM; | ||
137 | return ERR_PTR(ret); | ||
138 | } | ||
139 | |||
140 | #if defined(CONFIG_NFS_V4_1) | ||
141 | /* | ||
142 | * The callback service for NFSv4.1 callbacks | ||
143 | */ | ||
144 | static int | ||
145 | nfs41_callback_svc(void *vrqstp) | ||
146 | { | ||
147 | struct svc_rqst *rqstp = vrqstp; | ||
148 | struct svc_serv *serv = rqstp->rq_server; | ||
149 | struct rpc_rqst *req; | ||
150 | int error; | ||
151 | DEFINE_WAIT(wq); | ||
152 | |||
153 | set_freezable(); | ||
154 | |||
155 | /* | ||
156 | * FIXME: do we really need to run this under the BKL? If so, please | ||
157 | * add a comment about what it's intended to protect. | ||
158 | */ | ||
159 | lock_kernel(); | ||
160 | while (!kthread_should_stop()) { | ||
161 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | ||
162 | spin_lock_bh(&serv->sv_cb_lock); | ||
163 | if (!list_empty(&serv->sv_cb_list)) { | ||
164 | req = list_first_entry(&serv->sv_cb_list, | ||
165 | struct rpc_rqst, rq_bc_list); | ||
166 | list_del(&req->rq_bc_list); | ||
167 | spin_unlock_bh(&serv->sv_cb_lock); | ||
168 | dprintk("Invoking bc_svc_process()\n"); | ||
169 | error = bc_svc_process(serv, req, rqstp); | ||
170 | dprintk("bc_svc_process() returned w/ error code= %d\n", | ||
171 | error); | ||
172 | } else { | ||
173 | spin_unlock_bh(&serv->sv_cb_lock); | ||
174 | schedule(); | ||
175 | } | ||
176 | finish_wait(&serv->sv_cb_waitq, &wq); | ||
177 | } | ||
178 | unlock_kernel(); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Bring up the NFSv4.1 callback service | ||
184 | */ | ||
185 | struct svc_rqst * | ||
186 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | ||
187 | { | ||
188 | struct svc_xprt *bc_xprt; | ||
189 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | ||
190 | |||
191 | dprintk("--> %s\n", __func__); | ||
192 | /* Create a svc_sock for the service */ | ||
193 | bc_xprt = svc_sock_create(serv, xprt->prot); | ||
194 | if (!bc_xprt) | ||
195 | goto out; | ||
196 | |||
197 | /* | ||
198 | * Save the svc_serv in the transport so that it can | ||
199 | * be referenced when the session backchannel is initialized | ||
200 | */ | ||
201 | serv->bc_xprt = bc_xprt; | ||
202 | xprt->bc_serv = serv; | ||
203 | |||
204 | INIT_LIST_HEAD(&serv->sv_cb_list); | ||
205 | spin_lock_init(&serv->sv_cb_lock); | ||
206 | init_waitqueue_head(&serv->sv_cb_waitq); | ||
207 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | ||
208 | if (IS_ERR(rqstp)) | ||
209 | svc_sock_destroy(bc_xprt); | ||
210 | out: | ||
211 | dprintk("--> %s return %p\n", __func__, rqstp); | ||
212 | return rqstp; | ||
213 | } | ||
214 | |||
215 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
216 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
217 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
218 | { | ||
219 | if (minorversion) { | ||
220 | *rqstpp = nfs41_callback_up(serv, xprt); | ||
221 | *callback_svc = nfs41_callback_svc; | ||
222 | } | ||
223 | return minorversion; | ||
224 | } | ||
225 | |||
226 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
227 | struct nfs_callback_data *cb_info) | ||
228 | { | ||
229 | if (minorversion) | ||
230 | xprt->bc_serv = cb_info->serv; | ||
231 | } | ||
232 | #else | ||
233 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
234 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
235 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
236 | { | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
241 | struct nfs_callback_data *cb_info) | ||
242 | { | ||
243 | } | ||
244 | #endif /* CONFIG_NFS_V4_1 */ | ||
245 | |||
246 | /* | ||
247 | * Bring up the callback thread if it is not already up. | ||
248 | */ | ||
249 | int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | ||
250 | { | ||
251 | struct svc_serv *serv = NULL; | ||
252 | struct svc_rqst *rqstp; | ||
253 | int (*callback_svc)(void *vrqstp); | ||
254 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
255 | char svc_name[12]; | ||
256 | int ret = 0; | ||
257 | int minorversion_setup; | ||
258 | |||
259 | mutex_lock(&nfs_callback_mutex); | ||
260 | if (cb_info->users++ || cb_info->task != NULL) { | ||
261 | nfs_callback_bc_serv(minorversion, xprt, cb_info); | ||
262 | goto out; | ||
263 | } | ||
264 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
265 | if (!serv) { | ||
266 | ret = -ENOMEM; | ||
267 | goto out_err; | ||
268 | } | ||
269 | |||
270 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, | ||
271 | serv, xprt, &rqstp, &callback_svc); | ||
272 | if (!minorversion_setup) { | ||
273 | /* v4.0 callback setup */ | ||
274 | rqstp = nfs4_callback_up(serv); | ||
275 | callback_svc = nfs4_callback_svc; | ||
276 | } | ||
277 | |||
278 | if (IS_ERR(rqstp)) { | ||
279 | ret = PTR_ERR(rqstp); | ||
138 | goto out_err; | 280 | goto out_err; |
139 | } | 281 | } |
140 | 282 | ||
141 | svc_sock_update_bufs(serv); | 283 | svc_sock_update_bufs(serv); |
142 | 284 | ||
143 | nfs_callback_info.task = kthread_run(nfs_callback_svc, | 285 | sprintf(svc_name, "nfsv4.%u-svc", minorversion); |
144 | nfs_callback_info.rqst, | 286 | cb_info->serv = serv; |
145 | "nfsv4-svc"); | 287 | cb_info->rqst = rqstp; |
146 | if (IS_ERR(nfs_callback_info.task)) { | 288 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); |
147 | ret = PTR_ERR(nfs_callback_info.task); | 289 | if (IS_ERR(cb_info->task)) { |
148 | svc_exit_thread(nfs_callback_info.rqst); | 290 | ret = PTR_ERR(cb_info->task); |
149 | nfs_callback_info.rqst = NULL; | 291 | svc_exit_thread(cb_info->rqst); |
150 | nfs_callback_info.task = NULL; | 292 | cb_info->rqst = NULL; |
293 | cb_info->task = NULL; | ||
151 | goto out_err; | 294 | goto out_err; |
152 | } | 295 | } |
153 | out: | 296 | out: |
@@ -164,22 +307,25 @@ out: | |||
164 | out_err: | 307 | out_err: |
165 | dprintk("NFS: Couldn't create callback socket or server thread; " | 308 | dprintk("NFS: Couldn't create callback socket or server thread; " |
166 | "err = %d\n", ret); | 309 | "err = %d\n", ret); |
167 | nfs_callback_info.users--; | 310 | cb_info->users--; |
168 | goto out; | 311 | goto out; |
169 | } | 312 | } |
170 | 313 | ||
171 | /* | 314 | /* |
172 | * Kill the callback thread if it's no longer being used. | 315 | * Kill the callback thread if it's no longer being used. |
173 | */ | 316 | */ |
174 | void nfs_callback_down(void) | 317 | void nfs_callback_down(int minorversion) |
175 | { | 318 | { |
319 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
320 | |||
176 | mutex_lock(&nfs_callback_mutex); | 321 | mutex_lock(&nfs_callback_mutex); |
177 | nfs_callback_info.users--; | 322 | cb_info->users--; |
178 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { | 323 | if (cb_info->users == 0 && cb_info->task != NULL) { |
179 | kthread_stop(nfs_callback_info.task); | 324 | kthread_stop(cb_info->task); |
180 | svc_exit_thread(nfs_callback_info.rqst); | 325 | svc_exit_thread(cb_info->rqst); |
181 | nfs_callback_info.rqst = NULL; | 326 | cb_info->serv = NULL; |
182 | nfs_callback_info.task = NULL; | 327 | cb_info->rqst = NULL; |
328 | cb_info->task = NULL; | ||
183 | } | 329 | } |
184 | mutex_unlock(&nfs_callback_mutex); | 330 | mutex_unlock(&nfs_callback_mutex); |
185 | } | 331 | } |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e110e286a262..07baa8254ca1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -20,13 +20,24 @@ enum nfs4_callback_procnum { | |||
20 | enum nfs4_callback_opnum { | 20 | enum nfs4_callback_opnum { |
21 | OP_CB_GETATTR = 3, | 21 | OP_CB_GETATTR = 3, |
22 | OP_CB_RECALL = 4, | 22 | OP_CB_RECALL = 4, |
23 | /* Callback operations new to NFSv4.1 */ | ||
24 | OP_CB_LAYOUTRECALL = 5, | ||
25 | OP_CB_NOTIFY = 6, | ||
26 | OP_CB_PUSH_DELEG = 7, | ||
27 | OP_CB_RECALL_ANY = 8, | ||
28 | OP_CB_RECALLABLE_OBJ_AVAIL = 9, | ||
29 | OP_CB_RECALL_SLOT = 10, | ||
30 | OP_CB_SEQUENCE = 11, | ||
31 | OP_CB_WANTS_CANCELLED = 12, | ||
32 | OP_CB_NOTIFY_LOCK = 13, | ||
33 | OP_CB_NOTIFY_DEVICEID = 14, | ||
23 | OP_CB_ILLEGAL = 10044, | 34 | OP_CB_ILLEGAL = 10044, |
24 | }; | 35 | }; |
25 | 36 | ||
26 | struct cb_compound_hdr_arg { | 37 | struct cb_compound_hdr_arg { |
27 | unsigned int taglen; | 38 | unsigned int taglen; |
28 | const char *tag; | 39 | const char *tag; |
29 | unsigned int callback_ident; | 40 | unsigned int minorversion; |
30 | unsigned nops; | 41 | unsigned nops; |
31 | }; | 42 | }; |
32 | 43 | ||
@@ -59,16 +70,59 @@ struct cb_recallargs { | |||
59 | uint32_t truncate; | 70 | uint32_t truncate; |
60 | }; | 71 | }; |
61 | 72 | ||
73 | #if defined(CONFIG_NFS_V4_1) | ||
74 | |||
75 | struct referring_call { | ||
76 | uint32_t rc_sequenceid; | ||
77 | uint32_t rc_slotid; | ||
78 | }; | ||
79 | |||
80 | struct referring_call_list { | ||
81 | struct nfs4_sessionid rcl_sessionid; | ||
82 | uint32_t rcl_nrefcalls; | ||
83 | struct referring_call *rcl_refcalls; | ||
84 | }; | ||
85 | |||
86 | struct cb_sequenceargs { | ||
87 | struct sockaddr *csa_addr; | ||
88 | struct nfs4_sessionid csa_sessionid; | ||
89 | uint32_t csa_sequenceid; | ||
90 | uint32_t csa_slotid; | ||
91 | uint32_t csa_highestslotid; | ||
92 | uint32_t csa_cachethis; | ||
93 | uint32_t csa_nrclists; | ||
94 | struct referring_call_list *csa_rclists; | ||
95 | }; | ||
96 | |||
97 | struct cb_sequenceres { | ||
98 | __be32 csr_status; | ||
99 | struct nfs4_sessionid csr_sessionid; | ||
100 | uint32_t csr_sequenceid; | ||
101 | uint32_t csr_slotid; | ||
102 | uint32_t csr_highestslotid; | ||
103 | uint32_t csr_target_highestslotid; | ||
104 | }; | ||
105 | |||
106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
107 | struct cb_sequenceres *res); | ||
108 | |||
109 | #endif /* CONFIG_NFS_V4_1 */ | ||
110 | |||
62 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 111 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
63 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 112 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
64 | 113 | ||
65 | #ifdef CONFIG_NFS_V4 | 114 | #ifdef CONFIG_NFS_V4 |
66 | extern int nfs_callback_up(void); | 115 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
67 | extern void nfs_callback_down(void); | 116 | extern void nfs_callback_down(int minorversion); |
68 | #else | 117 | #endif /* CONFIG_NFS_V4 */ |
69 | #define nfs_callback_up() (0) | 118 | |
70 | #define nfs_callback_down() do {} while(0) | 119 | /* |
71 | #endif | 120 | * nfs41: Callbacks are expected to not cause substantial latency, |
121 | * so we limit their concurrency to 1 by setting up the maximum number | ||
122 | * of slots for the backchannel. | ||
123 | */ | ||
124 | #define NFS41_BC_MIN_CALLBACKS 1 | ||
125 | #define NFS41_BC_MAX_CALLBACKS 1 | ||
72 | 126 | ||
73 | extern unsigned int nfs_callback_set_tcpport; | 127 | extern unsigned int nfs_callback_set_tcpport; |
74 | extern unsigned short nfs_callback_tcpport; | 128 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f7e83e23cf9f..b7da1f54da68 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -101,3 +101,130 @@ out: | |||
101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
102 | return res; | 102 | return res; |
103 | } | 103 | } |
104 | |||
105 | #if defined(CONFIG_NFS_V4_1) | ||
106 | |||
107 | /* | ||
108 | * Validate the sequenceID sent by the server. | ||
109 | * Return success if the sequenceID is one more than what we last saw on | ||
110 | * this slot, accounting for wraparound. Increments the slot's sequence. | ||
111 | * | ||
112 | * We don't yet implement a duplicate request cache, so at this time | ||
113 | * we will log replays, and process them as if we had not seen them before, | ||
114 | * but we don't bump the sequence in the slot. Not too worried about it, | ||
115 | * since we only currently implement idempotent callbacks anyway. | ||
116 | * | ||
117 | * We have a single slot backchannel at this time, so we don't bother | ||
118 | * checking the used_slots bit array on the table. The lower layer guarantees | ||
119 | * a single outstanding callback request at a time. | ||
120 | */ | ||
121 | static int | ||
122 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | ||
123 | { | ||
124 | struct nfs4_slot *slot; | ||
125 | |||
126 | dprintk("%s enter. slotid %d seqid %d\n", | ||
127 | __func__, slotid, seqid); | ||
128 | |||
129 | if (slotid > NFS41_BC_MAX_CALLBACKS) | ||
130 | return htonl(NFS4ERR_BADSLOT); | ||
131 | |||
132 | slot = tbl->slots + slotid; | ||
133 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | ||
134 | |||
135 | /* Normal */ | ||
136 | if (likely(seqid == slot->seq_nr + 1)) { | ||
137 | slot->seq_nr++; | ||
138 | return htonl(NFS4_OK); | ||
139 | } | ||
140 | |||
141 | /* Replay */ | ||
142 | if (seqid == slot->seq_nr) { | ||
143 | dprintk("%s seqid %d is a replay - no DRC available\n", | ||
144 | __func__, seqid); | ||
145 | return htonl(NFS4_OK); | ||
146 | } | ||
147 | |||
148 | /* Wraparound */ | ||
149 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | ||
150 | slot->seq_nr = 1; | ||
151 | return htonl(NFS4_OK); | ||
152 | } | ||
153 | |||
154 | /* Misordered request */ | ||
155 | return htonl(NFS4ERR_SEQ_MISORDERED); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Returns a pointer to a held 'struct nfs_client' that matches the server's | ||
160 | * address, major version number, and session ID. It is the caller's | ||
161 | * responsibility to release the returned reference. | ||
162 | * | ||
163 | * Returns NULL if there are no connections with sessions, or if no session | ||
164 | * matches the one of interest. | ||
165 | */ | ||
166 | static struct nfs_client *find_client_with_session( | ||
167 | const struct sockaddr *addr, u32 nfsversion, | ||
168 | struct nfs4_sessionid *sessionid) | ||
169 | { | ||
170 | struct nfs_client *clp; | ||
171 | |||
172 | clp = nfs_find_client(addr, 4); | ||
173 | if (clp == NULL) | ||
174 | return NULL; | ||
175 | |||
176 | do { | ||
177 | struct nfs_client *prev = clp; | ||
178 | |||
179 | if (clp->cl_session != NULL) { | ||
180 | if (memcmp(clp->cl_session->sess_id.data, | ||
181 | sessionid->data, | ||
182 | NFS4_MAX_SESSIONID_LEN) == 0) { | ||
183 | /* Returns a held reference to clp */ | ||
184 | return clp; | ||
185 | } | ||
186 | } | ||
187 | clp = nfs_find_client_next(prev); | ||
188 | nfs_put_client(prev); | ||
189 | } while (clp != NULL); | ||
190 | |||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* FIXME: referring calls should be processed */ | ||
195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
196 | struct cb_sequenceres *res) | ||
197 | { | ||
198 | struct nfs_client *clp; | ||
199 | int i, status; | ||
200 | |||
201 | for (i = 0; i < args->csa_nrclists; i++) | ||
202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
203 | kfree(args->csa_rclists); | ||
204 | |||
205 | status = htonl(NFS4ERR_BADSESSION); | ||
206 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | ||
207 | if (clp == NULL) | ||
208 | goto out; | ||
209 | |||
210 | status = validate_seqid(&clp->cl_session->bc_slot_table, | ||
211 | args->csa_slotid, args->csa_sequenceid); | ||
212 | if (status) | ||
213 | goto out_putclient; | ||
214 | |||
215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
216 | sizeof(res->csr_sessionid)); | ||
217 | res->csr_sequenceid = args->csa_sequenceid; | ||
218 | res->csr_slotid = args->csa_slotid; | ||
219 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
220 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
221 | |||
222 | out_putclient: | ||
223 | nfs_put_client(clp); | ||
224 | out: | ||
225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
226 | res->csr_status = status; | ||
227 | return res->csr_status; | ||
228 | } | ||
229 | |||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index dd0ef34b5845..e5a2dac5f715 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -20,6 +20,11 @@ | |||
20 | 2 + 2 + 3 + 3) | 20 | 2 + 2 + 3 + 3) |
21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
22 | 22 | ||
23 | #if defined(CONFIG_NFS_V4_1) | ||
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | ||
25 | 4 + 1 + 3) | ||
26 | #endif /* CONFIG_NFS_V4_1 */ | ||
27 | |||
23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 28 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
24 | 29 | ||
25 | typedef __be32 (*callback_process_op_t)(void *, void *); | 30 | typedef __be32 (*callback_process_op_t)(void *, void *); |
@@ -132,7 +137,6 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | |||
132 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) | 137 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) |
133 | { | 138 | { |
134 | __be32 *p; | 139 | __be32 *p; |
135 | unsigned int minor_version; | ||
136 | __be32 status; | 140 | __be32 status; |
137 | 141 | ||
138 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); | 142 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); |
@@ -147,15 +151,19 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
147 | p = read_buf(xdr, 12); | 151 | p = read_buf(xdr, 12); |
148 | if (unlikely(p == NULL)) | 152 | if (unlikely(p == NULL)) |
149 | return htonl(NFS4ERR_RESOURCE); | 153 | return htonl(NFS4ERR_RESOURCE); |
150 | minor_version = ntohl(*p++); | 154 | hdr->minorversion = ntohl(*p++); |
151 | /* Check minor version is zero. */ | 155 | /* Check minor version is zero or one. */ |
152 | if (minor_version != 0) { | 156 | if (hdr->minorversion <= 1) { |
153 | printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n", | 157 | p++; /* skip callback_ident */ |
154 | __func__, minor_version); | 158 | } else { |
159 | printk(KERN_WARNING "%s: NFSv4 server callback with " | ||
160 | "illegal minor version %u!\n", | ||
161 | __func__, hdr->minorversion); | ||
155 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 162 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
156 | } | 163 | } |
157 | hdr->callback_ident = ntohl(*p++); | ||
158 | hdr->nops = ntohl(*p); | 164 | hdr->nops = ntohl(*p); |
165 | dprintk("%s: minorversion %d nops %d\n", __func__, | ||
166 | hdr->minorversion, hdr->nops); | ||
159 | return 0; | 167 | return 0; |
160 | } | 168 | } |
161 | 169 | ||
@@ -204,6 +212,122 @@ out: | |||
204 | return status; | 212 | return status; |
205 | } | 213 | } |
206 | 214 | ||
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | |||
217 | static unsigned decode_sessionid(struct xdr_stream *xdr, | ||
218 | struct nfs4_sessionid *sid) | ||
219 | { | ||
220 | uint32_t *p; | ||
221 | int len = NFS4_MAX_SESSIONID_LEN; | ||
222 | |||
223 | p = read_buf(xdr, len); | ||
224 | if (unlikely(p == NULL)) | ||
225 | return htonl(NFS4ERR_RESOURCE);; | ||
226 | |||
227 | memcpy(sid->data, p, len); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static unsigned decode_rc_list(struct xdr_stream *xdr, | ||
232 | struct referring_call_list *rc_list) | ||
233 | { | ||
234 | uint32_t *p; | ||
235 | int i; | ||
236 | unsigned status; | ||
237 | |||
238 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | ||
239 | if (status) | ||
240 | goto out; | ||
241 | |||
242 | status = htonl(NFS4ERR_RESOURCE); | ||
243 | p = read_buf(xdr, sizeof(uint32_t)); | ||
244 | if (unlikely(p == NULL)) | ||
245 | goto out; | ||
246 | |||
247 | rc_list->rcl_nrefcalls = ntohl(*p++); | ||
248 | if (rc_list->rcl_nrefcalls) { | ||
249 | p = read_buf(xdr, | ||
250 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); | ||
251 | if (unlikely(p == NULL)) | ||
252 | goto out; | ||
253 | rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls * | ||
254 | sizeof(*rc_list->rcl_refcalls), | ||
255 | GFP_KERNEL); | ||
256 | if (unlikely(rc_list->rcl_refcalls == NULL)) | ||
257 | goto out; | ||
258 | for (i = 0; i < rc_list->rcl_nrefcalls; i++) { | ||
259 | rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); | ||
260 | rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); | ||
261 | } | ||
262 | } | ||
263 | status = 0; | ||
264 | |||
265 | out: | ||
266 | return status; | ||
267 | } | ||
268 | |||
269 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | ||
270 | struct xdr_stream *xdr, | ||
271 | struct cb_sequenceargs *args) | ||
272 | { | ||
273 | uint32_t *p; | ||
274 | int i; | ||
275 | unsigned status; | ||
276 | |||
277 | status = decode_sessionid(xdr, &args->csa_sessionid); | ||
278 | if (status) | ||
279 | goto out; | ||
280 | |||
281 | status = htonl(NFS4ERR_RESOURCE); | ||
282 | p = read_buf(xdr, 5 * sizeof(uint32_t)); | ||
283 | if (unlikely(p == NULL)) | ||
284 | goto out; | ||
285 | |||
286 | args->csa_addr = svc_addr(rqstp); | ||
287 | args->csa_sequenceid = ntohl(*p++); | ||
288 | args->csa_slotid = ntohl(*p++); | ||
289 | args->csa_highestslotid = ntohl(*p++); | ||
290 | args->csa_cachethis = ntohl(*p++); | ||
291 | args->csa_nrclists = ntohl(*p++); | ||
292 | args->csa_rclists = NULL; | ||
293 | if (args->csa_nrclists) { | ||
294 | args->csa_rclists = kmalloc(args->csa_nrclists * | ||
295 | sizeof(*args->csa_rclists), | ||
296 | GFP_KERNEL); | ||
297 | if (unlikely(args->csa_rclists == NULL)) | ||
298 | goto out; | ||
299 | |||
300 | for (i = 0; i < args->csa_nrclists; i++) { | ||
301 | status = decode_rc_list(xdr, &args->csa_rclists[i]); | ||
302 | if (status) | ||
303 | goto out_free; | ||
304 | } | ||
305 | } | ||
306 | status = 0; | ||
307 | |||
308 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u " | ||
309 | "highestslotid %u cachethis %d nrclists %u\n", | ||
310 | __func__, | ||
311 | ((u32 *)&args->csa_sessionid)[0], | ||
312 | ((u32 *)&args->csa_sessionid)[1], | ||
313 | ((u32 *)&args->csa_sessionid)[2], | ||
314 | ((u32 *)&args->csa_sessionid)[3], | ||
315 | args->csa_sequenceid, args->csa_slotid, | ||
316 | args->csa_highestslotid, args->csa_cachethis, | ||
317 | args->csa_nrclists); | ||
318 | out: | ||
319 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
320 | return status; | ||
321 | |||
322 | out_free: | ||
323 | for (i = 0; i < args->csa_nrclists; i++) | ||
324 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
325 | kfree(args->csa_rclists); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | #endif /* CONFIG_NFS_V4_1 */ | ||
330 | |||
207 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 331 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
208 | { | 332 | { |
209 | __be32 *p; | 333 | __be32 *p; |
@@ -353,31 +477,134 @@ out: | |||
353 | return status; | 477 | return status; |
354 | } | 478 | } |
355 | 479 | ||
356 | static __be32 process_op(struct svc_rqst *rqstp, | 480 | #if defined(CONFIG_NFS_V4_1) |
481 | |||
482 | static unsigned encode_sessionid(struct xdr_stream *xdr, | ||
483 | const struct nfs4_sessionid *sid) | ||
484 | { | ||
485 | uint32_t *p; | ||
486 | int len = NFS4_MAX_SESSIONID_LEN; | ||
487 | |||
488 | p = xdr_reserve_space(xdr, len); | ||
489 | if (unlikely(p == NULL)) | ||
490 | return htonl(NFS4ERR_RESOURCE); | ||
491 | |||
492 | memcpy(p, sid, len); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | ||
497 | struct xdr_stream *xdr, | ||
498 | const struct cb_sequenceres *res) | ||
499 | { | ||
500 | uint32_t *p; | ||
501 | unsigned status = res->csr_status; | ||
502 | |||
503 | if (unlikely(status != 0)) | ||
504 | goto out; | ||
505 | |||
506 | encode_sessionid(xdr, &res->csr_sessionid); | ||
507 | |||
508 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); | ||
509 | if (unlikely(p == NULL)) | ||
510 | return htonl(NFS4ERR_RESOURCE); | ||
511 | |||
512 | *p++ = htonl(res->csr_sequenceid); | ||
513 | *p++ = htonl(res->csr_slotid); | ||
514 | *p++ = htonl(res->csr_highestslotid); | ||
515 | *p++ = htonl(res->csr_target_highestslotid); | ||
516 | out: | ||
517 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
518 | return status; | ||
519 | } | ||
520 | |||
521 | static __be32 | ||
522 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
523 | { | ||
524 | if (op_nr == OP_CB_SEQUENCE) { | ||
525 | if (nop != 0) | ||
526 | return htonl(NFS4ERR_SEQUENCE_POS); | ||
527 | } else { | ||
528 | if (nop == 0) | ||
529 | return htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
530 | } | ||
531 | |||
532 | switch (op_nr) { | ||
533 | case OP_CB_GETATTR: | ||
534 | case OP_CB_RECALL: | ||
535 | case OP_CB_SEQUENCE: | ||
536 | *op = &callback_ops[op_nr]; | ||
537 | break; | ||
538 | |||
539 | case OP_CB_LAYOUTRECALL: | ||
540 | case OP_CB_NOTIFY_DEVICEID: | ||
541 | case OP_CB_NOTIFY: | ||
542 | case OP_CB_PUSH_DELEG: | ||
543 | case OP_CB_RECALL_ANY: | ||
544 | case OP_CB_RECALLABLE_OBJ_AVAIL: | ||
545 | case OP_CB_RECALL_SLOT: | ||
546 | case OP_CB_WANTS_CANCELLED: | ||
547 | case OP_CB_NOTIFY_LOCK: | ||
548 | return htonl(NFS4ERR_NOTSUPP); | ||
549 | |||
550 | default: | ||
551 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
552 | } | ||
553 | |||
554 | return htonl(NFS_OK); | ||
555 | } | ||
556 | |||
557 | #else /* CONFIG_NFS_V4_1 */ | ||
558 | |||
559 | static __be32 | ||
560 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
561 | { | ||
562 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
563 | } | ||
564 | |||
565 | #endif /* CONFIG_NFS_V4_1 */ | ||
566 | |||
567 | static __be32 | ||
568 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | ||
569 | { | ||
570 | switch (op_nr) { | ||
571 | case OP_CB_GETATTR: | ||
572 | case OP_CB_RECALL: | ||
573 | *op = &callback_ops[op_nr]; | ||
574 | break; | ||
575 | default: | ||
576 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
577 | } | ||
578 | |||
579 | return htonl(NFS_OK); | ||
580 | } | ||
581 | |||
582 | static __be32 process_op(uint32_t minorversion, int nop, | ||
583 | struct svc_rqst *rqstp, | ||
357 | struct xdr_stream *xdr_in, void *argp, | 584 | struct xdr_stream *xdr_in, void *argp, |
358 | struct xdr_stream *xdr_out, void *resp) | 585 | struct xdr_stream *xdr_out, void *resp) |
359 | { | 586 | { |
360 | struct callback_op *op = &callback_ops[0]; | 587 | struct callback_op *op = &callback_ops[0]; |
361 | unsigned int op_nr = OP_CB_ILLEGAL; | 588 | unsigned int op_nr = OP_CB_ILLEGAL; |
362 | __be32 status = 0; | 589 | __be32 status; |
363 | long maxlen; | 590 | long maxlen; |
364 | __be32 res; | 591 | __be32 res; |
365 | 592 | ||
366 | dprintk("%s: start\n", __func__); | 593 | dprintk("%s: start\n", __func__); |
367 | status = decode_op_hdr(xdr_in, &op_nr); | 594 | status = decode_op_hdr(xdr_in, &op_nr); |
368 | if (likely(status == 0)) { | 595 | if (unlikely(status)) { |
369 | switch (op_nr) { | 596 | status = htonl(NFS4ERR_OP_ILLEGAL); |
370 | case OP_CB_GETATTR: | 597 | goto out; |
371 | case OP_CB_RECALL: | ||
372 | op = &callback_ops[op_nr]; | ||
373 | break; | ||
374 | default: | ||
375 | op_nr = OP_CB_ILLEGAL; | ||
376 | op = &callback_ops[0]; | ||
377 | status = htonl(NFS4ERR_OP_ILLEGAL); | ||
378 | } | ||
379 | } | 598 | } |
380 | 599 | ||
600 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | ||
601 | __func__, minorversion, nop, op_nr); | ||
602 | |||
603 | status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||
604 | preprocess_nfs4_op(op_nr, &op); | ||
605 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | ||
606 | op_nr = OP_CB_ILLEGAL; | ||
607 | out: | ||
381 | maxlen = xdr_out->end - xdr_out->p; | 608 | maxlen = xdr_out->end - xdr_out->p; |
382 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 609 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
383 | if (likely(status == 0 && op->decode_args != NULL)) | 610 | if (likely(status == 0 && op->decode_args != NULL)) |
@@ -425,7 +652,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
425 | return rpc_system_err; | 652 | return rpc_system_err; |
426 | 653 | ||
427 | while (status == 0 && nops != hdr_arg.nops) { | 654 | while (status == 0 && nops != hdr_arg.nops) { |
428 | status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); | 655 | status = process_op(hdr_arg.minorversion, nops, |
656 | rqstp, &xdr_in, argp, &xdr_out, resp); | ||
429 | nops++; | 657 | nops++; |
430 | } | 658 | } |
431 | 659 | ||
@@ -452,7 +680,15 @@ static struct callback_op callback_ops[] = { | |||
452 | .process_op = (callback_process_op_t)nfs4_callback_recall, | 680 | .process_op = (callback_process_op_t)nfs4_callback_recall, |
453 | .decode_args = (callback_decode_arg_t)decode_recall_args, | 681 | .decode_args = (callback_decode_arg_t)decode_recall_args, |
454 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, | 682 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, |
455 | } | 683 | }, |
684 | #if defined(CONFIG_NFS_V4_1) | ||
685 | [OP_CB_SEQUENCE] = { | ||
686 | .process_op = (callback_process_op_t)nfs4_callback_sequence, | ||
687 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, | ||
688 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, | ||
689 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, | ||
690 | }, | ||
691 | #endif /* CONFIG_NFS_V4_1 */ | ||
456 | }; | 692 | }; |
457 | 693 | ||
458 | /* | 694 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 75c9cd2aa119..8d25ccb2d51d 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
39 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
40 | #include <linux/sunrpc/bc_xprt.h> | ||
40 | 41 | ||
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
42 | 43 | ||
@@ -102,6 +103,7 @@ struct nfs_client_initdata { | |||
102 | size_t addrlen; | 103 | size_t addrlen; |
103 | const struct nfs_rpc_ops *rpc_ops; | 104 | const struct nfs_rpc_ops *rpc_ops; |
104 | int proto; | 105 | int proto; |
106 | u32 minorversion; | ||
105 | }; | 107 | }; |
106 | 108 | ||
107 | /* | 109 | /* |
@@ -114,18 +116,13 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
114 | { | 116 | { |
115 | struct nfs_client *clp; | 117 | struct nfs_client *clp; |
116 | struct rpc_cred *cred; | 118 | struct rpc_cred *cred; |
119 | int err = -ENOMEM; | ||
117 | 120 | ||
118 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) | 121 | if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL) |
119 | goto error_0; | 122 | goto error_0; |
120 | 123 | ||
121 | clp->rpc_ops = cl_init->rpc_ops; | 124 | clp->rpc_ops = cl_init->rpc_ops; |
122 | 125 | ||
123 | if (cl_init->rpc_ops->version == 4) { | ||
124 | if (nfs_callback_up() < 0) | ||
125 | goto error_2; | ||
126 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
127 | } | ||
128 | |||
129 | atomic_set(&clp->cl_count, 1); | 126 | atomic_set(&clp->cl_count, 1); |
130 | clp->cl_cons_state = NFS_CS_INITING; | 127 | clp->cl_cons_state = NFS_CS_INITING; |
131 | 128 | ||
@@ -133,9 +130,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
133 | clp->cl_addrlen = cl_init->addrlen; | 130 | clp->cl_addrlen = cl_init->addrlen; |
134 | 131 | ||
135 | if (cl_init->hostname) { | 132 | if (cl_init->hostname) { |
133 | err = -ENOMEM; | ||
136 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
137 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
138 | goto error_3; | 136 | goto error_cleanup; |
139 | } | 137 | } |
140 | 138 | ||
141 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
@@ -150,6 +148,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
150 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 148 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
151 | clp->cl_boot_time = CURRENT_TIME; | 149 | clp->cl_boot_time = CURRENT_TIME; |
152 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 150 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
151 | clp->cl_minorversion = cl_init->minorversion; | ||
153 | #endif | 152 | #endif |
154 | cred = rpc_lookup_machine_cred(); | 153 | cred = rpc_lookup_machine_cred(); |
155 | if (!IS_ERR(cred)) | 154 | if (!IS_ERR(cred)) |
@@ -159,13 +158,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
159 | 158 | ||
160 | return clp; | 159 | return clp; |
161 | 160 | ||
162 | error_3: | 161 | error_cleanup: |
163 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
164 | nfs_callback_down(); | ||
165 | error_2: | ||
166 | kfree(clp); | 162 | kfree(clp); |
167 | error_0: | 163 | error_0: |
168 | return NULL; | 164 | return ERR_PTR(err); |
169 | } | 165 | } |
170 | 166 | ||
171 | static void nfs4_shutdown_client(struct nfs_client *clp) | 167 | static void nfs4_shutdown_client(struct nfs_client *clp) |
@@ -182,12 +178,42 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
182 | } | 178 | } |
183 | 179 | ||
184 | /* | 180 | /* |
181 | * Destroy the NFS4 callback service | ||
182 | */ | ||
183 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
184 | { | ||
185 | #ifdef CONFIG_NFS_V4 | ||
186 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
187 | nfs_callback_down(clp->cl_minorversion); | ||
188 | #endif /* CONFIG_NFS_V4 */ | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Clears/puts all minor version specific parts from an nfs_client struct | ||
193 | * reverting it to minorversion 0. | ||
194 | */ | ||
195 | static void nfs4_clear_client_minor_version(struct nfs_client *clp) | ||
196 | { | ||
197 | #ifdef CONFIG_NFS_V4_1 | ||
198 | if (nfs4_has_session(clp)) { | ||
199 | nfs4_destroy_session(clp->cl_session); | ||
200 | clp->cl_session = NULL; | ||
201 | } | ||
202 | |||
203 | clp->cl_call_sync = _nfs4_call_sync; | ||
204 | #endif /* CONFIG_NFS_V4_1 */ | ||
205 | |||
206 | nfs4_destroy_callback(clp); | ||
207 | } | ||
208 | |||
209 | /* | ||
185 | * Destroy a shared client record | 210 | * Destroy a shared client record |
186 | */ | 211 | */ |
187 | static void nfs_free_client(struct nfs_client *clp) | 212 | static void nfs_free_client(struct nfs_client *clp) |
188 | { | 213 | { |
189 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 214 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
190 | 215 | ||
216 | nfs4_clear_client_minor_version(clp); | ||
191 | nfs4_shutdown_client(clp); | 217 | nfs4_shutdown_client(clp); |
192 | 218 | ||
193 | nfs_fscache_release_client_cookie(clp); | 219 | nfs_fscache_release_client_cookie(clp); |
@@ -196,9 +222,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
196 | if (!IS_ERR(clp->cl_rpcclient)) | 222 | if (!IS_ERR(clp->cl_rpcclient)) |
197 | rpc_shutdown_client(clp->cl_rpcclient); | 223 | rpc_shutdown_client(clp->cl_rpcclient); |
198 | 224 | ||
199 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
200 | nfs_callback_down(); | ||
201 | |||
202 | if (clp->cl_machine_cred != NULL) | 225 | if (clp->cl_machine_cred != NULL) |
203 | put_rpccred(clp->cl_machine_cred); | 226 | put_rpccred(clp->cl_machine_cred); |
204 | 227 | ||
@@ -347,7 +370,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
347 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 370 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
348 | 371 | ||
349 | /* Don't match clients that failed to initialise properly */ | 372 | /* Don't match clients that failed to initialise properly */ |
350 | if (clp->cl_cons_state != NFS_CS_READY) | 373 | if (!(clp->cl_cons_state == NFS_CS_READY || |
374 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
351 | continue; | 375 | continue; |
352 | 376 | ||
353 | /* Different NFS versions cannot share the same nfs_client */ | 377 | /* Different NFS versions cannot share the same nfs_client */ |
@@ -420,7 +444,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
420 | 444 | ||
421 | if (clp->cl_proto != data->proto) | 445 | if (clp->cl_proto != data->proto) |
422 | continue; | 446 | continue; |
423 | 447 | /* Match nfsv4 minorversion */ | |
448 | if (clp->cl_minorversion != data->minorversion) | ||
449 | continue; | ||
424 | /* Match the full socket address */ | 450 | /* Match the full socket address */ |
425 | if (!nfs_sockaddr_cmp(sap, clap)) | 451 | if (!nfs_sockaddr_cmp(sap, clap)) |
426 | continue; | 452 | continue; |
@@ -456,9 +482,10 @@ static struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_in | |||
456 | spin_unlock(&nfs_client_lock); | 482 | spin_unlock(&nfs_client_lock); |
457 | 483 | ||
458 | new = nfs_alloc_client(cl_init); | 484 | new = nfs_alloc_client(cl_init); |
459 | } while (new); | 485 | } while (!IS_ERR(new)); |
460 | 486 | ||
461 | return ERR_PTR(-ENOMEM); | 487 | dprintk("--> nfs_get_client() = %ld [failed]\n", PTR_ERR(new)); |
488 | return new; | ||
462 | 489 | ||
463 | /* install a new client and return with it unready */ | 490 | /* install a new client and return with it unready */ |
464 | install_client: | 491 | install_client: |
@@ -478,7 +505,7 @@ found_client: | |||
478 | nfs_free_client(new); | 505 | nfs_free_client(new); |
479 | 506 | ||
480 | error = wait_event_killable(nfs_client_active_wq, | 507 | error = wait_event_killable(nfs_client_active_wq, |
481 | clp->cl_cons_state != NFS_CS_INITING); | 508 | clp->cl_cons_state < NFS_CS_INITING); |
482 | if (error < 0) { | 509 | if (error < 0) { |
483 | nfs_put_client(clp); | 510 | nfs_put_client(clp); |
484 | return ERR_PTR(-ERESTARTSYS); | 511 | return ERR_PTR(-ERESTARTSYS); |
@@ -499,13 +526,29 @@ found_client: | |||
499 | /* | 526 | /* |
500 | * Mark a server as ready or failed | 527 | * Mark a server as ready or failed |
501 | */ | 528 | */ |
502 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | 529 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
503 | { | 530 | { |
504 | clp->cl_cons_state = state; | 531 | clp->cl_cons_state = state; |
505 | wake_up_all(&nfs_client_active_wq); | 532 | wake_up_all(&nfs_client_active_wq); |
506 | } | 533 | } |
507 | 534 | ||
508 | /* | 535 | /* |
536 | * With sessions, the client is not marked ready until after a | ||
537 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
538 | * | ||
539 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
540 | * other versions of NFS can be tried. | ||
541 | */ | ||
542 | int nfs4_check_client_ready(struct nfs_client *clp) | ||
543 | { | ||
544 | if (!nfs4_has_session(clp)) | ||
545 | return 0; | ||
546 | if (clp->cl_cons_state < NFS_CS_READY) | ||
547 | return -EPROTONOSUPPORT; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /* | ||
509 | * Initialise the timeout values for a connection | 552 | * Initialise the timeout values for a connection |
510 | */ | 553 | */ |
511 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 554 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
@@ -1050,6 +1093,61 @@ error: | |||
1050 | 1093 | ||
1051 | #ifdef CONFIG_NFS_V4 | 1094 | #ifdef CONFIG_NFS_V4 |
1052 | /* | 1095 | /* |
1096 | * Initialize the NFS4 callback service | ||
1097 | */ | ||
1098 | static int nfs4_init_callback(struct nfs_client *clp) | ||
1099 | { | ||
1100 | int error; | ||
1101 | |||
1102 | if (clp->rpc_ops->version == 4) { | ||
1103 | if (nfs4_has_session(clp)) { | ||
1104 | error = xprt_setup_backchannel( | ||
1105 | clp->cl_rpcclient->cl_xprt, | ||
1106 | NFS41_BC_MIN_CALLBACKS); | ||
1107 | if (error < 0) | ||
1108 | return error; | ||
1109 | } | ||
1110 | |||
1111 | error = nfs_callback_up(clp->cl_minorversion, | ||
1112 | clp->cl_rpcclient->cl_xprt); | ||
1113 | if (error < 0) { | ||
1114 | dprintk("%s: failed to start callback. Error = %d\n", | ||
1115 | __func__, error); | ||
1116 | return error; | ||
1117 | } | ||
1118 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
1119 | } | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Initialize the minor version specific parts of an NFS4 client record | ||
1125 | */ | ||
1126 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
1127 | { | ||
1128 | clp->cl_call_sync = _nfs4_call_sync; | ||
1129 | |||
1130 | #if defined(CONFIG_NFS_V4_1) | ||
1131 | if (clp->cl_minorversion) { | ||
1132 | struct nfs4_session *session = NULL; | ||
1133 | /* | ||
1134 | * Create the session and mark it expired. | ||
1135 | * When a SEQUENCE operation encounters the expired session | ||
1136 | * it will do session recovery to initialize it. | ||
1137 | */ | ||
1138 | session = nfs4_alloc_session(clp); | ||
1139 | if (!session) | ||
1140 | return -ENOMEM; | ||
1141 | |||
1142 | clp->cl_session = session; | ||
1143 | clp->cl_call_sync = _nfs4_call_sync_session; | ||
1144 | } | ||
1145 | #endif /* CONFIG_NFS_V4_1 */ | ||
1146 | |||
1147 | return nfs4_init_callback(clp); | ||
1148 | } | ||
1149 | |||
1150 | /* | ||
1053 | * Initialise an NFS4 client record | 1151 | * Initialise an NFS4 client record |
1054 | */ | 1152 | */ |
1055 | static int nfs4_init_client(struct nfs_client *clp, | 1153 | static int nfs4_init_client(struct nfs_client *clp, |
@@ -1083,7 +1181,12 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
1083 | } | 1181 | } |
1084 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | 1182 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); |
1085 | 1183 | ||
1086 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1184 | error = nfs4_init_client_minor_version(clp); |
1185 | if (error < 0) | ||
1186 | goto error; | ||
1187 | |||
1188 | if (!nfs4_has_session(clp)) | ||
1189 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1087 | return 0; | 1190 | return 0; |
1088 | 1191 | ||
1089 | error: | 1192 | error: |
@@ -1101,7 +1204,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1101 | const size_t addrlen, | 1204 | const size_t addrlen, |
1102 | const char *ip_addr, | 1205 | const char *ip_addr, |
1103 | rpc_authflavor_t authflavour, | 1206 | rpc_authflavor_t authflavour, |
1104 | int proto, const struct rpc_timeout *timeparms) | 1207 | int proto, const struct rpc_timeout *timeparms, |
1208 | u32 minorversion) | ||
1105 | { | 1209 | { |
1106 | struct nfs_client_initdata cl_init = { | 1210 | struct nfs_client_initdata cl_init = { |
1107 | .hostname = hostname, | 1211 | .hostname = hostname, |
@@ -1109,6 +1213,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1109 | .addrlen = addrlen, | 1213 | .addrlen = addrlen, |
1110 | .rpc_ops = &nfs_v4_clientops, | 1214 | .rpc_ops = &nfs_v4_clientops, |
1111 | .proto = proto, | 1215 | .proto = proto, |
1216 | .minorversion = minorversion, | ||
1112 | }; | 1217 | }; |
1113 | struct nfs_client *clp; | 1218 | struct nfs_client *clp; |
1114 | int error; | 1219 | int error; |
@@ -1137,6 +1242,22 @@ error: | |||
1137 | return error; | 1242 | return error; |
1138 | } | 1243 | } |
1139 | 1244 | ||
1245 | |||
1246 | /* | ||
1247 | * Session has been established, and the client marked ready. | ||
1248 | * Set the mount rsize and wsize with negotiated fore channel | ||
1249 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
1250 | */ | ||
1251 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
1252 | { | ||
1253 | #ifdef CONFIG_NFS_V4_1 | ||
1254 | if (!nfs4_has_session(server->nfs_client)) | ||
1255 | return; | ||
1256 | server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
1257 | server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; | ||
1258 | #endif /* CONFIG_NFS_V4_1 */ | ||
1259 | } | ||
1260 | |||
1140 | /* | 1261 | /* |
1141 | * Create a version 4 volume record | 1262 | * Create a version 4 volume record |
1142 | */ | 1263 | */ |
@@ -1164,7 +1285,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1164 | data->client_address, | 1285 | data->client_address, |
1165 | data->auth_flavors[0], | 1286 | data->auth_flavors[0], |
1166 | data->nfs_server.protocol, | 1287 | data->nfs_server.protocol, |
1167 | &timeparms); | 1288 | &timeparms, |
1289 | data->minorversion); | ||
1168 | if (error < 0) | 1290 | if (error < 0) |
1169 | goto error; | 1291 | goto error; |
1170 | 1292 | ||
@@ -1214,6 +1336,10 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1214 | BUG_ON(!server->nfs_client->rpc_ops); | 1336 | BUG_ON(!server->nfs_client->rpc_ops); |
1215 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1337 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1216 | 1338 | ||
1339 | error = nfs4_init_session(server); | ||
1340 | if (error < 0) | ||
1341 | goto error; | ||
1342 | |||
1217 | /* Probe the root fh to retrieve its FSID */ | 1343 | /* Probe the root fh to retrieve its FSID */ |
1218 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | 1344 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); |
1219 | if (error < 0) | 1345 | if (error < 0) |
@@ -1224,6 +1350,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1224 | (unsigned long long) server->fsid.minor); | 1350 | (unsigned long long) server->fsid.minor); |
1225 | dprintk("Mount FH: %d\n", mntfh->size); | 1351 | dprintk("Mount FH: %d\n", mntfh->size); |
1226 | 1352 | ||
1353 | nfs4_session_set_rwsize(server); | ||
1354 | |||
1227 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1355 | error = nfs_probe_fsinfo(server, mntfh, &fattr); |
1228 | if (error < 0) | 1356 | if (error < 0) |
1229 | goto error; | 1357 | goto error; |
@@ -1282,7 +1410,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1282 | parent_client->cl_ipaddr, | 1410 | parent_client->cl_ipaddr, |
1283 | data->authflavor, | 1411 | data->authflavor, |
1284 | parent_server->client->cl_xprt->prot, | 1412 | parent_server->client->cl_xprt->prot, |
1285 | parent_server->client->cl_timeout); | 1413 | parent_server->client->cl_timeout, |
1414 | parent_client->cl_minorversion); | ||
1286 | if (error < 0) | 1415 | if (error < 0) |
1287 | goto error; | 1416 | goto error; |
1288 | 1417 | ||
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 968225a88015..6dd48a4405b4 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kthread.h> | 10 | #include <linux/kthread.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/smp_lock.h> | ||
13 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
14 | 15 | ||
15 | #include <linux/nfs4.h> | 16 | #include <linux/nfs4.h> |
@@ -68,29 +69,26 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
68 | { | 69 | { |
69 | struct inode *inode = state->inode; | 70 | struct inode *inode = state->inode; |
70 | struct file_lock *fl; | 71 | struct file_lock *fl; |
71 | int status; | 72 | int status = 0; |
73 | |||
74 | if (inode->i_flock == NULL) | ||
75 | goto out; | ||
72 | 76 | ||
77 | /* Protect inode->i_flock using the BKL */ | ||
78 | lock_kernel(); | ||
73 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 79 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
74 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 80 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
75 | continue; | 81 | continue; |
76 | if (nfs_file_open_context(fl->fl_file) != ctx) | 82 | if (nfs_file_open_context(fl->fl_file) != ctx) |
77 | continue; | 83 | continue; |
84 | unlock_kernel(); | ||
78 | status = nfs4_lock_delegation_recall(state, fl); | 85 | status = nfs4_lock_delegation_recall(state, fl); |
79 | if (status >= 0) | 86 | if (status < 0) |
80 | continue; | 87 | goto out; |
81 | switch (status) { | 88 | lock_kernel(); |
82 | default: | ||
83 | printk(KERN_ERR "%s: unhandled error %d.\n", | ||
84 | __func__, status); | ||
85 | case -NFS4ERR_EXPIRED: | ||
86 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
87 | case -NFS4ERR_STALE_CLIENTID: | ||
88 | nfs4_schedule_state_recovery(NFS_SERVER(inode)->nfs_client); | ||
89 | goto out_err; | ||
90 | } | ||
91 | } | 89 | } |
92 | return 0; | 90 | unlock_kernel(); |
93 | out_err: | 91 | out: |
94 | return status; | 92 | return status; |
95 | } | 93 | } |
96 | 94 | ||
@@ -268,7 +266,10 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat | |||
268 | struct nfs_inode *nfsi = NFS_I(inode); | 266 | struct nfs_inode *nfsi = NFS_I(inode); |
269 | 267 | ||
270 | nfs_msync_inode(inode); | 268 | nfs_msync_inode(inode); |
271 | /* Guard against new delegated open calls */ | 269 | /* |
270 | * Guard against new delegated open/lock/unlock calls and against | ||
271 | * state recovery | ||
272 | */ | ||
272 | down_write(&nfsi->rwsem); | 273 | down_write(&nfsi->rwsem); |
273 | nfs_delegation_claim_opens(inode, &delegation->stateid); | 274 | nfs_delegation_claim_opens(inode, &delegation->stateid); |
274 | up_write(&nfsi->rwsem); | 275 | up_write(&nfsi->rwsem); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 89f98e9a024b..32062c33c859 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/nfs_fs.h> | 29 | #include <linux/nfs_fs.h> |
30 | #include <linux/nfs_mount.h> | 30 | #include <linux/nfs_mount.h> |
31 | #include <linux/pagemap.h> | 31 | #include <linux/pagemap.h> |
32 | #include <linux/smp_lock.h> | ||
33 | #include <linux/pagevec.h> | 32 | #include <linux/pagevec.h> |
34 | #include <linux/namei.h> | 33 | #include <linux/namei.h> |
35 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
@@ -1026,12 +1025,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1026 | res = NULL; | 1025 | res = NULL; |
1027 | goto out; | 1026 | goto out; |
1028 | /* This turned out not to be a regular file */ | 1027 | /* This turned out not to be a regular file */ |
1029 | case -EISDIR: | ||
1030 | case -ENOTDIR: | 1028 | case -ENOTDIR: |
1031 | goto no_open; | 1029 | goto no_open; |
1032 | case -ELOOP: | 1030 | case -ELOOP: |
1033 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1031 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
1034 | goto no_open; | 1032 | goto no_open; |
1033 | /* case -EISDIR: */ | ||
1035 | /* case -EINVAL: */ | 1034 | /* case -EINVAL: */ |
1036 | default: | 1035 | default: |
1037 | goto out; | 1036 | goto out; |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 08f6b040d289..e4e089a8f294 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -255,10 +255,13 @@ static void nfs_direct_read_release(void *calldata) | |||
255 | 255 | ||
256 | if (put_dreq(dreq)) | 256 | if (put_dreq(dreq)) |
257 | nfs_direct_complete(dreq); | 257 | nfs_direct_complete(dreq); |
258 | nfs_readdata_release(calldata); | 258 | nfs_readdata_free(data); |
259 | } | 259 | } |
260 | 260 | ||
261 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
262 | #if defined(CONFIG_NFS_V4_1) | ||
263 | .rpc_call_prepare = nfs_read_prepare, | ||
264 | #endif /* CONFIG_NFS_V4_1 */ | ||
262 | .rpc_call_done = nfs_direct_read_result, | 265 | .rpc_call_done = nfs_direct_read_result, |
263 | .rpc_release = nfs_direct_read_release, | 266 | .rpc_release = nfs_direct_read_release, |
264 | }; | 267 | }; |
@@ -311,14 +314,14 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
311 | data->npages, 1, 0, data->pagevec, NULL); | 314 | data->npages, 1, 0, data->pagevec, NULL); |
312 | up_read(¤t->mm->mmap_sem); | 315 | up_read(¤t->mm->mmap_sem); |
313 | if (result < 0) { | 316 | if (result < 0) { |
314 | nfs_readdata_release(data); | 317 | nfs_readdata_free(data); |
315 | break; | 318 | break; |
316 | } | 319 | } |
317 | if ((unsigned)result < data->npages) { | 320 | if ((unsigned)result < data->npages) { |
318 | bytes = result * PAGE_SIZE; | 321 | bytes = result * PAGE_SIZE; |
319 | if (bytes <= pgbase) { | 322 | if (bytes <= pgbase) { |
320 | nfs_direct_release_pages(data->pagevec, result); | 323 | nfs_direct_release_pages(data->pagevec, result); |
321 | nfs_readdata_release(data); | 324 | nfs_readdata_free(data); |
322 | break; | 325 | break; |
323 | } | 326 | } |
324 | bytes -= pgbase; | 327 | bytes -= pgbase; |
@@ -331,7 +334,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
331 | data->inode = inode; | 334 | data->inode = inode; |
332 | data->cred = msg.rpc_cred; | 335 | data->cred = msg.rpc_cred; |
333 | data->args.fh = NFS_FH(inode); | 336 | data->args.fh = NFS_FH(inode); |
334 | data->args.context = get_nfs_open_context(ctx); | 337 | data->args.context = ctx; |
335 | data->args.offset = pos; | 338 | data->args.offset = pos; |
336 | data->args.pgbase = pgbase; | 339 | data->args.pgbase = pgbase; |
337 | data->args.pages = data->pagevec; | 340 | data->args.pages = data->pagevec; |
@@ -438,7 +441,7 @@ static void nfs_direct_free_writedata(struct nfs_direct_req *dreq) | |||
438 | struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); | 441 | struct nfs_write_data *data = list_entry(dreq->rewrite_list.next, struct nfs_write_data, pages); |
439 | list_del(&data->pages); | 442 | list_del(&data->pages); |
440 | nfs_direct_release_pages(data->pagevec, data->npages); | 443 | nfs_direct_release_pages(data->pagevec, data->npages); |
441 | nfs_writedata_release(data); | 444 | nfs_writedata_free(data); |
442 | } | 445 | } |
443 | } | 446 | } |
444 | 447 | ||
@@ -531,10 +534,13 @@ static void nfs_direct_commit_release(void *calldata) | |||
531 | 534 | ||
532 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); | 535 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
533 | nfs_direct_write_complete(dreq, data->inode); | 536 | nfs_direct_write_complete(dreq, data->inode); |
534 | nfs_commitdata_release(calldata); | 537 | nfs_commit_free(data); |
535 | } | 538 | } |
536 | 539 | ||
537 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 540 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
541 | #if defined(CONFIG_NFS_V4_1) | ||
542 | .rpc_call_prepare = nfs_write_prepare, | ||
543 | #endif /* CONFIG_NFS_V4_1 */ | ||
538 | .rpc_call_done = nfs_direct_commit_result, | 544 | .rpc_call_done = nfs_direct_commit_result, |
539 | .rpc_release = nfs_direct_commit_release, | 545 | .rpc_release = nfs_direct_commit_release, |
540 | }; | 546 | }; |
@@ -564,7 +570,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
564 | data->args.fh = NFS_FH(data->inode); | 570 | data->args.fh = NFS_FH(data->inode); |
565 | data->args.offset = 0; | 571 | data->args.offset = 0; |
566 | data->args.count = 0; | 572 | data->args.count = 0; |
567 | data->args.context = get_nfs_open_context(dreq->ctx); | 573 | data->args.context = dreq->ctx; |
568 | data->res.count = 0; | 574 | data->res.count = 0; |
569 | data->res.fattr = &data->fattr; | 575 | data->res.fattr = &data->fattr; |
570 | data->res.verf = &data->verf; | 576 | data->res.verf = &data->verf; |
@@ -673,6 +679,9 @@ out_unlock: | |||
673 | } | 679 | } |
674 | 680 | ||
675 | static const struct rpc_call_ops nfs_write_direct_ops = { | 681 | static const struct rpc_call_ops nfs_write_direct_ops = { |
682 | #if defined(CONFIG_NFS_V4_1) | ||
683 | .rpc_call_prepare = nfs_write_prepare, | ||
684 | #endif /* CONFIG_NFS_V4_1 */ | ||
676 | .rpc_call_done = nfs_direct_write_result, | 685 | .rpc_call_done = nfs_direct_write_result, |
677 | .rpc_release = nfs_direct_write_release, | 686 | .rpc_release = nfs_direct_write_release, |
678 | }; | 687 | }; |
@@ -725,14 +734,14 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
725 | data->npages, 0, 0, data->pagevec, NULL); | 734 | data->npages, 0, 0, data->pagevec, NULL); |
726 | up_read(¤t->mm->mmap_sem); | 735 | up_read(¤t->mm->mmap_sem); |
727 | if (result < 0) { | 736 | if (result < 0) { |
728 | nfs_writedata_release(data); | 737 | nfs_writedata_free(data); |
729 | break; | 738 | break; |
730 | } | 739 | } |
731 | if ((unsigned)result < data->npages) { | 740 | if ((unsigned)result < data->npages) { |
732 | bytes = result * PAGE_SIZE; | 741 | bytes = result * PAGE_SIZE; |
733 | if (bytes <= pgbase) { | 742 | if (bytes <= pgbase) { |
734 | nfs_direct_release_pages(data->pagevec, result); | 743 | nfs_direct_release_pages(data->pagevec, result); |
735 | nfs_writedata_release(data); | 744 | nfs_writedata_free(data); |
736 | break; | 745 | break; |
737 | } | 746 | } |
738 | bytes -= pgbase; | 747 | bytes -= pgbase; |
@@ -747,7 +756,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
747 | data->inode = inode; | 756 | data->inode = inode; |
748 | data->cred = msg.rpc_cred; | 757 | data->cred = msg.rpc_cred; |
749 | data->args.fh = NFS_FH(inode); | 758 | data->args.fh = NFS_FH(inode); |
750 | data->args.context = get_nfs_open_context(ctx); | 759 | data->args.context = ctx; |
751 | data->args.offset = pos; | 760 | data->args.offset = pos; |
752 | data->args.pgbase = pgbase; | 761 | data->args.pgbase = pgbase; |
753 | data->args.pages = data->pagevec; | 762 | data->args.pages = data->pagevec; |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index ec7e27d00bc6..05062329b678 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
29 | #include <linux/smp_lock.h> | ||
30 | #include <linux/aio.h> | 29 | #include <linux/aio.h> |
31 | 30 | ||
32 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -48,6 +47,9 @@ static ssize_t nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
48 | size_t count, unsigned int flags); | 47 | size_t count, unsigned int flags); |
49 | static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, | 48 | static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov, |
50 | unsigned long nr_segs, loff_t pos); | 49 | unsigned long nr_segs, loff_t pos); |
50 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | ||
51 | struct file *filp, loff_t *ppos, | ||
52 | size_t count, unsigned int flags); | ||
51 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, | 53 | static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov, |
52 | unsigned long nr_segs, loff_t pos); | 54 | unsigned long nr_segs, loff_t pos); |
53 | static int nfs_file_flush(struct file *, fl_owner_t id); | 55 | static int nfs_file_flush(struct file *, fl_owner_t id); |
@@ -73,6 +75,7 @@ const struct file_operations nfs_file_operations = { | |||
73 | .lock = nfs_lock, | 75 | .lock = nfs_lock, |
74 | .flock = nfs_flock, | 76 | .flock = nfs_flock, |
75 | .splice_read = nfs_file_splice_read, | 77 | .splice_read = nfs_file_splice_read, |
78 | .splice_write = nfs_file_splice_write, | ||
76 | .check_flags = nfs_check_flags, | 79 | .check_flags = nfs_check_flags, |
77 | .setlease = nfs_setlease, | 80 | .setlease = nfs_setlease, |
78 | }; | 81 | }; |
@@ -587,12 +590,38 @@ out_swapfile: | |||
587 | goto out; | 590 | goto out; |
588 | } | 591 | } |
589 | 592 | ||
593 | static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | ||
594 | struct file *filp, loff_t *ppos, | ||
595 | size_t count, unsigned int flags) | ||
596 | { | ||
597 | struct dentry *dentry = filp->f_path.dentry; | ||
598 | struct inode *inode = dentry->d_inode; | ||
599 | ssize_t ret; | ||
600 | |||
601 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", | ||
602 | dentry->d_parent->d_name.name, dentry->d_name.name, | ||
603 | (unsigned long) count, (unsigned long long) *ppos); | ||
604 | |||
605 | /* | ||
606 | * The combination of splice and an O_APPEND destination is disallowed. | ||
607 | */ | ||
608 | |||
609 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
610 | |||
611 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); | ||
612 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | ||
613 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | ||
614 | if (err < 0) | ||
615 | ret = err; | ||
616 | } | ||
617 | return ret; | ||
618 | } | ||
619 | |||
590 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | 620 | static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) |
591 | { | 621 | { |
592 | struct inode *inode = filp->f_mapping->host; | 622 | struct inode *inode = filp->f_mapping->host; |
593 | int status = 0; | 623 | int status = 0; |
594 | 624 | ||
595 | lock_kernel(); | ||
596 | /* Try local locking first */ | 625 | /* Try local locking first */ |
597 | posix_test_lock(filp, fl); | 626 | posix_test_lock(filp, fl); |
598 | if (fl->fl_type != F_UNLCK) { | 627 | if (fl->fl_type != F_UNLCK) { |
@@ -608,7 +637,6 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl) | |||
608 | 637 | ||
609 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 638 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
610 | out: | 639 | out: |
611 | unlock_kernel(); | ||
612 | return status; | 640 | return status; |
613 | out_noconflict: | 641 | out_noconflict: |
614 | fl->fl_type = F_UNLCK; | 642 | fl->fl_type = F_UNLCK; |
@@ -650,13 +678,11 @@ static int do_unlk(struct file *filp, int cmd, struct file_lock *fl) | |||
650 | * If we're signalled while cleaning up locks on process exit, we | 678 | * If we're signalled while cleaning up locks on process exit, we |
651 | * still need to complete the unlock. | 679 | * still need to complete the unlock. |
652 | */ | 680 | */ |
653 | lock_kernel(); | ||
654 | /* Use local locking if mounted with "-onolock" */ | 681 | /* Use local locking if mounted with "-onolock" */ |
655 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) | 682 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
656 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 683 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
657 | else | 684 | else |
658 | status = do_vfs_lock(filp, fl); | 685 | status = do_vfs_lock(filp, fl); |
659 | unlock_kernel(); | ||
660 | return status; | 686 | return status; |
661 | } | 687 | } |
662 | 688 | ||
@@ -673,13 +699,11 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl) | |||
673 | if (status != 0) | 699 | if (status != 0) |
674 | goto out; | 700 | goto out; |
675 | 701 | ||
676 | lock_kernel(); | ||
677 | /* Use local locking if mounted with "-onolock" */ | 702 | /* Use local locking if mounted with "-onolock" */ |
678 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) | 703 | if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) |
679 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); | 704 | status = NFS_PROTO(inode)->lock(filp, cmd, fl); |
680 | else | 705 | else |
681 | status = do_vfs_lock(filp, fl); | 706 | status = do_vfs_lock(filp, fl); |
682 | unlock_kernel(); | ||
683 | if (status < 0) | 707 | if (status < 0) |
684 | goto out; | 708 | goto out; |
685 | /* | 709 | /* |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 46177cb87064..b35d2a616066 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/nfs_idmap.h> | 30 | #include <linux/nfs_idmap.h> |
31 | #include <linux/vfs.h> | 31 | #include <linux/vfs.h> |
32 | #include <linux/namei.h> | 32 | #include <linux/namei.h> |
33 | #include <linux/mnt_namespace.h> | ||
34 | #include <linux/security.h> | 33 | #include <linux/security.h> |
35 | 34 | ||
36 | #include <asm/system.h> | 35 | #include <asm/system.h> |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 64f87194d390..bd7938eda6a8 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/nfs_mount.h> | 30 | #include <linux/nfs_mount.h> |
31 | #include <linux/nfs4_mount.h> | 31 | #include <linux/nfs4_mount.h> |
32 | #include <linux/lockd/bind.h> | 32 | #include <linux/lockd/bind.h> |
33 | #include <linux/smp_lock.h> | ||
34 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
35 | #include <linux/mount.h> | 34 | #include <linux/mount.h> |
36 | #include <linux/nfs_idmap.h> | 35 | #include <linux/nfs_idmap.h> |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e4d6a8348adf..7dd90a6769d0 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * NFS internal definitions | 2 | * NFS internal definitions |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include "nfs4_fs.h" | ||
5 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
6 | #include <linux/security.h> | 7 | #include <linux/security.h> |
7 | 8 | ||
@@ -17,6 +18,18 @@ struct nfs_string; | |||
17 | */ | 18 | */ |
18 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | 19 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) |
19 | 20 | ||
21 | /* | ||
22 | * Determine if sessions are in use. | ||
23 | */ | ||
24 | static inline int nfs4_has_session(const struct nfs_client *clp) | ||
25 | { | ||
26 | #ifdef CONFIG_NFS_V4_1 | ||
27 | if (clp->cl_session) | ||
28 | return 1; | ||
29 | #endif /* CONFIG_NFS_V4_1 */ | ||
30 | return 0; | ||
31 | } | ||
32 | |||
20 | struct nfs_clone_mount { | 33 | struct nfs_clone_mount { |
21 | const struct super_block *sb; | 34 | const struct super_block *sb; |
22 | const struct dentry *dentry; | 35 | const struct dentry *dentry; |
@@ -30,6 +43,12 @@ struct nfs_clone_mount { | |||
30 | }; | 43 | }; |
31 | 44 | ||
32 | /* | 45 | /* |
46 | * Note: RFC 1813 doesn't limit the number of auth flavors that | ||
47 | * a server can return, so make something up. | ||
48 | */ | ||
49 | #define NFS_MAX_SECFLAVORS (12) | ||
50 | |||
51 | /* | ||
33 | * In-kernel mount arguments | 52 | * In-kernel mount arguments |
34 | */ | 53 | */ |
35 | struct nfs_parsed_mount_data { | 54 | struct nfs_parsed_mount_data { |
@@ -44,6 +63,7 @@ struct nfs_parsed_mount_data { | |||
44 | unsigned int auth_flavor_len; | 63 | unsigned int auth_flavor_len; |
45 | rpc_authflavor_t auth_flavors[1]; | 64 | rpc_authflavor_t auth_flavors[1]; |
46 | char *client_address; | 65 | char *client_address; |
66 | unsigned int minorversion; | ||
47 | char *fscache_uniq; | 67 | char *fscache_uniq; |
48 | 68 | ||
49 | struct { | 69 | struct { |
@@ -77,6 +97,8 @@ struct nfs_mount_request { | |||
77 | unsigned short protocol; | 97 | unsigned short protocol; |
78 | struct nfs_fh *fh; | 98 | struct nfs_fh *fh; |
79 | int noresvport; | 99 | int noresvport; |
100 | unsigned int *auth_flav_len; | ||
101 | rpc_authflavor_t *auth_flavs; | ||
80 | }; | 102 | }; |
81 | 103 | ||
82 | extern int nfs_mount(struct nfs_mount_request *info); | 104 | extern int nfs_mount(struct nfs_mount_request *info); |
@@ -99,6 +121,8 @@ extern void nfs_free_server(struct nfs_server *server); | |||
99 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 121 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
100 | struct nfs_fh *, | 122 | struct nfs_fh *, |
101 | struct nfs_fattr *); | 123 | struct nfs_fattr *); |
124 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | ||
125 | extern int nfs4_check_client_ready(struct nfs_client *clp); | ||
102 | #ifdef CONFIG_PROC_FS | 126 | #ifdef CONFIG_PROC_FS |
103 | extern int __init nfs_fs_proc_init(void); | 127 | extern int __init nfs_fs_proc_init(void); |
104 | extern void nfs_fs_proc_exit(void); | 128 | extern void nfs_fs_proc_exit(void); |
@@ -146,6 +170,20 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
146 | extern struct rpc_procinfo nfs3_procedures[]; | 170 | extern struct rpc_procinfo nfs3_procedures[]; |
147 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 171 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
148 | 172 | ||
173 | /* nfs4proc.c */ | ||
174 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
175 | const struct nfs_client *clp) | ||
176 | { | ||
177 | #ifdef CONFIG_NFS_V4_1 | ||
178 | if (nfs4_has_session(clp) && | ||
179 | test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
180 | rpc_restart_call_prepare(task); | ||
181 | return; | ||
182 | } | ||
183 | #endif /* CONFIG_NFS_V4_1 */ | ||
184 | rpc_restart_call(task); | ||
185 | } | ||
186 | |||
149 | /* nfs4xdr.c */ | 187 | /* nfs4xdr.c */ |
150 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
151 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 189 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
@@ -205,6 +243,38 @@ extern int nfs4_path_walk(struct nfs_server *server, | |||
205 | const char *path); | 243 | const char *path); |
206 | #endif | 244 | #endif |
207 | 245 | ||
246 | /* read.c */ | ||
247 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | ||
248 | |||
249 | /* write.c */ | ||
250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | ||
251 | |||
252 | /* nfs4proc.c */ | ||
253 | extern int _nfs4_call_sync(struct nfs_server *server, | ||
254 | struct rpc_message *msg, | ||
255 | struct nfs4_sequence_args *args, | ||
256 | struct nfs4_sequence_res *res, | ||
257 | int cache_reply); | ||
258 | extern int _nfs4_call_sync_session(struct nfs_server *server, | ||
259 | struct rpc_message *msg, | ||
260 | struct nfs4_sequence_args *args, | ||
261 | struct nfs4_sequence_res *res, | ||
262 | int cache_reply); | ||
263 | |||
264 | #ifdef CONFIG_NFS_V4_1 | ||
265 | extern void nfs41_sequence_free_slot(const struct nfs_client *, | ||
266 | struct nfs4_sequence_res *res); | ||
267 | #endif /* CONFIG_NFS_V4_1 */ | ||
268 | |||
269 | static inline void nfs4_sequence_free_slot(const struct nfs_client *clp, | ||
270 | struct nfs4_sequence_res *res) | ||
271 | { | ||
272 | #ifdef CONFIG_NFS_V4_1 | ||
273 | if (nfs4_has_session(clp)) | ||
274 | nfs41_sequence_free_slot(clp, res); | ||
275 | #endif /* CONFIG_NFS_V4_1 */ | ||
276 | } | ||
277 | |||
208 | /* | 278 | /* |
209 | * Determine the device name as a string | 279 | * Determine the device name as a string |
210 | */ | 280 | */ |
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h index a2ab2529b5ca..ceda50aad73c 100644 --- a/fs/nfs/iostat.h +++ b/fs/nfs/iostat.h | |||
@@ -31,7 +31,7 @@ static inline void nfs_inc_server_stats(const struct nfs_server *server, | |||
31 | cpu = get_cpu(); | 31 | cpu = get_cpu(); |
32 | iostats = per_cpu_ptr(server->io_stats, cpu); | 32 | iostats = per_cpu_ptr(server->io_stats, cpu); |
33 | iostats->events[stat]++; | 33 | iostats->events[stat]++; |
34 | put_cpu_no_resched(); | 34 | put_cpu(); |
35 | } | 35 | } |
36 | 36 | ||
37 | static inline void nfs_inc_stats(const struct inode *inode, | 37 | static inline void nfs_inc_stats(const struct inode *inode, |
@@ -50,7 +50,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server, | |||
50 | cpu = get_cpu(); | 50 | cpu = get_cpu(); |
51 | iostats = per_cpu_ptr(server->io_stats, cpu); | 51 | iostats = per_cpu_ptr(server->io_stats, cpu); |
52 | iostats->bytes[stat] += addend; | 52 | iostats->bytes[stat] += addend; |
53 | put_cpu_no_resched(); | 53 | put_cpu(); |
54 | } | 54 | } |
55 | 55 | ||
56 | static inline void nfs_add_stats(const struct inode *inode, | 56 | static inline void nfs_add_stats(const struct inode *inode, |
@@ -71,7 +71,7 @@ static inline void nfs_add_fscache_stats(struct inode *inode, | |||
71 | cpu = get_cpu(); | 71 | cpu = get_cpu(); |
72 | iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu); | 72 | iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu); |
73 | iostats->fscache[stat] += addend; | 73 | iostats->fscache[stat] += addend; |
74 | put_cpu_no_resched(); | 74 | put_cpu(); |
75 | } | 75 | } |
76 | #endif | 76 | #endif |
77 | 77 | ||
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index ca905a5bb1ba..38ef9eaec407 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -20,8 +20,116 @@ | |||
20 | # define NFSDBG_FACILITY NFSDBG_MOUNT | 20 | # define NFSDBG_FACILITY NFSDBG_MOUNT |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | /* | ||
24 | * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4 | ||
25 | */ | ||
26 | #define MNTPATHLEN (1024) | ||
27 | |||
28 | /* | ||
29 | * XDR data type sizes | ||
30 | */ | ||
31 | #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) | ||
32 | #define MNT_status_sz (1) | ||
33 | #define MNT_fhs_status_sz (1) | ||
34 | #define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE) | ||
35 | #define MNT_fhandle3_sz (1 + XDR_QUADLEN(NFS3_FHSIZE)) | ||
36 | #define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS) | ||
37 | |||
38 | /* | ||
39 | * XDR argument and result sizes | ||
40 | */ | ||
41 | #define MNT_enc_dirpath_sz encode_dirpath_sz | ||
42 | #define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz) | ||
43 | #define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandle_sz + \ | ||
44 | MNT_authflav3_sz) | ||
45 | |||
46 | /* | ||
47 | * Defined by RFC 1094, section A.5 | ||
48 | */ | ||
49 | enum { | ||
50 | MOUNTPROC_NULL = 0, | ||
51 | MOUNTPROC_MNT = 1, | ||
52 | MOUNTPROC_DUMP = 2, | ||
53 | MOUNTPROC_UMNT = 3, | ||
54 | MOUNTPROC_UMNTALL = 4, | ||
55 | MOUNTPROC_EXPORT = 5, | ||
56 | }; | ||
57 | |||
58 | /* | ||
59 | * Defined by RFC 1813, section 5.2 | ||
60 | */ | ||
61 | enum { | ||
62 | MOUNTPROC3_NULL = 0, | ||
63 | MOUNTPROC3_MNT = 1, | ||
64 | MOUNTPROC3_DUMP = 2, | ||
65 | MOUNTPROC3_UMNT = 3, | ||
66 | MOUNTPROC3_UMNTALL = 4, | ||
67 | MOUNTPROC3_EXPORT = 5, | ||
68 | }; | ||
69 | |||
23 | static struct rpc_program mnt_program; | 70 | static struct rpc_program mnt_program; |
24 | 71 | ||
72 | /* | ||
73 | * Defined by OpenGroup XNFS Version 3W, chapter 8 | ||
74 | */ | ||
75 | enum mountstat { | ||
76 | MNT_OK = 0, | ||
77 | MNT_EPERM = 1, | ||
78 | MNT_ENOENT = 2, | ||
79 | MNT_EACCES = 13, | ||
80 | MNT_EINVAL = 22, | ||
81 | }; | ||
82 | |||
83 | static struct { | ||
84 | u32 status; | ||
85 | int errno; | ||
86 | } mnt_errtbl[] = { | ||
87 | { .status = MNT_OK, .errno = 0, }, | ||
88 | { .status = MNT_EPERM, .errno = -EPERM, }, | ||
89 | { .status = MNT_ENOENT, .errno = -ENOENT, }, | ||
90 | { .status = MNT_EACCES, .errno = -EACCES, }, | ||
91 | { .status = MNT_EINVAL, .errno = -EINVAL, }, | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * Defined by RFC 1813, section 5.1.5 | ||
96 | */ | ||
97 | enum mountstat3 { | ||
98 | MNT3_OK = 0, /* no error */ | ||
99 | MNT3ERR_PERM = 1, /* Not owner */ | ||
100 | MNT3ERR_NOENT = 2, /* No such file or directory */ | ||
101 | MNT3ERR_IO = 5, /* I/O error */ | ||
102 | MNT3ERR_ACCES = 13, /* Permission denied */ | ||
103 | MNT3ERR_NOTDIR = 20, /* Not a directory */ | ||
104 | MNT3ERR_INVAL = 22, /* Invalid argument */ | ||
105 | MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ | ||
106 | MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ | ||
107 | MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */ | ||
108 | }; | ||
109 | |||
110 | static struct { | ||
111 | u32 status; | ||
112 | int errno; | ||
113 | } mnt3_errtbl[] = { | ||
114 | { .status = MNT3_OK, .errno = 0, }, | ||
115 | { .status = MNT3ERR_PERM, .errno = -EPERM, }, | ||
116 | { .status = MNT3ERR_NOENT, .errno = -ENOENT, }, | ||
117 | { .status = MNT3ERR_IO, .errno = -EIO, }, | ||
118 | { .status = MNT3ERR_ACCES, .errno = -EACCES, }, | ||
119 | { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, }, | ||
120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, | ||
121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, | ||
122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, | ||
123 | { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, }, | ||
124 | }; | ||
125 | |||
126 | struct mountres { | ||
127 | int errno; | ||
128 | struct nfs_fh *fh; | ||
129 | unsigned int *auth_count; | ||
130 | rpc_authflavor_t *auth_flavors; | ||
131 | }; | ||
132 | |||
25 | struct mnt_fhstatus { | 133 | struct mnt_fhstatus { |
26 | u32 status; | 134 | u32 status; |
27 | struct nfs_fh *fh; | 135 | struct nfs_fh *fh; |
@@ -35,8 +143,10 @@ struct mnt_fhstatus { | |||
35 | */ | 143 | */ |
36 | int nfs_mount(struct nfs_mount_request *info) | 144 | int nfs_mount(struct nfs_mount_request *info) |
37 | { | 145 | { |
38 | struct mnt_fhstatus result = { | 146 | struct mountres result = { |
39 | .fh = info->fh | 147 | .fh = info->fh, |
148 | .auth_count = info->auth_flav_len, | ||
149 | .auth_flavors = info->auth_flavs, | ||
40 | }; | 150 | }; |
41 | struct rpc_message msg = { | 151 | struct rpc_message msg = { |
42 | .rpc_argp = info->dirpath, | 152 | .rpc_argp = info->dirpath, |
@@ -68,14 +178,14 @@ int nfs_mount(struct nfs_mount_request *info) | |||
68 | if (info->version == NFS_MNT3_VERSION) | 178 | if (info->version == NFS_MNT3_VERSION) |
69 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; | 179 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; |
70 | else | 180 | else |
71 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; | 181 | msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; |
72 | 182 | ||
73 | status = rpc_call_sync(mnt_clnt, &msg, 0); | 183 | status = rpc_call_sync(mnt_clnt, &msg, 0); |
74 | rpc_shutdown_client(mnt_clnt); | 184 | rpc_shutdown_client(mnt_clnt); |
75 | 185 | ||
76 | if (status < 0) | 186 | if (status < 0) |
77 | goto out_call_err; | 187 | goto out_call_err; |
78 | if (result.status != 0) | 188 | if (result.errno != 0) |
79 | goto out_mnt_err; | 189 | goto out_mnt_err; |
80 | 190 | ||
81 | dprintk("NFS: MNT request succeeded\n"); | 191 | dprintk("NFS: MNT request succeeded\n"); |
@@ -86,72 +196,215 @@ out: | |||
86 | 196 | ||
87 | out_clnt_err: | 197 | out_clnt_err: |
88 | status = PTR_ERR(mnt_clnt); | 198 | status = PTR_ERR(mnt_clnt); |
89 | dprintk("NFS: failed to create RPC client, status=%d\n", status); | 199 | dprintk("NFS: failed to create MNT RPC client, status=%d\n", status); |
90 | goto out; | 200 | goto out; |
91 | 201 | ||
92 | out_call_err: | 202 | out_call_err: |
93 | dprintk("NFS: failed to start MNT request, status=%d\n", status); | 203 | dprintk("NFS: MNT request failed, status=%d\n", status); |
94 | goto out; | 204 | goto out; |
95 | 205 | ||
96 | out_mnt_err: | 206 | out_mnt_err: |
97 | dprintk("NFS: MNT server returned result %d\n", result.status); | 207 | dprintk("NFS: MNT server returned result %d\n", result.errno); |
98 | status = nfs_stat_to_errno(result.status); | 208 | status = result.errno; |
99 | goto out; | 209 | goto out; |
100 | } | 210 | } |
101 | 211 | ||
102 | /* | 212 | /* |
103 | * XDR encode/decode functions for MOUNT | 213 | * XDR encode/decode functions for MOUNT |
104 | */ | 214 | */ |
105 | static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, | 215 | |
106 | const char *path) | 216 | static int encode_mntdirpath(struct xdr_stream *xdr, const char *pathname) |
217 | { | ||
218 | const u32 pathname_len = strlen(pathname); | ||
219 | __be32 *p; | ||
220 | |||
221 | if (unlikely(pathname_len > MNTPATHLEN)) | ||
222 | return -EIO; | ||
223 | |||
224 | p = xdr_reserve_space(xdr, sizeof(u32) + pathname_len); | ||
225 | if (unlikely(p == NULL)) | ||
226 | return -EIO; | ||
227 | xdr_encode_opaque(p, pathname, pathname_len); | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int mnt_enc_dirpath(struct rpc_rqst *req, __be32 *p, | ||
233 | const char *dirpath) | ||
234 | { | ||
235 | struct xdr_stream xdr; | ||
236 | |||
237 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
238 | return encode_mntdirpath(&xdr, dirpath); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * RFC 1094: "A non-zero status indicates some sort of error. In this | ||
243 | * case, the status is a UNIX error number." This can be problematic | ||
244 | * if the server and client use different errno values for the same | ||
245 | * error. | ||
246 | * | ||
247 | * However, the OpenGroup XNFS spec provides a simple mapping that is | ||
248 | * independent of local errno values on the server and the client. | ||
249 | */ | ||
250 | static int decode_status(struct xdr_stream *xdr, struct mountres *res) | ||
107 | { | 251 | { |
108 | p = xdr_encode_string(p, path); | 252 | unsigned int i; |
253 | u32 status; | ||
254 | __be32 *p; | ||
255 | |||
256 | p = xdr_inline_decode(xdr, sizeof(status)); | ||
257 | if (unlikely(p == NULL)) | ||
258 | return -EIO; | ||
259 | status = ntohl(*p); | ||
109 | 260 | ||
110 | req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); | 261 | for (i = 0; i <= ARRAY_SIZE(mnt_errtbl); i++) { |
262 | if (mnt_errtbl[i].status == status) { | ||
263 | res->errno = mnt_errtbl[i].errno; | ||
264 | return 0; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | dprintk("NFS: unrecognized MNT status code: %u\n", status); | ||
269 | res->errno = -EACCES; | ||
111 | return 0; | 270 | return 0; |
112 | } | 271 | } |
113 | 272 | ||
114 | static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, | 273 | static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res) |
115 | struct mnt_fhstatus *res) | ||
116 | { | 274 | { |
117 | struct nfs_fh *fh = res->fh; | 275 | struct nfs_fh *fh = res->fh; |
276 | __be32 *p; | ||
277 | |||
278 | p = xdr_inline_decode(xdr, NFS2_FHSIZE); | ||
279 | if (unlikely(p == NULL)) | ||
280 | return -EIO; | ||
281 | |||
282 | fh->size = NFS2_FHSIZE; | ||
283 | memcpy(fh->data, p, NFS2_FHSIZE); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int mnt_dec_mountres(struct rpc_rqst *req, __be32 *p, | ||
288 | struct mountres *res) | ||
289 | { | ||
290 | struct xdr_stream xdr; | ||
291 | int status; | ||
292 | |||
293 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
294 | |||
295 | status = decode_status(&xdr, res); | ||
296 | if (unlikely(status != 0 || res->errno != 0)) | ||
297 | return status; | ||
298 | return decode_fhandle(&xdr, res); | ||
299 | } | ||
300 | |||
301 | static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) | ||
302 | { | ||
303 | unsigned int i; | ||
304 | u32 status; | ||
305 | __be32 *p; | ||
118 | 306 | ||
119 | if ((res->status = ntohl(*p++)) == 0) { | 307 | p = xdr_inline_decode(xdr, sizeof(status)); |
120 | fh->size = NFS2_FHSIZE; | 308 | if (unlikely(p == NULL)) |
121 | memcpy(fh->data, p, NFS2_FHSIZE); | 309 | return -EIO; |
310 | status = ntohl(*p); | ||
311 | |||
312 | for (i = 0; i <= ARRAY_SIZE(mnt3_errtbl); i++) { | ||
313 | if (mnt3_errtbl[i].status == status) { | ||
314 | res->errno = mnt3_errtbl[i].errno; | ||
315 | return 0; | ||
316 | } | ||
122 | } | 317 | } |
318 | |||
319 | dprintk("NFS: unrecognized MNT3 status code: %u\n", status); | ||
320 | res->errno = -EACCES; | ||
123 | return 0; | 321 | return 0; |
124 | } | 322 | } |
125 | 323 | ||
126 | static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, | 324 | static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res) |
127 | struct mnt_fhstatus *res) | ||
128 | { | 325 | { |
129 | struct nfs_fh *fh = res->fh; | 326 | struct nfs_fh *fh = res->fh; |
130 | unsigned size; | 327 | u32 size; |
131 | 328 | __be32 *p; | |
132 | if ((res->status = ntohl(*p++)) == 0) { | 329 | |
133 | size = ntohl(*p++); | 330 | p = xdr_inline_decode(xdr, sizeof(size)); |
134 | if (size <= NFS3_FHSIZE && size != 0) { | 331 | if (unlikely(p == NULL)) |
135 | fh->size = size; | 332 | return -EIO; |
136 | memcpy(fh->data, p, size); | 333 | |
137 | } else | 334 | size = ntohl(*p++); |
138 | res->status = -EBADHANDLE; | 335 | if (size > NFS3_FHSIZE || size == 0) |
336 | return -EIO; | ||
337 | |||
338 | p = xdr_inline_decode(xdr, size); | ||
339 | if (unlikely(p == NULL)) | ||
340 | return -EIO; | ||
341 | |||
342 | fh->size = size; | ||
343 | memcpy(fh->data, p, size); | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res) | ||
348 | { | ||
349 | rpc_authflavor_t *flavors = res->auth_flavors; | ||
350 | unsigned int *count = res->auth_count; | ||
351 | u32 entries, i; | ||
352 | __be32 *p; | ||
353 | |||
354 | if (*count == 0) | ||
355 | return 0; | ||
356 | |||
357 | p = xdr_inline_decode(xdr, sizeof(entries)); | ||
358 | if (unlikely(p == NULL)) | ||
359 | return -EIO; | ||
360 | entries = ntohl(*p); | ||
361 | dprintk("NFS: received %u auth flavors\n", entries); | ||
362 | if (entries > NFS_MAX_SECFLAVORS) | ||
363 | entries = NFS_MAX_SECFLAVORS; | ||
364 | |||
365 | p = xdr_inline_decode(xdr, sizeof(u32) * entries); | ||
366 | if (unlikely(p == NULL)) | ||
367 | return -EIO; | ||
368 | |||
369 | if (entries > *count) | ||
370 | entries = *count; | ||
371 | |||
372 | for (i = 0; i < entries; i++) { | ||
373 | flavors[i] = ntohl(*p++); | ||
374 | dprintk("NFS:\tflavor %u: %d\n", i, flavors[i]); | ||
139 | } | 375 | } |
376 | *count = i; | ||
377 | |||
140 | return 0; | 378 | return 0; |
141 | } | 379 | } |
142 | 380 | ||
143 | #define MNT_dirpath_sz (1 + 256) | 381 | static int mnt_dec_mountres3(struct rpc_rqst *req, __be32 *p, |
144 | #define MNT_fhstatus_sz (1 + 8) | 382 | struct mountres *res) |
145 | #define MNT_fhstatus3_sz (1 + 16) | 383 | { |
384 | struct xdr_stream xdr; | ||
385 | int status; | ||
386 | |||
387 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | ||
388 | |||
389 | status = decode_fhs_status(&xdr, res); | ||
390 | if (unlikely(status != 0 || res->errno != 0)) | ||
391 | return status; | ||
392 | status = decode_fhandle3(&xdr, res); | ||
393 | if (unlikely(status != 0)) { | ||
394 | res->errno = -EBADHANDLE; | ||
395 | return 0; | ||
396 | } | ||
397 | return decode_auth_flavors(&xdr, res); | ||
398 | } | ||
146 | 399 | ||
147 | static struct rpc_procinfo mnt_procedures[] = { | 400 | static struct rpc_procinfo mnt_procedures[] = { |
148 | [MNTPROC_MNT] = { | 401 | [MOUNTPROC_MNT] = { |
149 | .p_proc = MNTPROC_MNT, | 402 | .p_proc = MOUNTPROC_MNT, |
150 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 403 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, |
151 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus, | 404 | .p_decode = (kxdrproc_t)mnt_dec_mountres, |
152 | .p_arglen = MNT_dirpath_sz, | 405 | .p_arglen = MNT_enc_dirpath_sz, |
153 | .p_replen = MNT_fhstatus_sz, | 406 | .p_replen = MNT_dec_mountres_sz, |
154 | .p_statidx = MNTPROC_MNT, | 407 | .p_statidx = MOUNTPROC_MNT, |
155 | .p_name = "MOUNT", | 408 | .p_name = "MOUNT", |
156 | }, | 409 | }, |
157 | }; | 410 | }; |
@@ -159,10 +412,10 @@ static struct rpc_procinfo mnt_procedures[] = { | |||
159 | static struct rpc_procinfo mnt3_procedures[] = { | 412 | static struct rpc_procinfo mnt3_procedures[] = { |
160 | [MOUNTPROC3_MNT] = { | 413 | [MOUNTPROC3_MNT] = { |
161 | .p_proc = MOUNTPROC3_MNT, | 414 | .p_proc = MOUNTPROC3_MNT, |
162 | .p_encode = (kxdrproc_t) xdr_encode_dirpath, | 415 | .p_encode = (kxdrproc_t)mnt_enc_dirpath, |
163 | .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, | 416 | .p_decode = (kxdrproc_t)mnt_dec_mountres3, |
164 | .p_arglen = MNT_dirpath_sz, | 417 | .p_arglen = MNT_enc_dirpath_sz, |
165 | .p_replen = MNT_fhstatus3_sz, | 418 | .p_replen = MNT_dec_mountres3_sz, |
166 | .p_statidx = MOUNTPROC3_MNT, | 419 | .p_statidx = MOUNTPROC3_MNT, |
167 | .p_name = "MOUNT", | 420 | .p_name = "MOUNT", |
168 | }, | 421 | }, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index f01caec84463..40c766782891 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -65,6 +65,11 @@ char *nfs_path(const char *base, | |||
65 | dentry = dentry->d_parent; | 65 | dentry = dentry->d_parent; |
66 | } | 66 | } |
67 | spin_unlock(&dcache_lock); | 67 | spin_unlock(&dcache_lock); |
68 | if (*end != '/') { | ||
69 | if (--buflen < 0) | ||
70 | goto Elong; | ||
71 | *--end = '/'; | ||
72 | } | ||
68 | namelen = strlen(base); | 73 | namelen = strlen(base); |
69 | /* Strip off excess slashes in base string */ | 74 | /* Strip off excess slashes in base string */ |
70 | while (namelen > 0 && base[namelen - 1] == '/') | 75 | while (namelen > 0 && base[namelen - 1] == '/') |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 6bbf0e6daad2..bac60515a4b3 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -207,8 +207,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) | |||
207 | status = nfs_revalidate_inode(server, inode); | 207 | status = nfs_revalidate_inode(server, inode); |
208 | if (status < 0) | 208 | if (status < 0) |
209 | return ERR_PTR(status); | 209 | return ERR_PTR(status); |
210 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
211 | nfs_zap_acl_cache(inode); | ||
212 | acl = nfs3_get_cached_acl(inode, type); | 210 | acl = nfs3_get_cached_acl(inode, type); |
213 | if (acl != ERR_PTR(-EAGAIN)) | 211 | if (acl != ERR_PTR(-EAGAIN)) |
214 | return acl; | 212 | return acl; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 84345deab26f..6ea07a3c75d4 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -44,6 +44,7 @@ enum nfs4_client_state { | |||
44 | NFS4CLNT_RECLAIM_REBOOT, | 44 | NFS4CLNT_RECLAIM_REBOOT, |
45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_SETUP, | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -177,6 +178,14 @@ struct nfs4_state_recovery_ops { | |||
177 | int state_flag_bit; | 178 | int state_flag_bit; |
178 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | 179 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); |
179 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 180 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
181 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | ||
182 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | ||
183 | }; | ||
184 | |||
185 | struct nfs4_state_maintenance_ops { | ||
186 | int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *); | ||
187 | struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *); | ||
188 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); | ||
180 | }; | 189 | }; |
181 | 190 | ||
182 | extern const struct dentry_operations nfs4_dentry_operations; | 191 | extern const struct dentry_operations nfs4_dentry_operations; |
@@ -193,6 +202,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |||
193 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 202 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
194 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 203 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
195 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 204 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
205 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | ||
196 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 206 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
197 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 207 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
198 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 208 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -200,8 +210,32 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh | |||
200 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 210 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
201 | struct nfs4_fs_locations *fs_locations, struct page *page); | 211 | struct nfs4_fs_locations *fs_locations, struct page *page); |
202 | 212 | ||
203 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 213 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; |
204 | extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops; | 214 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; |
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | extern int nfs4_setup_sequence(struct nfs_client *clp, | ||
217 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
218 | int cache_reply, struct rpc_task *task); | ||
219 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
220 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
221 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | ||
222 | extern int nfs4_proc_destroy_session(struct nfs4_session *); | ||
223 | extern int nfs4_init_session(struct nfs_server *server); | ||
224 | #else /* CONFIG_NFS_v4_1 */ | ||
225 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | ||
226 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
227 | int cache_reply, struct rpc_task *task) | ||
228 | { | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static inline int nfs4_init_session(struct nfs_server *server) | ||
233 | { | ||
234 | return 0; | ||
235 | } | ||
236 | #endif /* CONFIG_NFS_V4_1 */ | ||
237 | |||
238 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | ||
205 | 239 | ||
206 | extern const u32 nfs4_fattr_bitmap[2]; | 240 | extern const u32 nfs4_fattr_bitmap[2]; |
207 | extern const u32 nfs4_statfs_bitmap[2]; | 241 | extern const u32 nfs4_statfs_bitmap[2]; |
@@ -216,7 +250,12 @@ extern void nfs4_kill_renewd(struct nfs_client *); | |||
216 | extern void nfs4_renew_state(struct work_struct *); | 250 | extern void nfs4_renew_state(struct work_struct *); |
217 | 251 | ||
218 | /* nfs4state.c */ | 252 | /* nfs4state.c */ |
253 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp); | ||
219 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); | 254 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); |
255 | #if defined(CONFIG_NFS_V4_1) | ||
256 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); | ||
257 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); | ||
258 | #endif /* CONFIG_NFS_V4_1 */ | ||
220 | 259 | ||
221 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 260 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
222 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 261 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4674f8092da8..6917311f201c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -45,14 +45,16 @@ | |||
45 | #include <linux/nfs4.h> | 45 | #include <linux/nfs4.h> |
46 | #include <linux/nfs_fs.h> | 46 | #include <linux/nfs_fs.h> |
47 | #include <linux/nfs_page.h> | 47 | #include <linux/nfs_page.h> |
48 | #include <linux/smp_lock.h> | ||
49 | #include <linux/namei.h> | 48 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 49 | #include <linux/mount.h> |
50 | #include <linux/module.h> | ||
51 | #include <linux/sunrpc/bc_xprt.h> | ||
51 | 52 | ||
52 | #include "nfs4_fs.h" | 53 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 54 | #include "delegation.h" |
54 | #include "internal.h" | 55 | #include "internal.h" |
55 | #include "iostat.h" | 56 | #include "iostat.h" |
57 | #include "callback.h" | ||
56 | 58 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 59 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 60 | ||
@@ -247,7 +249,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
247 | ret = nfs4_wait_clnt_recover(clp); | 249 | ret = nfs4_wait_clnt_recover(clp); |
248 | if (ret == 0) | 250 | if (ret == 0) |
249 | exception->retry = 1; | 251 | exception->retry = 1; |
252 | #if !defined(CONFIG_NFS_V4_1) | ||
250 | break; | 253 | break; |
254 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
255 | if (!nfs4_has_session(server->nfs_client)) | ||
256 | break; | ||
257 | /* FALLTHROUGH */ | ||
258 | case -NFS4ERR_BADSESSION: | ||
259 | case -NFS4ERR_BADSLOT: | ||
260 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
261 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
262 | case -NFS4ERR_DEADSESSION: | ||
263 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
264 | case -NFS4ERR_SEQ_MISORDERED: | ||
265 | dprintk("%s ERROR: %d Reset session\n", __func__, | ||
266 | errorcode); | ||
267 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
268 | exception->retry = 1; | ||
269 | /* FALLTHROUGH */ | ||
270 | #endif /* !defined(CONFIG_NFS_V4_1) */ | ||
251 | case -NFS4ERR_FILE_OPEN: | 271 | case -NFS4ERR_FILE_OPEN: |
252 | case -NFS4ERR_GRACE: | 272 | case -NFS4ERR_GRACE: |
253 | case -NFS4ERR_DELAY: | 273 | case -NFS4ERR_DELAY: |
@@ -271,6 +291,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
271 | spin_unlock(&clp->cl_lock); | 291 | spin_unlock(&clp->cl_lock); |
272 | } | 292 | } |
273 | 293 | ||
294 | #if defined(CONFIG_NFS_V4_1) | ||
295 | |||
296 | /* | ||
297 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
298 | * | ||
299 | * freeing a slot is trivially done by clearing its respective bit | ||
300 | * in the bitmap. | ||
301 | * If the freed slotid equals highest_used_slotid we want to update it | ||
302 | * so that the server would be able to size down the slot table if needed, | ||
303 | * otherwise we know that the highest_used_slotid is still in use. | ||
304 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
305 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
306 | * highest slotid in use. | ||
307 | * If none found, highest_used_slotid is set to -1. | ||
308 | */ | ||
309 | static void | ||
310 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | ||
311 | { | ||
312 | int slotid = free_slotid; | ||
313 | |||
314 | spin_lock(&tbl->slot_tbl_lock); | ||
315 | /* clear used bit in bitmap */ | ||
316 | __clear_bit(slotid, tbl->used_slots); | ||
317 | |||
318 | /* update highest_used_slotid when it is freed */ | ||
319 | if (slotid == tbl->highest_used_slotid) { | ||
320 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | ||
321 | if (slotid >= 0 && slotid < tbl->max_slots) | ||
322 | tbl->highest_used_slotid = slotid; | ||
323 | else | ||
324 | tbl->highest_used_slotid = -1; | ||
325 | } | ||
326 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
327 | spin_unlock(&tbl->slot_tbl_lock); | ||
328 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | ||
329 | free_slotid, tbl->highest_used_slotid); | ||
330 | } | ||
331 | |||
332 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
333 | struct nfs4_sequence_res *res) | ||
334 | { | ||
335 | struct nfs4_slot_table *tbl; | ||
336 | |||
337 | if (!nfs4_has_session(clp)) { | ||
338 | dprintk("%s: No session\n", __func__); | ||
339 | return; | ||
340 | } | ||
341 | tbl = &clp->cl_session->fc_slot_table; | ||
342 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | ||
343 | dprintk("%s: No slot\n", __func__); | ||
344 | /* just wake up the next guy waiting since | ||
345 | * we may have not consumed a slot after all */ | ||
346 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
347 | return; | ||
348 | } | ||
349 | nfs4_free_slot(tbl, res->sr_slotid); | ||
350 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
351 | } | ||
352 | |||
353 | static void nfs41_sequence_done(struct nfs_client *clp, | ||
354 | struct nfs4_sequence_res *res, | ||
355 | int rpc_status) | ||
356 | { | ||
357 | unsigned long timestamp; | ||
358 | struct nfs4_slot_table *tbl; | ||
359 | struct nfs4_slot *slot; | ||
360 | |||
361 | /* | ||
362 | * sr_status remains 1 if an RPC level error occurred. The server | ||
363 | * may or may not have processed the sequence operation.. | ||
364 | * Proceed as if the server received and processed the sequence | ||
365 | * operation. | ||
366 | */ | ||
367 | if (res->sr_status == 1) | ||
368 | res->sr_status = NFS_OK; | ||
369 | |||
370 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | ||
371 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | ||
372 | goto out; | ||
373 | |||
374 | tbl = &clp->cl_session->fc_slot_table; | ||
375 | slot = tbl->slots + res->sr_slotid; | ||
376 | |||
377 | if (res->sr_status == 0) { | ||
378 | /* Update the slot's sequence and clientid lease timer */ | ||
379 | ++slot->seq_nr; | ||
380 | timestamp = res->sr_renewal_time; | ||
381 | spin_lock(&clp->cl_lock); | ||
382 | if (time_before(clp->cl_last_renewal, timestamp)) | ||
383 | clp->cl_last_renewal = timestamp; | ||
384 | spin_unlock(&clp->cl_lock); | ||
385 | return; | ||
386 | } | ||
387 | out: | ||
388 | /* The session may be reset by one of the error handlers. */ | ||
389 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | ||
390 | nfs41_sequence_free_slot(clp, res); | ||
391 | } | ||
392 | |||
393 | /* | ||
394 | * nfs4_find_slot - efficiently look for a free slot | ||
395 | * | ||
396 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | ||
397 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
398 | * and respectively set up the sequence operation args. | ||
399 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | ||
400 | * | ||
401 | * Note: must be called with under the slot_tbl_lock. | ||
402 | */ | ||
403 | static u8 | ||
404 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | ||
405 | { | ||
406 | int slotid; | ||
407 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | ||
408 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
409 | |||
410 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | ||
411 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
412 | tbl->max_slots); | ||
413 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | ||
414 | if (slotid >= tbl->max_slots) | ||
415 | goto out; | ||
416 | __set_bit(slotid, tbl->used_slots); | ||
417 | if (slotid > tbl->highest_used_slotid) | ||
418 | tbl->highest_used_slotid = slotid; | ||
419 | ret_id = slotid; | ||
420 | out: | ||
421 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
422 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); | ||
423 | return ret_id; | ||
424 | } | ||
425 | |||
426 | static int nfs4_recover_session(struct nfs4_session *session) | ||
427 | { | ||
428 | struct nfs_client *clp = session->clp; | ||
429 | int ret; | ||
430 | |||
431 | for (;;) { | ||
432 | ret = nfs4_wait_clnt_recover(clp); | ||
433 | if (ret != 0) | ||
434 | return ret; | ||
435 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
436 | break; | ||
437 | nfs4_schedule_state_manager(clp); | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int nfs41_setup_sequence(struct nfs4_session *session, | ||
443 | struct nfs4_sequence_args *args, | ||
444 | struct nfs4_sequence_res *res, | ||
445 | int cache_reply, | ||
446 | struct rpc_task *task) | ||
447 | { | ||
448 | struct nfs4_slot *slot; | ||
449 | struct nfs4_slot_table *tbl; | ||
450 | int status = 0; | ||
451 | u8 slotid; | ||
452 | |||
453 | dprintk("--> %s\n", __func__); | ||
454 | /* slot already allocated? */ | ||
455 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | ||
456 | return 0; | ||
457 | |||
458 | memset(res, 0, sizeof(*res)); | ||
459 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
460 | tbl = &session->fc_slot_table; | ||
461 | |||
462 | spin_lock(&tbl->slot_tbl_lock); | ||
463 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | ||
464 | if (tbl->highest_used_slotid != -1) { | ||
465 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
466 | spin_unlock(&tbl->slot_tbl_lock); | ||
467 | dprintk("<-- %s: Session reset: draining\n", __func__); | ||
468 | return -EAGAIN; | ||
469 | } | ||
470 | |||
471 | /* The slot table is empty; start the reset thread */ | ||
472 | dprintk("%s Session Reset\n", __func__); | ||
473 | spin_unlock(&tbl->slot_tbl_lock); | ||
474 | status = nfs4_recover_session(session); | ||
475 | if (status) | ||
476 | return status; | ||
477 | spin_lock(&tbl->slot_tbl_lock); | ||
478 | } | ||
479 | |||
480 | slotid = nfs4_find_slot(tbl, task); | ||
481 | if (slotid == NFS4_MAX_SLOT_TABLE) { | ||
482 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
483 | spin_unlock(&tbl->slot_tbl_lock); | ||
484 | dprintk("<-- %s: no free slots\n", __func__); | ||
485 | return -EAGAIN; | ||
486 | } | ||
487 | spin_unlock(&tbl->slot_tbl_lock); | ||
488 | |||
489 | slot = tbl->slots + slotid; | ||
490 | args->sa_session = session; | ||
491 | args->sa_slotid = slotid; | ||
492 | args->sa_cache_this = cache_reply; | ||
493 | |||
494 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | ||
495 | |||
496 | res->sr_session = session; | ||
497 | res->sr_slotid = slotid; | ||
498 | res->sr_renewal_time = jiffies; | ||
499 | /* | ||
500 | * sr_status is only set in decode_sequence, and so will remain | ||
501 | * set to 1 if an rpc level failure occurs. | ||
502 | */ | ||
503 | res->sr_status = 1; | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | int nfs4_setup_sequence(struct nfs_client *clp, | ||
508 | struct nfs4_sequence_args *args, | ||
509 | struct nfs4_sequence_res *res, | ||
510 | int cache_reply, | ||
511 | struct rpc_task *task) | ||
512 | { | ||
513 | int ret = 0; | ||
514 | |||
515 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | ||
516 | __func__, clp, clp->cl_session, res->sr_slotid); | ||
517 | |||
518 | if (!nfs4_has_session(clp)) | ||
519 | goto out; | ||
520 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
521 | task); | ||
522 | if (ret != -EAGAIN) { | ||
523 | /* terminate rpc task */ | ||
524 | task->tk_status = ret; | ||
525 | task->tk_action = NULL; | ||
526 | } | ||
527 | out: | ||
528 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | struct nfs41_call_sync_data { | ||
533 | struct nfs_client *clp; | ||
534 | struct nfs4_sequence_args *seq_args; | ||
535 | struct nfs4_sequence_res *seq_res; | ||
536 | int cache_reply; | ||
537 | }; | ||
538 | |||
539 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | ||
540 | { | ||
541 | struct nfs41_call_sync_data *data = calldata; | ||
542 | |||
543 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | ||
544 | data->clp->cl_session); | ||
545 | if (nfs4_setup_sequence(data->clp, data->seq_args, | ||
546 | data->seq_res, data->cache_reply, task)) | ||
547 | return; | ||
548 | rpc_call_start(task); | ||
549 | } | ||
550 | |||
551 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | ||
552 | { | ||
553 | struct nfs41_call_sync_data *data = calldata; | ||
554 | |||
555 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | ||
556 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
557 | } | ||
558 | |||
559 | struct rpc_call_ops nfs41_call_sync_ops = { | ||
560 | .rpc_call_prepare = nfs41_call_sync_prepare, | ||
561 | .rpc_call_done = nfs41_call_sync_done, | ||
562 | }; | ||
563 | |||
564 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | ||
565 | struct rpc_clnt *clnt, | ||
566 | struct rpc_message *msg, | ||
567 | struct nfs4_sequence_args *args, | ||
568 | struct nfs4_sequence_res *res, | ||
569 | int cache_reply) | ||
570 | { | ||
571 | int ret; | ||
572 | struct rpc_task *task; | ||
573 | struct nfs41_call_sync_data data = { | ||
574 | .clp = clp, | ||
575 | .seq_args = args, | ||
576 | .seq_res = res, | ||
577 | .cache_reply = cache_reply, | ||
578 | }; | ||
579 | struct rpc_task_setup task_setup = { | ||
580 | .rpc_client = clnt, | ||
581 | .rpc_message = msg, | ||
582 | .callback_ops = &nfs41_call_sync_ops, | ||
583 | .callback_data = &data | ||
584 | }; | ||
585 | |||
586 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
587 | task = rpc_run_task(&task_setup); | ||
588 | if (IS_ERR(task)) | ||
589 | ret = PTR_ERR(task); | ||
590 | else { | ||
591 | ret = task->tk_status; | ||
592 | rpc_put_task(task); | ||
593 | } | ||
594 | return ret; | ||
595 | } | ||
596 | |||
597 | int _nfs4_call_sync_session(struct nfs_server *server, | ||
598 | struct rpc_message *msg, | ||
599 | struct nfs4_sequence_args *args, | ||
600 | struct nfs4_sequence_res *res, | ||
601 | int cache_reply) | ||
602 | { | ||
603 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | ||
604 | msg, args, res, cache_reply); | ||
605 | } | ||
606 | |||
607 | #endif /* CONFIG_NFS_V4_1 */ | ||
608 | |||
609 | int _nfs4_call_sync(struct nfs_server *server, | ||
610 | struct rpc_message *msg, | ||
611 | struct nfs4_sequence_args *args, | ||
612 | struct nfs4_sequence_res *res, | ||
613 | int cache_reply) | ||
614 | { | ||
615 | args->sa_session = res->sr_session = NULL; | ||
616 | return rpc_call_sync(server->client, msg, 0); | ||
617 | } | ||
618 | |||
619 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | ||
620 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | ||
621 | &(res)->seq_res, (cache_reply)) | ||
622 | |||
623 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
624 | struct nfs4_sequence_res *res, int rpc_status) | ||
625 | { | ||
626 | #ifdef CONFIG_NFS_V4_1 | ||
627 | if (nfs4_has_session(server->nfs_client)) | ||
628 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
629 | #endif /* CONFIG_NFS_V4_1 */ | ||
630 | } | ||
631 | |||
632 | /* no restart, therefore free slot here */ | ||
633 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
634 | struct nfs4_sequence_res *res, | ||
635 | int rpc_status) | ||
636 | { | ||
637 | nfs4_sequence_done(server, res, rpc_status); | ||
638 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
639 | } | ||
640 | |||
274 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 641 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
275 | { | 642 | { |
276 | struct nfs_inode *nfsi = NFS_I(dir); | 643 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -312,6 +679,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p) | |||
312 | p->o_res.server = p->o_arg.server; | 679 | p->o_res.server = p->o_arg.server; |
313 | nfs_fattr_init(&p->f_attr); | 680 | nfs_fattr_init(&p->f_attr); |
314 | nfs_fattr_init(&p->dir_attr); | 681 | nfs_fattr_init(&p->dir_attr); |
682 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
315 | } | 683 | } |
316 | 684 | ||
317 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | 685 | static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, |
@@ -804,16 +1172,30 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
804 | err = _nfs4_open_delegation_recall(ctx, state, stateid); | 1172 | err = _nfs4_open_delegation_recall(ctx, state, stateid); |
805 | switch (err) { | 1173 | switch (err) { |
806 | case 0: | 1174 | case 0: |
807 | return err; | 1175 | case -ENOENT: |
1176 | case -ESTALE: | ||
1177 | goto out; | ||
808 | case -NFS4ERR_STALE_CLIENTID: | 1178 | case -NFS4ERR_STALE_CLIENTID: |
809 | case -NFS4ERR_STALE_STATEID: | 1179 | case -NFS4ERR_STALE_STATEID: |
810 | case -NFS4ERR_EXPIRED: | 1180 | case -NFS4ERR_EXPIRED: |
811 | /* Don't recall a delegation if it was lost */ | 1181 | /* Don't recall a delegation if it was lost */ |
812 | nfs4_schedule_state_recovery(server->nfs_client); | 1182 | nfs4_schedule_state_recovery(server->nfs_client); |
813 | return err; | 1183 | goto out; |
1184 | case -ERESTARTSYS: | ||
1185 | /* | ||
1186 | * The show must go on: exit, but mark the | ||
1187 | * stateid as needing recovery. | ||
1188 | */ | ||
1189 | case -NFS4ERR_ADMIN_REVOKED: | ||
1190 | case -NFS4ERR_BAD_STATEID: | ||
1191 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | ||
1192 | case -ENOMEM: | ||
1193 | err = 0; | ||
1194 | goto out; | ||
814 | } | 1195 | } |
815 | err = nfs4_handle_exception(server, err, &exception); | 1196 | err = nfs4_handle_exception(server, err, &exception); |
816 | } while (exception.retry); | 1197 | } while (exception.retry); |
1198 | out: | ||
817 | return err; | 1199 | return err; |
818 | } | 1200 | } |
819 | 1201 | ||
@@ -929,6 +1311,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
929 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1311 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
930 | } | 1312 | } |
931 | data->timestamp = jiffies; | 1313 | data->timestamp = jiffies; |
1314 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | ||
1315 | &data->o_arg.seq_args, | ||
1316 | &data->o_res.seq_res, 1, task)) | ||
1317 | return; | ||
932 | rpc_call_start(task); | 1318 | rpc_call_start(task); |
933 | return; | 1319 | return; |
934 | out_no_action: | 1320 | out_no_action: |
@@ -941,6 +1327,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
941 | struct nfs4_opendata *data = calldata; | 1327 | struct nfs4_opendata *data = calldata; |
942 | 1328 | ||
943 | data->rpc_status = task->tk_status; | 1329 | data->rpc_status = task->tk_status; |
1330 | |||
1331 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | ||
1332 | task->tk_status); | ||
1333 | |||
944 | if (RPC_ASSASSINATED(task)) | 1334 | if (RPC_ASSASSINATED(task)) |
945 | return; | 1335 | return; |
946 | if (task->tk_status == 0) { | 1336 | if (task->tk_status == 0) { |
@@ -1269,7 +1659,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1269 | } else | 1659 | } else |
1270 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1660 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1271 | 1661 | ||
1272 | status = rpc_call_sync(server->client, &msg, 0); | 1662 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
1273 | if (status == 0 && state != NULL) | 1663 | if (status == 0 && state != NULL) |
1274 | renew_lease(server, timestamp); | 1664 | renew_lease(server, timestamp); |
1275 | return status; | 1665 | return status; |
@@ -1318,6 +1708,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1318 | struct nfs4_state *state = calldata->state; | 1708 | struct nfs4_state *state = calldata->state; |
1319 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1709 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1320 | 1710 | ||
1711 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | ||
1321 | if (RPC_ASSASSINATED(task)) | 1712 | if (RPC_ASSASSINATED(task)) |
1322 | return; | 1713 | return; |
1323 | /* hmm. we are done with the inode, and in the process of freeing | 1714 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -1336,10 +1727,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1336 | break; | 1727 | break; |
1337 | default: | 1728 | default: |
1338 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1729 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1339 | rpc_restart_call(task); | 1730 | nfs4_restart_rpc(task, server->nfs_client); |
1340 | return; | 1731 | return; |
1341 | } | 1732 | } |
1342 | } | 1733 | } |
1734 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | ||
1343 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1735 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1344 | } | 1736 | } |
1345 | 1737 | ||
@@ -1380,6 +1772,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1380 | calldata->arg.fmode = FMODE_WRITE; | 1772 | calldata->arg.fmode = FMODE_WRITE; |
1381 | } | 1773 | } |
1382 | calldata->timestamp = jiffies; | 1774 | calldata->timestamp = jiffies; |
1775 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | ||
1776 | &calldata->arg.seq_args, &calldata->res.seq_res, | ||
1777 | 1, task)) | ||
1778 | return; | ||
1383 | rpc_call_start(task); | 1779 | rpc_call_start(task); |
1384 | } | 1780 | } |
1385 | 1781 | ||
@@ -1419,13 +1815,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1419 | }; | 1815 | }; |
1420 | int status = -ENOMEM; | 1816 | int status = -ENOMEM; |
1421 | 1817 | ||
1422 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1818 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); |
1423 | if (calldata == NULL) | 1819 | if (calldata == NULL) |
1424 | goto out; | 1820 | goto out; |
1425 | calldata->inode = state->inode; | 1821 | calldata->inode = state->inode; |
1426 | calldata->state = state; | 1822 | calldata->state = state; |
1427 | calldata->arg.fh = NFS_FH(state->inode); | 1823 | calldata->arg.fh = NFS_FH(state->inode); |
1428 | calldata->arg.stateid = &state->open_stateid; | 1824 | calldata->arg.stateid = &state->open_stateid; |
1825 | if (nfs4_has_session(server->nfs_client)) | ||
1826 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1429 | /* Serialization for the sequence id */ | 1827 | /* Serialization for the sequence id */ |
1430 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1828 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1431 | if (calldata->arg.seqid == NULL) | 1829 | if (calldata->arg.seqid == NULL) |
@@ -1435,6 +1833,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1435 | calldata->res.fattr = &calldata->fattr; | 1833 | calldata->res.fattr = &calldata->fattr; |
1436 | calldata->res.seqid = calldata->arg.seqid; | 1834 | calldata->res.seqid = calldata->arg.seqid; |
1437 | calldata->res.server = server; | 1835 | calldata->res.server = server; |
1836 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
1438 | calldata->path.mnt = mntget(path->mnt); | 1837 | calldata->path.mnt = mntget(path->mnt); |
1439 | calldata->path.dentry = dget(path->dentry); | 1838 | calldata->path.dentry = dget(path->dentry); |
1440 | 1839 | ||
@@ -1584,15 +1983,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
1584 | 1983 | ||
1585 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1984 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
1586 | { | 1985 | { |
1986 | struct nfs4_server_caps_arg args = { | ||
1987 | .fhandle = fhandle, | ||
1988 | }; | ||
1587 | struct nfs4_server_caps_res res = {}; | 1989 | struct nfs4_server_caps_res res = {}; |
1588 | struct rpc_message msg = { | 1990 | struct rpc_message msg = { |
1589 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], | 1991 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], |
1590 | .rpc_argp = fhandle, | 1992 | .rpc_argp = &args, |
1591 | .rpc_resp = &res, | 1993 | .rpc_resp = &res, |
1592 | }; | 1994 | }; |
1593 | int status; | 1995 | int status; |
1594 | 1996 | ||
1595 | status = rpc_call_sync(server->client, &msg, 0); | 1997 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1596 | if (status == 0) { | 1998 | if (status == 0) { |
1597 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 1999 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
1598 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2000 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
@@ -1606,6 +2008,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1606 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2008 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1607 | server->acl_bitmask = res.acl_bitmask; | 2009 | server->acl_bitmask = res.acl_bitmask; |
1608 | } | 2010 | } |
2011 | |||
1609 | return status; | 2012 | return status; |
1610 | } | 2013 | } |
1611 | 2014 | ||
@@ -1637,8 +2040,9 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1637 | .rpc_argp = &args, | 2040 | .rpc_argp = &args, |
1638 | .rpc_resp = &res, | 2041 | .rpc_resp = &res, |
1639 | }; | 2042 | }; |
2043 | |||
1640 | nfs_fattr_init(info->fattr); | 2044 | nfs_fattr_init(info->fattr); |
1641 | return rpc_call_sync(server->client, &msg, 0); | 2045 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
1642 | } | 2046 | } |
1643 | 2047 | ||
1644 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2048 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -1728,7 +2132,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1728 | }; | 2132 | }; |
1729 | 2133 | ||
1730 | nfs_fattr_init(fattr); | 2134 | nfs_fattr_init(fattr); |
1731 | return rpc_call_sync(server->client, &msg, 0); | 2135 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
1732 | } | 2136 | } |
1733 | 2137 | ||
1734 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2138 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -1812,7 +2216,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
1812 | nfs_fattr_init(fattr); | 2216 | nfs_fattr_init(fattr); |
1813 | 2217 | ||
1814 | dprintk("NFS call lookupfh %s\n", name->name); | 2218 | dprintk("NFS call lookupfh %s\n", name->name); |
1815 | status = rpc_call_sync(server->client, &msg, 0); | 2219 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1816 | dprintk("NFS reply lookupfh: %d\n", status); | 2220 | dprintk("NFS reply lookupfh: %d\n", status); |
1817 | return status; | 2221 | return status; |
1818 | } | 2222 | } |
@@ -1898,7 +2302,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1898 | args.access |= NFS4_ACCESS_EXECUTE; | 2302 | args.access |= NFS4_ACCESS_EXECUTE; |
1899 | } | 2303 | } |
1900 | nfs_fattr_init(&fattr); | 2304 | nfs_fattr_init(&fattr); |
1901 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2305 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1902 | if (!status) { | 2306 | if (!status) { |
1903 | entry->mask = 0; | 2307 | entry->mask = 0; |
1904 | if (res.access & NFS4_ACCESS_READ) | 2308 | if (res.access & NFS4_ACCESS_READ) |
@@ -1957,13 +2361,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
1957 | .pglen = pglen, | 2361 | .pglen = pglen, |
1958 | .pages = &page, | 2362 | .pages = &page, |
1959 | }; | 2363 | }; |
2364 | struct nfs4_readlink_res res; | ||
1960 | struct rpc_message msg = { | 2365 | struct rpc_message msg = { |
1961 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], | 2366 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], |
1962 | .rpc_argp = &args, | 2367 | .rpc_argp = &args, |
1963 | .rpc_resp = NULL, | 2368 | .rpc_resp = &res, |
1964 | }; | 2369 | }; |
1965 | 2370 | ||
1966 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2371 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
1967 | } | 2372 | } |
1968 | 2373 | ||
1969 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2374 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2057,7 +2462,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2057 | int status; | 2462 | int status; |
2058 | 2463 | ||
2059 | nfs_fattr_init(&res.dir_attr); | 2464 | nfs_fattr_init(&res.dir_attr); |
2060 | status = rpc_call_sync(server->client, &msg, 0); | 2465 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
2061 | if (status == 0) { | 2466 | if (status == 0) { |
2062 | update_changeattr(dir, &res.cinfo); | 2467 | update_changeattr(dir, &res.cinfo); |
2063 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2468 | nfs_post_op_update_inode(dir, &res.dir_attr); |
@@ -2092,8 +2497,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2092 | { | 2497 | { |
2093 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2498 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2094 | 2499 | ||
2500 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | ||
2095 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2501 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2096 | return 0; | 2502 | return 0; |
2503 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2097 | update_changeattr(dir, &res->cinfo); | 2504 | update_changeattr(dir, &res->cinfo); |
2098 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2505 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2099 | return 1; | 2506 | return 1; |
@@ -2125,7 +2532,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2125 | 2532 | ||
2126 | nfs_fattr_init(res.old_fattr); | 2533 | nfs_fattr_init(res.old_fattr); |
2127 | nfs_fattr_init(res.new_fattr); | 2534 | nfs_fattr_init(res.new_fattr); |
2128 | status = rpc_call_sync(server->client, &msg, 0); | 2535 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2129 | 2536 | ||
2130 | if (!status) { | 2537 | if (!status) { |
2131 | update_changeattr(old_dir, &res.old_cinfo); | 2538 | update_changeattr(old_dir, &res.old_cinfo); |
@@ -2174,7 +2581,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2174 | 2581 | ||
2175 | nfs_fattr_init(res.fattr); | 2582 | nfs_fattr_init(res.fattr); |
2176 | nfs_fattr_init(res.dir_attr); | 2583 | nfs_fattr_init(res.dir_attr); |
2177 | status = rpc_call_sync(server->client, &msg, 0); | 2584 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2178 | if (!status) { | 2585 | if (!status) { |
2179 | update_changeattr(dir, &res.cinfo); | 2586 | update_changeattr(dir, &res.cinfo); |
2180 | nfs_post_op_update_inode(dir, res.dir_attr); | 2587 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2235,7 +2642,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2235 | 2642 | ||
2236 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2643 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2237 | { | 2644 | { |
2238 | int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 2645 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, |
2646 | &data->arg, &data->res, 1); | ||
2239 | if (status == 0) { | 2647 | if (status == 0) { |
2240 | update_changeattr(dir, &data->res.dir_cinfo); | 2648 | update_changeattr(dir, &data->res.dir_cinfo); |
2241 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2649 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2344,7 +2752,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2344 | (unsigned long long)cookie); | 2752 | (unsigned long long)cookie); |
2345 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2753 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2346 | res.pgbase = args.pgbase; | 2754 | res.pgbase = args.pgbase; |
2347 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2755 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
2348 | if (status == 0) | 2756 | if (status == 0) |
2349 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2757 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2350 | 2758 | ||
@@ -2422,14 +2830,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2422 | .fh = fhandle, | 2830 | .fh = fhandle, |
2423 | .bitmask = server->attr_bitmask, | 2831 | .bitmask = server->attr_bitmask, |
2424 | }; | 2832 | }; |
2833 | struct nfs4_statfs_res res = { | ||
2834 | .fsstat = fsstat, | ||
2835 | }; | ||
2425 | struct rpc_message msg = { | 2836 | struct rpc_message msg = { |
2426 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], | 2837 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], |
2427 | .rpc_argp = &args, | 2838 | .rpc_argp = &args, |
2428 | .rpc_resp = fsstat, | 2839 | .rpc_resp = &res, |
2429 | }; | 2840 | }; |
2430 | 2841 | ||
2431 | nfs_fattr_init(fsstat->fattr); | 2842 | nfs_fattr_init(fsstat->fattr); |
2432 | return rpc_call_sync(server->client, &msg, 0); | 2843 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2433 | } | 2844 | } |
2434 | 2845 | ||
2435 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 2846 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -2451,13 +2862,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2451 | .fh = fhandle, | 2862 | .fh = fhandle, |
2452 | .bitmask = server->attr_bitmask, | 2863 | .bitmask = server->attr_bitmask, |
2453 | }; | 2864 | }; |
2865 | struct nfs4_fsinfo_res res = { | ||
2866 | .fsinfo = fsinfo, | ||
2867 | }; | ||
2454 | struct rpc_message msg = { | 2868 | struct rpc_message msg = { |
2455 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], | 2869 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], |
2456 | .rpc_argp = &args, | 2870 | .rpc_argp = &args, |
2457 | .rpc_resp = fsinfo, | 2871 | .rpc_resp = &res, |
2458 | }; | 2872 | }; |
2459 | 2873 | ||
2460 | return rpc_call_sync(server->client, &msg, 0); | 2874 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2461 | } | 2875 | } |
2462 | 2876 | ||
2463 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2877 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -2486,10 +2900,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2486 | .fh = fhandle, | 2900 | .fh = fhandle, |
2487 | .bitmask = server->attr_bitmask, | 2901 | .bitmask = server->attr_bitmask, |
2488 | }; | 2902 | }; |
2903 | struct nfs4_pathconf_res res = { | ||
2904 | .pathconf = pathconf, | ||
2905 | }; | ||
2489 | struct rpc_message msg = { | 2906 | struct rpc_message msg = { |
2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], | 2907 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], |
2491 | .rpc_argp = &args, | 2908 | .rpc_argp = &args, |
2492 | .rpc_resp = pathconf, | 2909 | .rpc_resp = &res, |
2493 | }; | 2910 | }; |
2494 | 2911 | ||
2495 | /* None of the pathconf attributes are mandatory to implement */ | 2912 | /* None of the pathconf attributes are mandatory to implement */ |
@@ -2499,7 +2916,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2499 | } | 2916 | } |
2500 | 2917 | ||
2501 | nfs_fattr_init(pathconf->fattr); | 2918 | nfs_fattr_init(pathconf->fattr); |
2502 | return rpc_call_sync(server->client, &msg, 0); | 2919 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2503 | } | 2920 | } |
2504 | 2921 | ||
2505 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 2922 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2520,8 +2937,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2520 | { | 2937 | { |
2521 | struct nfs_server *server = NFS_SERVER(data->inode); | 2938 | struct nfs_server *server = NFS_SERVER(data->inode); |
2522 | 2939 | ||
2940 | dprintk("--> %s\n", __func__); | ||
2941 | |||
2942 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2943 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | ||
2944 | |||
2523 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 2945 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2524 | rpc_restart_call(task); | 2946 | nfs4_restart_rpc(task, server->nfs_client); |
2525 | return -EAGAIN; | 2947 | return -EAGAIN; |
2526 | } | 2948 | } |
2527 | 2949 | ||
@@ -2541,8 +2963,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2541 | { | 2963 | { |
2542 | struct inode *inode = data->inode; | 2964 | struct inode *inode = data->inode; |
2543 | 2965 | ||
2966 | /* slot is freed in nfs_writeback_done */ | ||
2967 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2968 | task->tk_status); | ||
2969 | |||
2544 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 2970 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2545 | rpc_restart_call(task); | 2971 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2546 | return -EAGAIN; | 2972 | return -EAGAIN; |
2547 | } | 2973 | } |
2548 | if (task->tk_status >= 0) { | 2974 | if (task->tk_status >= 0) { |
@@ -2567,10 +2993,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2567 | { | 2993 | { |
2568 | struct inode *inode = data->inode; | 2994 | struct inode *inode = data->inode; |
2569 | 2995 | ||
2996 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2997 | task->tk_status); | ||
2570 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 2998 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2571 | rpc_restart_call(task); | 2999 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2572 | return -EAGAIN; | 3000 | return -EAGAIN; |
2573 | } | 3001 | } |
3002 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3003 | &data->res.seq_res); | ||
2574 | nfs_refresh_inode(inode, data->res.fattr); | 3004 | nfs_refresh_inode(inode, data->res.fattr); |
2575 | return 0; | 3005 | return 0; |
2576 | } | 3006 | } |
@@ -2603,6 +3033,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
2603 | if (time_before(clp->cl_last_renewal,timestamp)) | 3033 | if (time_before(clp->cl_last_renewal,timestamp)) |
2604 | clp->cl_last_renewal = timestamp; | 3034 | clp->cl_last_renewal = timestamp; |
2605 | spin_unlock(&clp->cl_lock); | 3035 | spin_unlock(&clp->cl_lock); |
3036 | dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__, | ||
3037 | task->tk_msg.rpc_cred); | ||
3038 | put_rpccred(task->tk_msg.rpc_cred); | ||
2606 | } | 3039 | } |
2607 | 3040 | ||
2608 | static const struct rpc_call_ops nfs4_renew_ops = { | 3041 | static const struct rpc_call_ops nfs4_renew_ops = { |
@@ -2742,12 +3175,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2742 | .acl_pages = pages, | 3175 | .acl_pages = pages, |
2743 | .acl_len = buflen, | 3176 | .acl_len = buflen, |
2744 | }; | 3177 | }; |
2745 | size_t resp_len = buflen; | 3178 | struct nfs_getaclres res = { |
3179 | .acl_len = buflen, | ||
3180 | }; | ||
2746 | void *resp_buf; | 3181 | void *resp_buf; |
2747 | struct rpc_message msg = { | 3182 | struct rpc_message msg = { |
2748 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3183 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
2749 | .rpc_argp = &args, | 3184 | .rpc_argp = &args, |
2750 | .rpc_resp = &resp_len, | 3185 | .rpc_resp = &res, |
2751 | }; | 3186 | }; |
2752 | struct page *localpage = NULL; | 3187 | struct page *localpage = NULL; |
2753 | int ret; | 3188 | int ret; |
@@ -2761,26 +3196,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2761 | return -ENOMEM; | 3196 | return -ENOMEM; |
2762 | args.acl_pages[0] = localpage; | 3197 | args.acl_pages[0] = localpage; |
2763 | args.acl_pgbase = 0; | 3198 | args.acl_pgbase = 0; |
2764 | resp_len = args.acl_len = PAGE_SIZE; | 3199 | args.acl_len = PAGE_SIZE; |
2765 | } else { | 3200 | } else { |
2766 | resp_buf = buf; | 3201 | resp_buf = buf; |
2767 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3202 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
2768 | } | 3203 | } |
2769 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3204 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
2770 | if (ret) | 3205 | if (ret) |
2771 | goto out_free; | 3206 | goto out_free; |
2772 | if (resp_len > args.acl_len) | 3207 | if (res.acl_len > args.acl_len) |
2773 | nfs4_write_cached_acl(inode, NULL, resp_len); | 3208 | nfs4_write_cached_acl(inode, NULL, res.acl_len); |
2774 | else | 3209 | else |
2775 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | 3210 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); |
2776 | if (buf) { | 3211 | if (buf) { |
2777 | ret = -ERANGE; | 3212 | ret = -ERANGE; |
2778 | if (resp_len > buflen) | 3213 | if (res.acl_len > buflen) |
2779 | goto out_free; | 3214 | goto out_free; |
2780 | if (localpage) | 3215 | if (localpage) |
2781 | memcpy(buf, resp_buf, resp_len); | 3216 | memcpy(buf, resp_buf, res.acl_len); |
2782 | } | 3217 | } |
2783 | ret = resp_len; | 3218 | ret = res.acl_len; |
2784 | out_free: | 3219 | out_free: |
2785 | if (localpage) | 3220 | if (localpage) |
2786 | __free_page(localpage); | 3221 | __free_page(localpage); |
@@ -2810,8 +3245,6 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
2810 | ret = nfs_revalidate_inode(server, inode); | 3245 | ret = nfs_revalidate_inode(server, inode); |
2811 | if (ret < 0) | 3246 | if (ret < 0) |
2812 | return ret; | 3247 | return ret; |
2813 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
2814 | nfs_zap_acl_cache(inode); | ||
2815 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3248 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
2816 | if (ret != -ENOENT) | 3249 | if (ret != -ENOENT) |
2817 | return ret; | 3250 | return ret; |
@@ -2827,10 +3260,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2827 | .acl_pages = pages, | 3260 | .acl_pages = pages, |
2828 | .acl_len = buflen, | 3261 | .acl_len = buflen, |
2829 | }; | 3262 | }; |
3263 | struct nfs_setaclres res; | ||
2830 | struct rpc_message msg = { | 3264 | struct rpc_message msg = { |
2831 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | 3265 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], |
2832 | .rpc_argp = &arg, | 3266 | .rpc_argp = &arg, |
2833 | .rpc_resp = NULL, | 3267 | .rpc_resp = &res, |
2834 | }; | 3268 | }; |
2835 | int ret; | 3269 | int ret; |
2836 | 3270 | ||
@@ -2838,7 +3272,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2838 | return -EOPNOTSUPP; | 3272 | return -EOPNOTSUPP; |
2839 | nfs_inode_return_delegation(inode); | 3273 | nfs_inode_return_delegation(inode); |
2840 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3274 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2841 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3275 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2842 | nfs_access_zap_cache(inode); | 3276 | nfs_access_zap_cache(inode); |
2843 | nfs_zap_acl_cache(inode); | 3277 | nfs_zap_acl_cache(inode); |
2844 | return ret; | 3278 | return ret; |
@@ -2857,10 +3291,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2857 | } | 3291 | } |
2858 | 3292 | ||
2859 | static int | 3293 | static int |
2860 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3294 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) |
2861 | { | 3295 | { |
2862 | struct nfs_client *clp = server->nfs_client; | ||
2863 | |||
2864 | if (!clp || task->tk_status >= 0) | 3296 | if (!clp || task->tk_status >= 0) |
2865 | return 0; | 3297 | return 0; |
2866 | switch(task->tk_status) { | 3298 | switch(task->tk_status) { |
@@ -2879,8 +3311,23 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2879 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3311 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2880 | task->tk_status = 0; | 3312 | task->tk_status = 0; |
2881 | return -EAGAIN; | 3313 | return -EAGAIN; |
3314 | #if defined(CONFIG_NFS_V4_1) | ||
3315 | case -NFS4ERR_BADSESSION: | ||
3316 | case -NFS4ERR_BADSLOT: | ||
3317 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
3318 | case -NFS4ERR_DEADSESSION: | ||
3319 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
3320 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
3321 | case -NFS4ERR_SEQ_MISORDERED: | ||
3322 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
3323 | task->tk_status); | ||
3324 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
3325 | task->tk_status = 0; | ||
3326 | return -EAGAIN; | ||
3327 | #endif /* CONFIG_NFS_V4_1 */ | ||
2882 | case -NFS4ERR_DELAY: | 3328 | case -NFS4ERR_DELAY: |
2883 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3329 | if (server) |
3330 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
2884 | case -NFS4ERR_GRACE: | 3331 | case -NFS4ERR_GRACE: |
2885 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3332 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
2886 | task->tk_status = 0; | 3333 | task->tk_status = 0; |
@@ -2893,6 +3340,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2893 | return 0; | 3340 | return 0; |
2894 | } | 3341 | } |
2895 | 3342 | ||
3343 | static int | ||
3344 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
3345 | { | ||
3346 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
3347 | } | ||
3348 | |||
2896 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3349 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2897 | { | 3350 | { |
2898 | nfs4_verifier sc_verifier; | 3351 | nfs4_verifier sc_verifier; |
@@ -3000,6 +3453,10 @@ struct nfs4_delegreturndata { | |||
3000 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 3453 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
3001 | { | 3454 | { |
3002 | struct nfs4_delegreturndata *data = calldata; | 3455 | struct nfs4_delegreturndata *data = calldata; |
3456 | |||
3457 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | ||
3458 | task->tk_status); | ||
3459 | |||
3003 | data->rpc_status = task->tk_status; | 3460 | data->rpc_status = task->tk_status; |
3004 | if (data->rpc_status == 0) | 3461 | if (data->rpc_status == 0) |
3005 | renew_lease(data->res.server, data->timestamp); | 3462 | renew_lease(data->res.server, data->timestamp); |
@@ -3010,7 +3467,25 @@ static void nfs4_delegreturn_release(void *calldata) | |||
3010 | kfree(calldata); | 3467 | kfree(calldata); |
3011 | } | 3468 | } |
3012 | 3469 | ||
3470 | #if defined(CONFIG_NFS_V4_1) | ||
3471 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | ||
3472 | { | ||
3473 | struct nfs4_delegreturndata *d_data; | ||
3474 | |||
3475 | d_data = (struct nfs4_delegreturndata *)data; | ||
3476 | |||
3477 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | ||
3478 | &d_data->args.seq_args, | ||
3479 | &d_data->res.seq_res, 1, task)) | ||
3480 | return; | ||
3481 | rpc_call_start(task); | ||
3482 | } | ||
3483 | #endif /* CONFIG_NFS_V4_1 */ | ||
3484 | |||
3013 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 3485 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
3486 | #if defined(CONFIG_NFS_V4_1) | ||
3487 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
3488 | #endif /* CONFIG_NFS_V4_1 */ | ||
3014 | .rpc_call_done = nfs4_delegreturn_done, | 3489 | .rpc_call_done = nfs4_delegreturn_done, |
3015 | .rpc_release = nfs4_delegreturn_release, | 3490 | .rpc_release = nfs4_delegreturn_release, |
3016 | }; | 3491 | }; |
@@ -3032,7 +3507,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3032 | }; | 3507 | }; |
3033 | int status = 0; | 3508 | int status = 0; |
3034 | 3509 | ||
3035 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3510 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
3036 | if (data == NULL) | 3511 | if (data == NULL) |
3037 | return -ENOMEM; | 3512 | return -ENOMEM; |
3038 | data->args.fhandle = &data->fh; | 3513 | data->args.fhandle = &data->fh; |
@@ -3042,6 +3517,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3042 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3517 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3043 | data->res.fattr = &data->fattr; | 3518 | data->res.fattr = &data->fattr; |
3044 | data->res.server = server; | 3519 | data->res.server = server; |
3520 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3045 | nfs_fattr_init(data->res.fattr); | 3521 | nfs_fattr_init(data->res.fattr); |
3046 | data->timestamp = jiffies; | 3522 | data->timestamp = jiffies; |
3047 | data->rpc_status = 0; | 3523 | data->rpc_status = 0; |
@@ -3127,7 +3603,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3127 | goto out; | 3603 | goto out; |
3128 | lsp = request->fl_u.nfs4_fl.owner; | 3604 | lsp = request->fl_u.nfs4_fl.owner; |
3129 | arg.lock_owner.id = lsp->ls_id.id; | 3605 | arg.lock_owner.id = lsp->ls_id.id; |
3130 | status = rpc_call_sync(server->client, &msg, 0); | 3606 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3131 | switch (status) { | 3607 | switch (status) { |
3132 | case 0: | 3608 | case 0: |
3133 | request->fl_type = F_UNLCK; | 3609 | request->fl_type = F_UNLCK; |
@@ -3187,13 +3663,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3187 | struct nfs4_unlockdata *p; | 3663 | struct nfs4_unlockdata *p; |
3188 | struct inode *inode = lsp->ls_state->inode; | 3664 | struct inode *inode = lsp->ls_state->inode; |
3189 | 3665 | ||
3190 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 3666 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
3191 | if (p == NULL) | 3667 | if (p == NULL) |
3192 | return NULL; | 3668 | return NULL; |
3193 | p->arg.fh = NFS_FH(inode); | 3669 | p->arg.fh = NFS_FH(inode); |
3194 | p->arg.fl = &p->fl; | 3670 | p->arg.fl = &p->fl; |
3195 | p->arg.seqid = seqid; | 3671 | p->arg.seqid = seqid; |
3196 | p->res.seqid = seqid; | 3672 | p->res.seqid = seqid; |
3673 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3197 | p->arg.stateid = &lsp->ls_stateid; | 3674 | p->arg.stateid = &lsp->ls_stateid; |
3198 | p->lsp = lsp; | 3675 | p->lsp = lsp; |
3199 | atomic_inc(&lsp->ls_count); | 3676 | atomic_inc(&lsp->ls_count); |
@@ -3217,6 +3694,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3217 | { | 3694 | { |
3218 | struct nfs4_unlockdata *calldata = data; | 3695 | struct nfs4_unlockdata *calldata = data; |
3219 | 3696 | ||
3697 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | ||
3698 | task->tk_status); | ||
3220 | if (RPC_ASSASSINATED(task)) | 3699 | if (RPC_ASSASSINATED(task)) |
3221 | return; | 3700 | return; |
3222 | switch (task->tk_status) { | 3701 | switch (task->tk_status) { |
@@ -3233,8 +3712,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3233 | break; | 3712 | break; |
3234 | default: | 3713 | default: |
3235 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3714 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3236 | rpc_restart_call(task); | 3715 | nfs4_restart_rpc(task, |
3716 | calldata->server->nfs_client); | ||
3237 | } | 3717 | } |
3718 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3719 | &calldata->res.seq_res); | ||
3238 | } | 3720 | } |
3239 | 3721 | ||
3240 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3722 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3249,6 +3731,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3249 | return; | 3731 | return; |
3250 | } | 3732 | } |
3251 | calldata->timestamp = jiffies; | 3733 | calldata->timestamp = jiffies; |
3734 | if (nfs4_setup_sequence(calldata->server->nfs_client, | ||
3735 | &calldata->arg.seq_args, | ||
3736 | &calldata->res.seq_res, 1, task)) | ||
3737 | return; | ||
3252 | rpc_call_start(task); | 3738 | rpc_call_start(task); |
3253 | } | 3739 | } |
3254 | 3740 | ||
@@ -3341,6 +3827,7 @@ struct nfs4_lockdata { | |||
3341 | unsigned long timestamp; | 3827 | unsigned long timestamp; |
3342 | int rpc_status; | 3828 | int rpc_status; |
3343 | int cancelled; | 3829 | int cancelled; |
3830 | struct nfs_server *server; | ||
3344 | }; | 3831 | }; |
3345 | 3832 | ||
3346 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 3833 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
@@ -3366,7 +3853,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3366 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3853 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3367 | p->arg.lock_owner.id = lsp->ls_id.id; | 3854 | p->arg.lock_owner.id = lsp->ls_id.id; |
3368 | p->res.lock_seqid = p->arg.lock_seqid; | 3855 | p->res.lock_seqid = p->arg.lock_seqid; |
3856 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3369 | p->lsp = lsp; | 3857 | p->lsp = lsp; |
3858 | p->server = server; | ||
3370 | atomic_inc(&lsp->ls_count); | 3859 | atomic_inc(&lsp->ls_count); |
3371 | p->ctx = get_nfs_open_context(ctx); | 3860 | p->ctx = get_nfs_open_context(ctx); |
3372 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3861 | memcpy(&p->fl, fl, sizeof(p->fl)); |
@@ -3396,6 +3885,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3396 | } else | 3885 | } else |
3397 | data->arg.new_lock_owner = 0; | 3886 | data->arg.new_lock_owner = 0; |
3398 | data->timestamp = jiffies; | 3887 | data->timestamp = jiffies; |
3888 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | ||
3889 | &data->res.seq_res, 1, task)) | ||
3890 | return; | ||
3399 | rpc_call_start(task); | 3891 | rpc_call_start(task); |
3400 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 3892 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3401 | } | 3893 | } |
@@ -3406,6 +3898,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3406 | 3898 | ||
3407 | dprintk("%s: begin!\n", __func__); | 3899 | dprintk("%s: begin!\n", __func__); |
3408 | 3900 | ||
3901 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | ||
3902 | task->tk_status); | ||
3903 | |||
3409 | data->rpc_status = task->tk_status; | 3904 | data->rpc_status = task->tk_status; |
3410 | if (RPC_ASSASSINATED(task)) | 3905 | if (RPC_ASSASSINATED(task)) |
3411 | goto out; | 3906 | goto out; |
@@ -3487,8 +3982,6 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
3487 | ret = nfs4_wait_for_completion_rpc_task(task); | 3982 | ret = nfs4_wait_for_completion_rpc_task(task); |
3488 | if (ret == 0) { | 3983 | if (ret == 0) { |
3489 | ret = data->rpc_status; | 3984 | ret = data->rpc_status; |
3490 | if (ret == -NFS4ERR_DENIED) | ||
3491 | ret = -EAGAIN; | ||
3492 | } else | 3985 | } else |
3493 | data->cancelled = 1; | 3986 | data->cancelled = 1; |
3494 | rpc_put_task(task); | 3987 | rpc_put_task(task); |
@@ -3576,9 +4069,11 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock * | |||
3576 | int err; | 4069 | int err; |
3577 | 4070 | ||
3578 | do { | 4071 | do { |
4072 | err = _nfs4_proc_setlk(state, cmd, request); | ||
4073 | if (err == -NFS4ERR_DENIED) | ||
4074 | err = -EAGAIN; | ||
3579 | err = nfs4_handle_exception(NFS_SERVER(state->inode), | 4075 | err = nfs4_handle_exception(NFS_SERVER(state->inode), |
3580 | _nfs4_proc_setlk(state, cmd, request), | 4076 | err, &exception); |
3581 | &exception); | ||
3582 | } while (exception.retry); | 4077 | } while (exception.retry); |
3583 | return err; | 4078 | return err; |
3584 | } | 4079 | } |
@@ -3598,15 +4093,23 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request) | |||
3598 | if (request->fl_start < 0 || request->fl_end < 0) | 4093 | if (request->fl_start < 0 || request->fl_end < 0) |
3599 | return -EINVAL; | 4094 | return -EINVAL; |
3600 | 4095 | ||
3601 | if (IS_GETLK(cmd)) | 4096 | if (IS_GETLK(cmd)) { |
3602 | return nfs4_proc_getlk(state, F_GETLK, request); | 4097 | if (state != NULL) |
4098 | return nfs4_proc_getlk(state, F_GETLK, request); | ||
4099 | return 0; | ||
4100 | } | ||
3603 | 4101 | ||
3604 | if (!(IS_SETLK(cmd) || IS_SETLKW(cmd))) | 4102 | if (!(IS_SETLK(cmd) || IS_SETLKW(cmd))) |
3605 | return -EINVAL; | 4103 | return -EINVAL; |
3606 | 4104 | ||
3607 | if (request->fl_type == F_UNLCK) | 4105 | if (request->fl_type == F_UNLCK) { |
3608 | return nfs4_proc_unlck(state, cmd, request); | 4106 | if (state != NULL) |
4107 | return nfs4_proc_unlck(state, cmd, request); | ||
4108 | return 0; | ||
4109 | } | ||
3609 | 4110 | ||
4111 | if (state == NULL) | ||
4112 | return -ENOLCK; | ||
3610 | do { | 4113 | do { |
3611 | status = nfs4_proc_setlk(state, cmd, request); | 4114 | status = nfs4_proc_setlk(state, cmd, request); |
3612 | if ((status != -EAGAIN) || IS_SETLK(cmd)) | 4115 | if ((status != -EAGAIN) || IS_SETLK(cmd)) |
@@ -3630,8 +4133,37 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
3630 | goto out; | 4133 | goto out; |
3631 | do { | 4134 | do { |
3632 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); | 4135 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); |
3633 | if (err != -NFS4ERR_DELAY) | 4136 | switch (err) { |
3634 | break; | 4137 | default: |
4138 | printk(KERN_ERR "%s: unhandled error %d.\n", | ||
4139 | __func__, err); | ||
4140 | case 0: | ||
4141 | case -ESTALE: | ||
4142 | goto out; | ||
4143 | case -NFS4ERR_EXPIRED: | ||
4144 | case -NFS4ERR_STALE_CLIENTID: | ||
4145 | case -NFS4ERR_STALE_STATEID: | ||
4146 | nfs4_schedule_state_recovery(server->nfs_client); | ||
4147 | goto out; | ||
4148 | case -ERESTARTSYS: | ||
4149 | /* | ||
4150 | * The show must go on: exit, but mark the | ||
4151 | * stateid as needing recovery. | ||
4152 | */ | ||
4153 | case -NFS4ERR_ADMIN_REVOKED: | ||
4154 | case -NFS4ERR_BAD_STATEID: | ||
4155 | case -NFS4ERR_OPENMODE: | ||
4156 | nfs4_state_mark_reclaim_nograce(server->nfs_client, state); | ||
4157 | err = 0; | ||
4158 | goto out; | ||
4159 | case -ENOMEM: | ||
4160 | case -NFS4ERR_DENIED: | ||
4161 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | ||
4162 | err = 0; | ||
4163 | goto out; | ||
4164 | case -NFS4ERR_DELAY: | ||
4165 | break; | ||
4166 | } | ||
3635 | err = nfs4_handle_exception(server, err, &exception); | 4167 | err = nfs4_handle_exception(server, err, &exception); |
3636 | } while (exception.retry); | 4168 | } while (exception.retry); |
3637 | out: | 4169 | out: |
@@ -3706,10 +4238,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3706 | .page = page, | 4238 | .page = page, |
3707 | .bitmask = bitmask, | 4239 | .bitmask = bitmask, |
3708 | }; | 4240 | }; |
4241 | struct nfs4_fs_locations_res res = { | ||
4242 | .fs_locations = fs_locations, | ||
4243 | }; | ||
3709 | struct rpc_message msg = { | 4244 | struct rpc_message msg = { |
3710 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | 4245 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], |
3711 | .rpc_argp = &args, | 4246 | .rpc_argp = &args, |
3712 | .rpc_resp = fs_locations, | 4247 | .rpc_resp = &res, |
3713 | }; | 4248 | }; |
3714 | int status; | 4249 | int status; |
3715 | 4250 | ||
@@ -3717,24 +4252,736 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3717 | nfs_fattr_init(&fs_locations->fattr); | 4252 | nfs_fattr_init(&fs_locations->fattr); |
3718 | fs_locations->server = server; | 4253 | fs_locations->server = server; |
3719 | fs_locations->nlocations = 0; | 4254 | fs_locations->nlocations = 0; |
3720 | status = rpc_call_sync(server->client, &msg, 0); | 4255 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
3721 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4256 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
3722 | dprintk("%s: returned status = %d\n", __func__, status); | 4257 | dprintk("%s: returned status = %d\n", __func__, status); |
3723 | return status; | 4258 | return status; |
3724 | } | 4259 | } |
3725 | 4260 | ||
3726 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4261 | #ifdef CONFIG_NFS_V4_1 |
4262 | /* | ||
4263 | * nfs4_proc_exchange_id() | ||
4264 | * | ||
4265 | * Since the clientid has expired, all compounds using sessions | ||
4266 | * associated with the stale clientid will be returning | ||
4267 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
4268 | * be in some phase of session reset. | ||
4269 | */ | ||
4270 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
4271 | { | ||
4272 | nfs4_verifier verifier; | ||
4273 | struct nfs41_exchange_id_args args = { | ||
4274 | .client = clp, | ||
4275 | .flags = clp->cl_exchange_flags, | ||
4276 | }; | ||
4277 | struct nfs41_exchange_id_res res = { | ||
4278 | .client = clp, | ||
4279 | }; | ||
4280 | int status; | ||
4281 | struct rpc_message msg = { | ||
4282 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
4283 | .rpc_argp = &args, | ||
4284 | .rpc_resp = &res, | ||
4285 | .rpc_cred = cred, | ||
4286 | }; | ||
4287 | __be32 *p; | ||
4288 | |||
4289 | dprintk("--> %s\n", __func__); | ||
4290 | BUG_ON(clp == NULL); | ||
4291 | |||
4292 | p = (u32 *)verifier.data; | ||
4293 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4294 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4295 | args.verifier = &verifier; | ||
4296 | |||
4297 | while (1) { | ||
4298 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
4299 | "%s/%s %u", | ||
4300 | clp->cl_ipaddr, | ||
4301 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
4302 | RPC_DISPLAY_ADDR), | ||
4303 | clp->cl_id_uniquifier); | ||
4304 | |||
4305 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4306 | |||
4307 | if (status != NFS4ERR_CLID_INUSE) | ||
4308 | break; | ||
4309 | |||
4310 | if (signalled()) | ||
4311 | break; | ||
4312 | |||
4313 | if (++clp->cl_id_uniquifier == 0) | ||
4314 | break; | ||
4315 | } | ||
4316 | |||
4317 | dprintk("<-- %s status= %d\n", __func__, status); | ||
4318 | return status; | ||
4319 | } | ||
4320 | |||
4321 | struct nfs4_get_lease_time_data { | ||
4322 | struct nfs4_get_lease_time_args *args; | ||
4323 | struct nfs4_get_lease_time_res *res; | ||
4324 | struct nfs_client *clp; | ||
4325 | }; | ||
4326 | |||
4327 | static void nfs4_get_lease_time_prepare(struct rpc_task *task, | ||
4328 | void *calldata) | ||
4329 | { | ||
4330 | int ret; | ||
4331 | struct nfs4_get_lease_time_data *data = | ||
4332 | (struct nfs4_get_lease_time_data *)calldata; | ||
4333 | |||
4334 | dprintk("--> %s\n", __func__); | ||
4335 | /* just setup sequence, do not trigger session recovery | ||
4336 | since we're invoked within one */ | ||
4337 | ret = nfs41_setup_sequence(data->clp->cl_session, | ||
4338 | &data->args->la_seq_args, | ||
4339 | &data->res->lr_seq_res, 0, task); | ||
4340 | |||
4341 | BUG_ON(ret == -EAGAIN); | ||
4342 | rpc_call_start(task); | ||
4343 | dprintk("<-- %s\n", __func__); | ||
4344 | } | ||
4345 | |||
4346 | /* | ||
4347 | * Called from nfs4_state_manager thread for session setup, so don't recover | ||
4348 | * from sequence operation or clientid errors. | ||
4349 | */ | ||
4350 | static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | ||
4351 | { | ||
4352 | struct nfs4_get_lease_time_data *data = | ||
4353 | (struct nfs4_get_lease_time_data *)calldata; | ||
4354 | |||
4355 | dprintk("--> %s\n", __func__); | ||
4356 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | ||
4357 | switch (task->tk_status) { | ||
4358 | case -NFS4ERR_DELAY: | ||
4359 | case -NFS4ERR_GRACE: | ||
4360 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | ||
4361 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | ||
4362 | task->tk_status = 0; | ||
4363 | nfs4_restart_rpc(task, data->clp); | ||
4364 | return; | ||
4365 | } | ||
4366 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4367 | dprintk("<-- %s\n", __func__); | ||
4368 | } | ||
4369 | |||
4370 | struct rpc_call_ops nfs4_get_lease_time_ops = { | ||
4371 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | ||
4372 | .rpc_call_done = nfs4_get_lease_time_done, | ||
4373 | }; | ||
4374 | |||
4375 | int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | ||
4376 | { | ||
4377 | struct rpc_task *task; | ||
4378 | struct nfs4_get_lease_time_args args; | ||
4379 | struct nfs4_get_lease_time_res res = { | ||
4380 | .lr_fsinfo = fsinfo, | ||
4381 | }; | ||
4382 | struct nfs4_get_lease_time_data data = { | ||
4383 | .args = &args, | ||
4384 | .res = &res, | ||
4385 | .clp = clp, | ||
4386 | }; | ||
4387 | struct rpc_message msg = { | ||
4388 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME], | ||
4389 | .rpc_argp = &args, | ||
4390 | .rpc_resp = &res, | ||
4391 | }; | ||
4392 | struct rpc_task_setup task_setup = { | ||
4393 | .rpc_client = clp->cl_rpcclient, | ||
4394 | .rpc_message = &msg, | ||
4395 | .callback_ops = &nfs4_get_lease_time_ops, | ||
4396 | .callback_data = &data | ||
4397 | }; | ||
4398 | int status; | ||
4399 | |||
4400 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4401 | dprintk("--> %s\n", __func__); | ||
4402 | task = rpc_run_task(&task_setup); | ||
4403 | |||
4404 | if (IS_ERR(task)) | ||
4405 | status = PTR_ERR(task); | ||
4406 | else { | ||
4407 | status = task->tk_status; | ||
4408 | rpc_put_task(task); | ||
4409 | } | ||
4410 | dprintk("<-- %s return %d\n", __func__, status); | ||
4411 | |||
4412 | return status; | ||
4413 | } | ||
4414 | |||
4415 | /* | ||
4416 | * Reset a slot table | ||
4417 | */ | ||
4418 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | ||
4419 | int old_max_slots, int ivalue) | ||
4420 | { | ||
4421 | int i; | ||
4422 | int ret = 0; | ||
4423 | |||
4424 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | ||
4425 | |||
4426 | /* | ||
4427 | * Until we have dynamic slot table adjustment, insist | ||
4428 | * upon the same slot table size | ||
4429 | */ | ||
4430 | if (max_slots != old_max_slots) { | ||
4431 | dprintk("%s reset slot table does't match old\n", | ||
4432 | __func__); | ||
4433 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | ||
4434 | goto out; | ||
4435 | } | ||
4436 | spin_lock(&tbl->slot_tbl_lock); | ||
4437 | for (i = 0; i < max_slots; ++i) | ||
4438 | tbl->slots[i].seq_nr = ivalue; | ||
4439 | tbl->highest_used_slotid = -1; | ||
4440 | spin_unlock(&tbl->slot_tbl_lock); | ||
4441 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4442 | tbl, tbl->slots, tbl->max_slots); | ||
4443 | out: | ||
4444 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4445 | return ret; | ||
4446 | } | ||
4447 | |||
4448 | /* | ||
4449 | * Reset the forechannel and backchannel slot tables | ||
4450 | */ | ||
4451 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
4452 | { | ||
4453 | int status; | ||
4454 | |||
4455 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
4456 | session->fc_attrs.max_reqs, | ||
4457 | session->fc_slot_table.max_slots, | ||
4458 | 1); | ||
4459 | if (status) | ||
4460 | return status; | ||
4461 | |||
4462 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
4463 | session->bc_attrs.max_reqs, | ||
4464 | session->bc_slot_table.max_slots, | ||
4465 | 0); | ||
4466 | return status; | ||
4467 | } | ||
4468 | |||
4469 | /* Destroy the slot table */ | ||
4470 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
4471 | { | ||
4472 | if (session->fc_slot_table.slots != NULL) { | ||
4473 | kfree(session->fc_slot_table.slots); | ||
4474 | session->fc_slot_table.slots = NULL; | ||
4475 | } | ||
4476 | if (session->bc_slot_table.slots != NULL) { | ||
4477 | kfree(session->bc_slot_table.slots); | ||
4478 | session->bc_slot_table.slots = NULL; | ||
4479 | } | ||
4480 | return; | ||
4481 | } | ||
4482 | |||
4483 | /* | ||
4484 | * Initialize slot table | ||
4485 | */ | ||
4486 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
4487 | int max_slots, int ivalue) | ||
4488 | { | ||
4489 | int i; | ||
4490 | struct nfs4_slot *slot; | ||
4491 | int ret = -ENOMEM; | ||
4492 | |||
4493 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
4494 | |||
4495 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
4496 | |||
4497 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | ||
4498 | if (!slot) | ||
4499 | goto out; | ||
4500 | for (i = 0; i < max_slots; ++i) | ||
4501 | slot[i].seq_nr = ivalue; | ||
4502 | ret = 0; | ||
4503 | |||
4504 | spin_lock(&tbl->slot_tbl_lock); | ||
4505 | if (tbl->slots != NULL) { | ||
4506 | spin_unlock(&tbl->slot_tbl_lock); | ||
4507 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4508 | __func__, tbl, tbl->slots); | ||
4509 | WARN_ON(1); | ||
4510 | goto out_free; | ||
4511 | } | ||
4512 | tbl->max_slots = max_slots; | ||
4513 | tbl->slots = slot; | ||
4514 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
4515 | spin_unlock(&tbl->slot_tbl_lock); | ||
4516 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4517 | tbl, tbl->slots, tbl->max_slots); | ||
4518 | out: | ||
4519 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4520 | return ret; | ||
4521 | |||
4522 | out_free: | ||
4523 | kfree(slot); | ||
4524 | goto out; | ||
4525 | } | ||
4526 | |||
4527 | /* | ||
4528 | * Initialize the forechannel and backchannel tables | ||
4529 | */ | ||
4530 | static int nfs4_init_slot_tables(struct nfs4_session *session) | ||
4531 | { | ||
4532 | int status; | ||
4533 | |||
4534 | status = nfs4_init_slot_table(&session->fc_slot_table, | ||
4535 | session->fc_attrs.max_reqs, 1); | ||
4536 | if (status) | ||
4537 | return status; | ||
4538 | |||
4539 | status = nfs4_init_slot_table(&session->bc_slot_table, | ||
4540 | session->bc_attrs.max_reqs, 0); | ||
4541 | if (status) | ||
4542 | nfs4_destroy_slot_tables(session); | ||
4543 | |||
4544 | return status; | ||
4545 | } | ||
4546 | |||
4547 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
4548 | { | ||
4549 | struct nfs4_session *session; | ||
4550 | struct nfs4_slot_table *tbl; | ||
4551 | |||
4552 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | ||
4553 | if (!session) | ||
4554 | return NULL; | ||
4555 | |||
4556 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4557 | /* | ||
4558 | * The create session reply races with the server back | ||
4559 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4560 | * so that the client back channel can find the | ||
4561 | * nfs_client struct | ||
4562 | */ | ||
4563 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4564 | |||
4565 | tbl = &session->fc_slot_table; | ||
4566 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4567 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
4568 | |||
4569 | tbl = &session->bc_slot_table; | ||
4570 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4571 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
4572 | |||
4573 | session->clp = clp; | ||
4574 | return session; | ||
4575 | } | ||
4576 | |||
4577 | void nfs4_destroy_session(struct nfs4_session *session) | ||
4578 | { | ||
4579 | nfs4_proc_destroy_session(session); | ||
4580 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
4581 | __func__, session->clp->cl_rpcclient->cl_xprt); | ||
4582 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | ||
4583 | NFS41_BC_MIN_CALLBACKS); | ||
4584 | nfs4_destroy_slot_tables(session); | ||
4585 | kfree(session); | ||
4586 | } | ||
4587 | |||
4588 | /* | ||
4589 | * Initialize the values to be used by the client in CREATE_SESSION | ||
4590 | * If nfs4_init_session set the fore channel request and response sizes, | ||
4591 | * use them. | ||
4592 | * | ||
4593 | * Set the back channel max_resp_sz_cached to zero to force the client to | ||
4594 | * always set csa_cachethis to FALSE because the current implementation | ||
4595 | * of the back channel DRC only supports caching the CB_SEQUENCE operation. | ||
4596 | */ | ||
4597 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | ||
4598 | { | ||
4599 | struct nfs4_session *session = args->client->cl_session; | ||
4600 | unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, | ||
4601 | mxresp_sz = session->fc_attrs.max_resp_sz; | ||
4602 | |||
4603 | if (mxrqst_sz == 0) | ||
4604 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
4605 | if (mxresp_sz == 0) | ||
4606 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
4607 | /* Fore channel attributes */ | ||
4608 | args->fc_attrs.headerpadsz = 0; | ||
4609 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | ||
4610 | args->fc_attrs.max_resp_sz = mxresp_sz; | ||
4611 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4612 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | ||
4613 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | ||
4614 | |||
4615 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4616 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4617 | __func__, | ||
4618 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | ||
4619 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | ||
4620 | args->fc_attrs.max_reqs); | ||
4621 | |||
4622 | /* Back channel attributes */ | ||
4623 | args->bc_attrs.headerpadsz = 0; | ||
4624 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | ||
4625 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | ||
4626 | args->bc_attrs.max_resp_sz_cached = 0; | ||
4627 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | ||
4628 | args->bc_attrs.max_reqs = 1; | ||
4629 | |||
4630 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4631 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4632 | __func__, | ||
4633 | args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz, | ||
4634 | args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops, | ||
4635 | args->bc_attrs.max_reqs); | ||
4636 | } | ||
4637 | |||
4638 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | ||
4639 | { | ||
4640 | if (rcvd <= sent) | ||
4641 | return 0; | ||
4642 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | ||
4643 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | ||
4644 | return -EINVAL; | ||
4645 | } | ||
4646 | |||
4647 | #define _verify_fore_channel_attr(_name_) \ | ||
4648 | _verify_channel_attr("fore", #_name_, \ | ||
4649 | args->fc_attrs._name_, \ | ||
4650 | session->fc_attrs._name_) | ||
4651 | |||
4652 | #define _verify_back_channel_attr(_name_) \ | ||
4653 | _verify_channel_attr("back", #_name_, \ | ||
4654 | args->bc_attrs._name_, \ | ||
4655 | session->bc_attrs._name_) | ||
4656 | |||
4657 | /* | ||
4658 | * The server is not allowed to increase the fore channel header pad size, | ||
4659 | * maximum response size, or maximum number of operations. | ||
4660 | * | ||
4661 | * The back channel attributes are only negotiatied down: We send what the | ||
4662 | * (back channel) server insists upon. | ||
4663 | */ | ||
4664 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | ||
4665 | struct nfs4_session *session) | ||
4666 | { | ||
4667 | int ret = 0; | ||
4668 | |||
4669 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4670 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4671 | ret |= _verify_fore_channel_attr(max_ops); | ||
4672 | |||
4673 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4674 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4675 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4676 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4677 | ret |= _verify_back_channel_attr(max_ops); | ||
4678 | ret |= _verify_back_channel_attr(max_reqs); | ||
4679 | |||
4680 | return ret; | ||
4681 | } | ||
4682 | |||
4683 | static int _nfs4_proc_create_session(struct nfs_client *clp) | ||
4684 | { | ||
4685 | struct nfs4_session *session = clp->cl_session; | ||
4686 | struct nfs41_create_session_args args = { | ||
4687 | .client = clp, | ||
4688 | .cb_program = NFS4_CALLBACK, | ||
4689 | }; | ||
4690 | struct nfs41_create_session_res res = { | ||
4691 | .client = clp, | ||
4692 | }; | ||
4693 | struct rpc_message msg = { | ||
4694 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | ||
4695 | .rpc_argp = &args, | ||
4696 | .rpc_resp = &res, | ||
4697 | }; | ||
4698 | int status; | ||
4699 | |||
4700 | nfs4_init_channel_attrs(&args); | ||
4701 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | ||
4702 | |||
4703 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4704 | |||
4705 | if (!status) | ||
4706 | /* Verify the session's negotiated channel_attrs values */ | ||
4707 | status = nfs4_verify_channel_attrs(&args, session); | ||
4708 | if (!status) { | ||
4709 | /* Increment the clientid slot sequence id */ | ||
4710 | clp->cl_seqid++; | ||
4711 | } | ||
4712 | |||
4713 | return status; | ||
4714 | } | ||
4715 | |||
4716 | /* | ||
4717 | * Issues a CREATE_SESSION operation to the server. | ||
4718 | * It is the responsibility of the caller to verify the session is | ||
4719 | * expired before calling this routine. | ||
4720 | */ | ||
4721 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | ||
4722 | { | ||
4723 | int status; | ||
4724 | unsigned *ptr; | ||
4725 | struct nfs_fsinfo fsinfo; | ||
4726 | struct nfs4_session *session = clp->cl_session; | ||
4727 | |||
4728 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | ||
4729 | |||
4730 | status = _nfs4_proc_create_session(clp); | ||
4731 | if (status) | ||
4732 | goto out; | ||
4733 | |||
4734 | /* Init or reset the fore channel */ | ||
4735 | if (reset) | ||
4736 | status = nfs4_reset_slot_tables(session); | ||
4737 | else | ||
4738 | status = nfs4_init_slot_tables(session); | ||
4739 | dprintk("fore channel slot table initialization returned %d\n", status); | ||
4740 | if (status) | ||
4741 | goto out; | ||
4742 | |||
4743 | ptr = (unsigned *)&session->sess_id.data[0]; | ||
4744 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | ||
4745 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
4746 | |||
4747 | if (reset) | ||
4748 | /* Lease time is aleady set */ | ||
4749 | goto out; | ||
4750 | |||
4751 | /* Get the lease time */ | ||
4752 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4753 | if (status == 0) { | ||
4754 | /* Update lease time and schedule renewal */ | ||
4755 | spin_lock(&clp->cl_lock); | ||
4756 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4757 | clp->cl_last_renewal = jiffies; | ||
4758 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4759 | spin_unlock(&clp->cl_lock); | ||
4760 | |||
4761 | nfs4_schedule_state_renewal(clp); | ||
4762 | } | ||
4763 | out: | ||
4764 | dprintk("<-- %s\n", __func__); | ||
4765 | return status; | ||
4766 | } | ||
4767 | |||
4768 | /* | ||
4769 | * Issue the over-the-wire RPC DESTROY_SESSION. | ||
4770 | * The caller must serialize access to this routine. | ||
4771 | */ | ||
4772 | int nfs4_proc_destroy_session(struct nfs4_session *session) | ||
4773 | { | ||
4774 | int status = 0; | ||
4775 | struct rpc_message msg; | ||
4776 | |||
4777 | dprintk("--> nfs4_proc_destroy_session\n"); | ||
4778 | |||
4779 | /* session is still being setup */ | ||
4780 | if (session->clp->cl_cons_state != NFS_CS_READY) | ||
4781 | return status; | ||
4782 | |||
4783 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION]; | ||
4784 | msg.rpc_argp = session; | ||
4785 | msg.rpc_resp = NULL; | ||
4786 | msg.rpc_cred = NULL; | ||
4787 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4788 | |||
4789 | if (status) | ||
4790 | printk(KERN_WARNING | ||
4791 | "Got error %d from the server on DESTROY_SESSION. " | ||
4792 | "Session has been destroyed regardless...\n", status); | ||
4793 | |||
4794 | dprintk("<-- nfs4_proc_destroy_session\n"); | ||
4795 | return status; | ||
4796 | } | ||
4797 | |||
4798 | int nfs4_init_session(struct nfs_server *server) | ||
4799 | { | ||
4800 | struct nfs_client *clp = server->nfs_client; | ||
4801 | int ret; | ||
4802 | |||
4803 | if (!nfs4_has_session(clp)) | ||
4804 | return 0; | ||
4805 | |||
4806 | clp->cl_session->fc_attrs.max_rqst_sz = server->wsize; | ||
4807 | clp->cl_session->fc_attrs.max_resp_sz = server->rsize; | ||
4808 | ret = nfs4_recover_expired_lease(server); | ||
4809 | if (!ret) | ||
4810 | ret = nfs4_check_client_ready(clp); | ||
4811 | return ret; | ||
4812 | } | ||
4813 | |||
4814 | /* | ||
4815 | * Renew the cl_session lease. | ||
4816 | */ | ||
4817 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
4818 | { | ||
4819 | struct nfs4_sequence_args args; | ||
4820 | struct nfs4_sequence_res res; | ||
4821 | |||
4822 | struct rpc_message msg = { | ||
4823 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4824 | .rpc_argp = &args, | ||
4825 | .rpc_resp = &res, | ||
4826 | .rpc_cred = cred, | ||
4827 | }; | ||
4828 | |||
4829 | args.sa_cache_this = 0; | ||
4830 | |||
4831 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
4832 | &res, 0); | ||
4833 | } | ||
4834 | |||
4835 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4836 | { | ||
4837 | struct nfs_client *clp = (struct nfs_client *)data; | ||
4838 | |||
4839 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
4840 | |||
4841 | if (task->tk_status < 0) { | ||
4842 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
4843 | |||
4844 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
4845 | == -EAGAIN) { | ||
4846 | nfs4_restart_rpc(task, clp); | ||
4847 | return; | ||
4848 | } | ||
4849 | } | ||
4850 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4851 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
4852 | |||
4853 | put_rpccred(task->tk_msg.rpc_cred); | ||
4854 | kfree(task->tk_msg.rpc_argp); | ||
4855 | kfree(task->tk_msg.rpc_resp); | ||
4856 | |||
4857 | dprintk("<-- %s\n", __func__); | ||
4858 | } | ||
4859 | |||
4860 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
4861 | { | ||
4862 | struct nfs_client *clp; | ||
4863 | struct nfs4_sequence_args *args; | ||
4864 | struct nfs4_sequence_res *res; | ||
4865 | |||
4866 | clp = (struct nfs_client *)data; | ||
4867 | args = task->tk_msg.rpc_argp; | ||
4868 | res = task->tk_msg.rpc_resp; | ||
4869 | |||
4870 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
4871 | return; | ||
4872 | rpc_call_start(task); | ||
4873 | } | ||
4874 | |||
4875 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
4876 | .rpc_call_done = nfs41_sequence_call_done, | ||
4877 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
4878 | }; | ||
4879 | |||
4880 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
4881 | struct rpc_cred *cred) | ||
4882 | { | ||
4883 | struct nfs4_sequence_args *args; | ||
4884 | struct nfs4_sequence_res *res; | ||
4885 | struct rpc_message msg = { | ||
4886 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4887 | .rpc_cred = cred, | ||
4888 | }; | ||
4889 | |||
4890 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
4891 | if (!args) | ||
4892 | return -ENOMEM; | ||
4893 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
4894 | if (!res) { | ||
4895 | kfree(args); | ||
4896 | return -ENOMEM; | ||
4897 | } | ||
4898 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4899 | msg.rpc_argp = args; | ||
4900 | msg.rpc_resp = res; | ||
4901 | |||
4902 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
4903 | &nfs41_sequence_ops, (void *)clp); | ||
4904 | } | ||
4905 | |||
4906 | #endif /* CONFIG_NFS_V4_1 */ | ||
4907 | |||
4908 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
3727 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 4909 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
3728 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 4910 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
3729 | .recover_open = nfs4_open_reclaim, | 4911 | .recover_open = nfs4_open_reclaim, |
3730 | .recover_lock = nfs4_lock_reclaim, | 4912 | .recover_lock = nfs4_lock_reclaim, |
4913 | .establish_clid = nfs4_init_clientid, | ||
4914 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
4915 | }; | ||
4916 | |||
4917 | #if defined(CONFIG_NFS_V4_1) | ||
4918 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | ||
4919 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
4920 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
4921 | .recover_open = nfs4_open_reclaim, | ||
4922 | .recover_lock = nfs4_lock_reclaim, | ||
4923 | .establish_clid = nfs4_proc_exchange_id, | ||
4924 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4925 | }; | ||
4926 | #endif /* CONFIG_NFS_V4_1 */ | ||
4927 | |||
4928 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | ||
4929 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
4930 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
4931 | .recover_open = nfs4_open_expired, | ||
4932 | .recover_lock = nfs4_lock_expired, | ||
4933 | .establish_clid = nfs4_init_clientid, | ||
4934 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
3731 | }; | 4935 | }; |
3732 | 4936 | ||
3733 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { | 4937 | #if defined(CONFIG_NFS_V4_1) |
4938 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | ||
3734 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 4939 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
3735 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 4940 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
3736 | .recover_open = nfs4_open_expired, | 4941 | .recover_open = nfs4_open_expired, |
3737 | .recover_lock = nfs4_lock_expired, | 4942 | .recover_lock = nfs4_lock_expired, |
4943 | .establish_clid = nfs4_proc_exchange_id, | ||
4944 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4945 | }; | ||
4946 | #endif /* CONFIG_NFS_V4_1 */ | ||
4947 | |||
4948 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | ||
4949 | .sched_state_renewal = nfs4_proc_async_renew, | ||
4950 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | ||
4951 | .renew_lease = nfs4_proc_renew, | ||
4952 | }; | ||
4953 | |||
4954 | #if defined(CONFIG_NFS_V4_1) | ||
4955 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | ||
4956 | .sched_state_renewal = nfs41_proc_async_sequence, | ||
4957 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | ||
4958 | .renew_lease = nfs4_proc_sequence, | ||
4959 | }; | ||
4960 | #endif | ||
4961 | |||
4962 | /* | ||
4963 | * Per minor version reboot and network partition recovery ops | ||
4964 | */ | ||
4965 | |||
4966 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | ||
4967 | &nfs40_reboot_recovery_ops, | ||
4968 | #if defined(CONFIG_NFS_V4_1) | ||
4969 | &nfs41_reboot_recovery_ops, | ||
4970 | #endif | ||
4971 | }; | ||
4972 | |||
4973 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
4974 | &nfs40_nograce_recovery_ops, | ||
4975 | #if defined(CONFIG_NFS_V4_1) | ||
4976 | &nfs41_nograce_recovery_ops, | ||
4977 | #endif | ||
4978 | }; | ||
4979 | |||
4980 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | ||
4981 | &nfs40_state_renewal_ops, | ||
4982 | #if defined(CONFIG_NFS_V4_1) | ||
4983 | &nfs41_state_renewal_ops, | ||
4984 | #endif | ||
3738 | }; | 4985 | }; |
3739 | 4986 | ||
3740 | static const struct inode_operations nfs4_file_inode_operations = { | 4987 | static const struct inode_operations nfs4_file_inode_operations = { |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index f524e932ff7b..e27c6cef18f2 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -59,12 +59,14 @@ | |||
59 | void | 59 | void |
60 | nfs4_renew_state(struct work_struct *work) | 60 | nfs4_renew_state(struct work_struct *work) |
61 | { | 61 | { |
62 | struct nfs4_state_maintenance_ops *ops; | ||
62 | struct nfs_client *clp = | 63 | struct nfs_client *clp = |
63 | container_of(work, struct nfs_client, cl_renewd.work); | 64 | container_of(work, struct nfs_client, cl_renewd.work); |
64 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
65 | long lease, timeout; | 66 | long lease, timeout; |
66 | unsigned long last, now; | 67 | unsigned long last, now; |
67 | 68 | ||
69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
68 | dprintk("%s: start\n", __func__); | 70 | dprintk("%s: start\n", __func__); |
69 | /* Are there any active superblocks? */ | 71 | /* Are there any active superblocks? */ |
70 | if (list_empty(&clp->cl_superblocks)) | 72 | if (list_empty(&clp->cl_superblocks)) |
@@ -76,7 +78,7 @@ nfs4_renew_state(struct work_struct *work) | |||
76 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 78 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
77 | /* Are we close to a lease timeout? */ | 79 | /* Are we close to a lease timeout? */ |
78 | if (time_after(now, last + lease/3)) { | 80 | if (time_after(now, last + lease/3)) { |
79 | cred = nfs4_get_renew_cred_locked(clp); | 81 | cred = ops->get_state_renewal_cred_locked(clp); |
80 | spin_unlock(&clp->cl_lock); | 82 | spin_unlock(&clp->cl_lock); |
81 | if (cred == NULL) { | 83 | if (cred == NULL) { |
82 | if (list_empty(&clp->cl_delegations)) { | 84 | if (list_empty(&clp->cl_delegations)) { |
@@ -86,7 +88,7 @@ nfs4_renew_state(struct work_struct *work) | |||
86 | nfs_expire_all_delegations(clp); | 88 | nfs_expire_all_delegations(clp); |
87 | } else { | 89 | } else { |
88 | /* Queue an asynchronous RENEW. */ | 90 | /* Queue an asynchronous RENEW. */ |
89 | nfs4_proc_async_renew(clp, cred); | 91 | ops->sched_state_renewal(clp, cred); |
90 | put_rpccred(cred); | 92 | put_rpccred(cred); |
91 | } | 93 | } |
92 | timeout = (2 * lease) / 3; | 94 | timeout = (2 * lease) / 3; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0298e909559f..65ca8c18476f 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid; | |||
60 | 60 | ||
61 | static LIST_HEAD(nfs4_clientid_list); | 61 | static LIST_HEAD(nfs4_clientid_list); |
62 | 62 | ||
63 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
64 | { | 64 | { |
65 | unsigned short port; | 65 | unsigned short port; |
66 | int status; | 66 | int status; |
@@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
77 | return status; | 77 | return status; |
78 | } | 78 | } |
79 | 79 | ||
80 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | 80 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) |
81 | { | 81 | { |
82 | struct rpc_cred *cred = NULL; | 82 | struct rpc_cred *cred = NULL; |
83 | 83 | ||
@@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
114 | return cred; | 114 | return cred; |
115 | } | 115 | } |
116 | 116 | ||
117 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 117 | #if defined(CONFIG_NFS_V4_1) |
118 | |||
119 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | ||
118 | { | 120 | { |
119 | struct rpc_cred *cred; | 121 | struct rpc_cred *cred; |
120 | 122 | ||
121 | spin_lock(&clp->cl_lock); | 123 | spin_lock(&clp->cl_lock); |
122 | cred = nfs4_get_renew_cred_locked(clp); | 124 | cred = nfs4_get_machine_cred_locked(clp); |
123 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
124 | return cred; | 126 | return cred; |
125 | } | 127 | } |
126 | 128 | ||
127 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 129 | #endif /* CONFIG_NFS_V4_1 */ |
130 | |||
131 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | ||
128 | { | 132 | { |
129 | struct nfs4_state_owner *sp; | 133 | struct nfs4_state_owner *sp; |
130 | struct rb_node *pos; | 134 | struct rb_node *pos; |
@@ -549,6 +553,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
549 | INIT_LIST_HEAD(&lsp->ls_sequence.list); | 553 | INIT_LIST_HEAD(&lsp->ls_sequence.list); |
550 | lsp->ls_seqid.sequence = &lsp->ls_sequence; | 554 | lsp->ls_seqid.sequence = &lsp->ls_sequence; |
551 | atomic_set(&lsp->ls_count, 1); | 555 | atomic_set(&lsp->ls_count, 1); |
556 | lsp->ls_state = state; | ||
552 | lsp->ls_owner = fl_owner; | 557 | lsp->ls_owner = fl_owner; |
553 | spin_lock(&clp->cl_lock); | 558 | spin_lock(&clp->cl_lock); |
554 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); | 559 | nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64); |
@@ -583,7 +588,6 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
583 | if (lsp != NULL) | 588 | if (lsp != NULL) |
584 | break; | 589 | break; |
585 | if (new != NULL) { | 590 | if (new != NULL) { |
586 | new->ls_state = state; | ||
587 | list_add(&new->ls_locks, &state->lock_states); | 591 | list_add(&new->ls_locks, &state->lock_states); |
588 | set_bit(LK_STATE_IN_USE, &state->flags); | 592 | set_bit(LK_STATE_IN_USE, &state->flags); |
589 | lsp = new; | 593 | lsp = new; |
@@ -738,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |||
738 | 742 | ||
739 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | 743 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) |
740 | { | 744 | { |
741 | if (status == -NFS4ERR_BAD_SEQID) { | 745 | struct nfs4_state_owner *sp = container_of(seqid->sequence, |
742 | struct nfs4_state_owner *sp = container_of(seqid->sequence, | 746 | struct nfs4_state_owner, so_seqid); |
743 | struct nfs4_state_owner, so_seqid); | 747 | struct nfs_server *server = sp->so_server; |
748 | |||
749 | if (status == -NFS4ERR_BAD_SEQID) | ||
744 | nfs4_drop_state_owner(sp); | 750 | nfs4_drop_state_owner(sp); |
745 | } | 751 | if (!nfs4_has_session(server->nfs_client)) |
746 | nfs_increment_seqid(status, seqid); | 752 | nfs_increment_seqid(status, seqid); |
747 | } | 753 | } |
748 | 754 | ||
749 | /* | 755 | /* |
@@ -847,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
847 | struct file_lock *fl; | 853 | struct file_lock *fl; |
848 | int status = 0; | 854 | int status = 0; |
849 | 855 | ||
856 | if (inode->i_flock == NULL) | ||
857 | return 0; | ||
858 | |||
859 | /* Guard against delegation returns and new lock/unlock calls */ | ||
850 | down_write(&nfsi->rwsem); | 860 | down_write(&nfsi->rwsem); |
861 | /* Protect inode->i_flock using the BKL */ | ||
862 | lock_kernel(); | ||
851 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 863 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
852 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 864 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
853 | continue; | 865 | continue; |
854 | if (nfs_file_open_context(fl->fl_file)->state != state) | 866 | if (nfs_file_open_context(fl->fl_file)->state != state) |
855 | continue; | 867 | continue; |
868 | unlock_kernel(); | ||
856 | status = ops->recover_lock(state, fl); | 869 | status = ops->recover_lock(state, fl); |
857 | if (status >= 0) | ||
858 | continue; | ||
859 | switch (status) { | 870 | switch (status) { |
871 | case 0: | ||
872 | break; | ||
873 | case -ESTALE: | ||
874 | case -NFS4ERR_ADMIN_REVOKED: | ||
875 | case -NFS4ERR_STALE_STATEID: | ||
876 | case -NFS4ERR_BAD_STATEID: | ||
877 | case -NFS4ERR_EXPIRED: | ||
878 | case -NFS4ERR_NO_GRACE: | ||
879 | case -NFS4ERR_STALE_CLIENTID: | ||
880 | goto out; | ||
860 | default: | 881 | default: |
861 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 882 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
862 | __func__, status); | 883 | __func__, status); |
863 | case -NFS4ERR_EXPIRED: | 884 | case -ENOMEM: |
864 | case -NFS4ERR_NO_GRACE: | 885 | case -NFS4ERR_DENIED: |
865 | case -NFS4ERR_RECLAIM_BAD: | 886 | case -NFS4ERR_RECLAIM_BAD: |
866 | case -NFS4ERR_RECLAIM_CONFLICT: | 887 | case -NFS4ERR_RECLAIM_CONFLICT: |
867 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ | 888 | /* kill_proc(fl->fl_pid, SIGLOST, 1); */ |
868 | break; | 889 | status = 0; |
869 | case -NFS4ERR_STALE_CLIENTID: | ||
870 | goto out_err; | ||
871 | } | 890 | } |
891 | lock_kernel(); | ||
872 | } | 892 | } |
873 | up_write(&nfsi->rwsem); | 893 | unlock_kernel(); |
874 | return 0; | 894 | out: |
875 | out_err: | ||
876 | up_write(&nfsi->rwsem); | 895 | up_write(&nfsi->rwsem); |
877 | return status; | 896 | return status; |
878 | } | 897 | } |
@@ -918,6 +937,7 @@ restart: | |||
918 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 937 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
919 | __func__, status); | 938 | __func__, status); |
920 | case -ENOENT: | 939 | case -ENOENT: |
940 | case -ENOMEM: | ||
921 | case -ESTALE: | 941 | case -ESTALE: |
922 | /* | 942 | /* |
923 | * Open state on this file cannot be recovered | 943 | * Open state on this file cannot be recovered |
@@ -928,6 +948,9 @@ restart: | |||
928 | /* Mark the file as being 'closed' */ | 948 | /* Mark the file as being 'closed' */ |
929 | state->state = 0; | 949 | state->state = 0; |
930 | break; | 950 | break; |
951 | case -NFS4ERR_ADMIN_REVOKED: | ||
952 | case -NFS4ERR_STALE_STATEID: | ||
953 | case -NFS4ERR_BAD_STATEID: | ||
931 | case -NFS4ERR_RECLAIM_BAD: | 954 | case -NFS4ERR_RECLAIM_BAD: |
932 | case -NFS4ERR_RECLAIM_CONFLICT: | 955 | case -NFS4ERR_RECLAIM_CONFLICT: |
933 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 956 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); |
@@ -1042,6 +1065,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1042 | case -NFS4ERR_EXPIRED: | 1065 | case -NFS4ERR_EXPIRED: |
1043 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1066 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1044 | nfs4_state_start_reclaim_nograce(clp); | 1067 | nfs4_state_start_reclaim_nograce(clp); |
1068 | case -NFS4ERR_BADSESSION: | ||
1069 | case -NFS4ERR_BADSLOT: | ||
1070 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1071 | case -NFS4ERR_DEADSESSION: | ||
1072 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1073 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
1074 | case -NFS4ERR_SEQ_MISORDERED: | ||
1075 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1045 | } | 1076 | } |
1046 | } | 1077 | } |
1047 | 1078 | ||
@@ -1075,18 +1106,22 @@ restart: | |||
1075 | static int nfs4_check_lease(struct nfs_client *clp) | 1106 | static int nfs4_check_lease(struct nfs_client *clp) |
1076 | { | 1107 | { |
1077 | struct rpc_cred *cred; | 1108 | struct rpc_cred *cred; |
1109 | struct nfs4_state_maintenance_ops *ops = | ||
1110 | nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
1078 | int status = -NFS4ERR_EXPIRED; | 1111 | int status = -NFS4ERR_EXPIRED; |
1079 | 1112 | ||
1080 | /* Is the client already known to have an expired lease? */ | 1113 | /* Is the client already known to have an expired lease? */ |
1081 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1114 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1082 | return 0; | 1115 | return 0; |
1083 | cred = nfs4_get_renew_cred(clp); | 1116 | spin_lock(&clp->cl_lock); |
1117 | cred = ops->get_state_renewal_cred_locked(clp); | ||
1118 | spin_unlock(&clp->cl_lock); | ||
1084 | if (cred == NULL) { | 1119 | if (cred == NULL) { |
1085 | cred = nfs4_get_setclientid_cred(clp); | 1120 | cred = nfs4_get_setclientid_cred(clp); |
1086 | if (cred == NULL) | 1121 | if (cred == NULL) |
1087 | goto out; | 1122 | goto out; |
1088 | } | 1123 | } |
1089 | status = nfs4_proc_renew(clp, cred); | 1124 | status = ops->renew_lease(clp, cred); |
1090 | put_rpccred(cred); | 1125 | put_rpccred(cred); |
1091 | out: | 1126 | out: |
1092 | nfs4_recovery_handle_error(clp, status); | 1127 | nfs4_recovery_handle_error(clp, status); |
@@ -1096,21 +1131,98 @@ out: | |||
1096 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1131 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
1097 | { | 1132 | { |
1098 | struct rpc_cred *cred; | 1133 | struct rpc_cred *cred; |
1134 | struct nfs4_state_recovery_ops *ops = | ||
1135 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | ||
1099 | int status = -ENOENT; | 1136 | int status = -ENOENT; |
1100 | 1137 | ||
1101 | cred = nfs4_get_setclientid_cred(clp); | 1138 | cred = ops->get_clid_cred(clp); |
1102 | if (cred != NULL) { | 1139 | if (cred != NULL) { |
1103 | status = nfs4_init_client(clp, cred); | 1140 | status = ops->establish_clid(clp, cred); |
1104 | put_rpccred(cred); | 1141 | put_rpccred(cred); |
1105 | /* Handle case where the user hasn't set up machine creds */ | 1142 | /* Handle case where the user hasn't set up machine creds */ |
1106 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 1143 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
1107 | nfs4_clear_machine_cred(clp); | 1144 | nfs4_clear_machine_cred(clp); |
1108 | status = -EAGAIN; | 1145 | status = -EAGAIN; |
1109 | } | 1146 | } |
1147 | if (status == -NFS4ERR_MINOR_VERS_MISMATCH) | ||
1148 | status = -EPROTONOSUPPORT; | ||
1149 | } | ||
1150 | return status; | ||
1151 | } | ||
1152 | |||
1153 | #ifdef CONFIG_NFS_V4_1 | ||
1154 | static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err) | ||
1155 | { | ||
1156 | switch (err) { | ||
1157 | case -NFS4ERR_STALE_CLIENTID: | ||
1158 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1159 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | static int nfs4_reset_session(struct nfs_client *clp) | ||
1164 | { | ||
1165 | int status; | ||
1166 | |||
1167 | status = nfs4_proc_destroy_session(clp->cl_session); | ||
1168 | if (status && status != -NFS4ERR_BADSESSION && | ||
1169 | status != -NFS4ERR_DEADSESSION) { | ||
1170 | nfs4_session_recovery_handle_error(clp, status); | ||
1171 | goto out; | ||
1110 | } | 1172 | } |
1173 | |||
1174 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | ||
1175 | status = nfs4_proc_create_session(clp, 1); | ||
1176 | if (status) | ||
1177 | nfs4_session_recovery_handle_error(clp, status); | ||
1178 | /* fall through*/ | ||
1179 | out: | ||
1180 | /* Wake up the next rpc task even on error */ | ||
1181 | rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq); | ||
1111 | return status; | 1182 | return status; |
1112 | } | 1183 | } |
1113 | 1184 | ||
1185 | static int nfs4_initialize_session(struct nfs_client *clp) | ||
1186 | { | ||
1187 | int status; | ||
1188 | |||
1189 | status = nfs4_proc_create_session(clp, 0); | ||
1190 | if (!status) { | ||
1191 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1192 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | ||
1193 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1194 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1195 | } else { | ||
1196 | nfs_mark_client_ready(clp, status); | ||
1197 | } | ||
1198 | return status; | ||
1199 | } | ||
1200 | #else /* CONFIG_NFS_V4_1 */ | ||
1201 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | ||
1202 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | ||
1203 | #endif /* CONFIG_NFS_V4_1 */ | ||
1204 | |||
1205 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | ||
1206 | * on EXCHANGE_ID for v4.1 | ||
1207 | */ | ||
1208 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | ||
1209 | { | ||
1210 | if (nfs4_has_session(clp)) { | ||
1211 | switch (status) { | ||
1212 | case -NFS4ERR_DELAY: | ||
1213 | case -NFS4ERR_CLID_INUSE: | ||
1214 | case -EAGAIN: | ||
1215 | break; | ||
1216 | |||
1217 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | ||
1218 | * in nfs4_exchange_id */ | ||
1219 | default: | ||
1220 | return; | ||
1221 | } | ||
1222 | } | ||
1223 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1224 | } | ||
1225 | |||
1114 | static void nfs4_state_manager(struct nfs_client *clp) | 1226 | static void nfs4_state_manager(struct nfs_client *clp) |
1115 | { | 1227 | { |
1116 | int status = 0; | 1228 | int status = 0; |
@@ -1121,9 +1233,12 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1121 | /* We're going to have to re-establish a clientid */ | 1233 | /* We're going to have to re-establish a clientid */ |
1122 | status = nfs4_reclaim_lease(clp); | 1234 | status = nfs4_reclaim_lease(clp); |
1123 | if (status) { | 1235 | if (status) { |
1124 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1236 | nfs4_set_lease_expired(clp, status); |
1125 | if (status == -EAGAIN) | 1237 | if (status == -EAGAIN) |
1126 | continue; | 1238 | continue; |
1239 | if (clp->cl_cons_state == | ||
1240 | NFS_CS_SESSION_INITING) | ||
1241 | nfs_mark_client_ready(clp, status); | ||
1127 | goto out_error; | 1242 | goto out_error; |
1128 | } | 1243 | } |
1129 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1244 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
@@ -1134,25 +1249,44 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1134 | if (status != 0) | 1249 | if (status != 0) |
1135 | continue; | 1250 | continue; |
1136 | } | 1251 | } |
1137 | 1252 | /* Initialize or reset the session */ | |
1253 | if (nfs4_has_session(clp) && | ||
1254 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | ||
1256 | status = nfs4_initialize_session(clp); | ||
1257 | else | ||
1258 | status = nfs4_reset_session(clp); | ||
1259 | if (status) { | ||
1260 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
1261 | continue; | ||
1262 | goto out_error; | ||
1263 | } | ||
1264 | } | ||
1138 | /* First recover reboot state... */ | 1265 | /* First recover reboot state... */ |
1139 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1266 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1140 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | 1267 | status = nfs4_do_reclaim(clp, |
1268 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
1141 | if (status == -NFS4ERR_STALE_CLIENTID) | 1269 | if (status == -NFS4ERR_STALE_CLIENTID) |
1142 | continue; | 1270 | continue; |
1271 | if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
1272 | continue; | ||
1143 | nfs4_state_end_reclaim_reboot(clp); | 1273 | nfs4_state_end_reclaim_reboot(clp); |
1144 | continue; | 1274 | continue; |
1145 | } | 1275 | } |
1146 | 1276 | ||
1147 | /* Now recover expired state... */ | 1277 | /* Now recover expired state... */ |
1148 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1278 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1149 | status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); | 1279 | status = nfs4_do_reclaim(clp, |
1280 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | ||
1150 | if (status < 0) { | 1281 | if (status < 0) { |
1151 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | 1282 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); |
1152 | if (status == -NFS4ERR_STALE_CLIENTID) | 1283 | if (status == -NFS4ERR_STALE_CLIENTID) |
1153 | continue; | 1284 | continue; |
1154 | if (status == -NFS4ERR_EXPIRED) | 1285 | if (status == -NFS4ERR_EXPIRED) |
1155 | continue; | 1286 | continue; |
1287 | if (test_bit(NFS4CLNT_SESSION_SETUP, | ||
1288 | &clp->cl_state)) | ||
1289 | continue; | ||
1156 | goto out_error; | 1290 | goto out_error; |
1157 | } else | 1291 | } else |
1158 | nfs4_state_end_reclaim_nograce(clp); | 1292 | nfs4_state_end_reclaim_nograce(clp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1690f0e44b91..617273e7d47f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int); | |||
192 | decode_verifier_maxsz) | 192 | decode_verifier_maxsz) |
193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ | 193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ |
194 | nfs4_name_maxsz) | 194 | nfs4_name_maxsz) |
195 | #define decode_remove_maxsz (op_decode_hdr_maxsz + \ | ||
196 | decode_change_info_maxsz) | ||
195 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ | 197 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ |
196 | 2 * nfs4_name_maxsz) | 198 | 2 * nfs4_name_maxsz) |
197 | #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) | 199 | #define decode_rename_maxsz (op_decode_hdr_maxsz + \ |
200 | decode_change_info_maxsz + \ | ||
201 | decode_change_info_maxsz) | ||
198 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
199 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
200 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
201 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
202 | 7 + \ | 206 | 7 + \ |
203 | 1 + encode_stateid_maxsz + 8) | 207 | 1 + encode_stateid_maxsz + 8) |
@@ -240,43 +244,115 @@ static int nfs4_stat_to_errno(int); | |||
240 | (encode_getattr_maxsz) | 244 | (encode_getattr_maxsz) |
241 | #define decode_fs_locations_maxsz \ | 245 | #define decode_fs_locations_maxsz \ |
242 | (0) | 246 | (0) |
247 | |||
248 | #if defined(CONFIG_NFS_V4_1) | ||
249 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | ||
250 | |||
251 | #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ | ||
252 | encode_verifier_maxsz + \ | ||
253 | 1 /* co_ownerid.len */ + \ | ||
254 | XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ | ||
255 | 1 /* flags */ + \ | ||
256 | 1 /* spa_how */ + \ | ||
257 | 0 /* SP4_NONE (for now) */ + \ | ||
258 | 1 /* zero implemetation id array */) | ||
259 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | ||
260 | 2 /* eir_clientid */ + \ | ||
261 | 1 /* eir_sequenceid */ + \ | ||
262 | 1 /* eir_flags */ + \ | ||
263 | 1 /* spr_how */ + \ | ||
264 | 0 /* SP4_NONE (for now) */ + \ | ||
265 | 2 /* eir_server_owner.so_minor_id */ + \ | ||
266 | /* eir_server_owner.so_major_id<> */ \ | ||
267 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
268 | /* eir_server_scope<> */ \ | ||
269 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
270 | 1 /* eir_server_impl_id array length */ + \ | ||
271 | 0 /* ignored eir_server_impl_id contents */) | ||
272 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) | ||
273 | #define decode_channel_attrs_maxsz (6 + \ | ||
274 | 1 /* ca_rdma_ird.len */ + \ | ||
275 | 1 /* ca_rdma_ird */) | ||
276 | #define encode_create_session_maxsz (op_encode_hdr_maxsz + \ | ||
277 | 2 /* csa_clientid */ + \ | ||
278 | 1 /* csa_sequence */ + \ | ||
279 | 1 /* csa_flags */ + \ | ||
280 | encode_channel_attrs_maxsz + \ | ||
281 | encode_channel_attrs_maxsz + \ | ||
282 | 1 /* csa_cb_program */ + \ | ||
283 | 1 /* csa_sec_parms.len (1) */ + \ | ||
284 | 1 /* cb_secflavor (AUTH_SYS) */ + \ | ||
285 | 1 /* stamp */ + \ | ||
286 | 1 /* machinename.len */ + \ | ||
287 | XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \ | ||
288 | 1 /* uid */ + \ | ||
289 | 1 /* gid */ + \ | ||
290 | 1 /* gids.len (0) */) | ||
291 | #define decode_create_session_maxsz (op_decode_hdr_maxsz + \ | ||
292 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
293 | 1 /* csr_sequence */ + \ | ||
294 | 1 /* csr_flags */ + \ | ||
295 | decode_channel_attrs_maxsz + \ | ||
296 | decode_channel_attrs_maxsz) | ||
297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) | ||
298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) | ||
299 | #define encode_sequence_maxsz (op_encode_hdr_maxsz + \ | ||
300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) | ||
301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | ||
302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | ||
303 | #else /* CONFIG_NFS_V4_1 */ | ||
304 | #define encode_sequence_maxsz 0 | ||
305 | #define decode_sequence_maxsz 0 | ||
306 | #endif /* CONFIG_NFS_V4_1 */ | ||
307 | |||
243 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ | 308 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ |
244 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ | 309 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ |
245 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ | 310 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ |
311 | encode_sequence_maxsz + \ | ||
246 | encode_putfh_maxsz + \ | 312 | encode_putfh_maxsz + \ |
247 | encode_read_maxsz) | 313 | encode_read_maxsz) |
248 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ | 314 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ |
315 | decode_sequence_maxsz + \ | ||
249 | decode_putfh_maxsz + \ | 316 | decode_putfh_maxsz + \ |
250 | decode_read_maxsz) | 317 | decode_read_maxsz) |
251 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ | 318 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ |
319 | encode_sequence_maxsz + \ | ||
252 | encode_putfh_maxsz + \ | 320 | encode_putfh_maxsz + \ |
253 | encode_readlink_maxsz) | 321 | encode_readlink_maxsz) |
254 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ | 322 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ |
323 | decode_sequence_maxsz + \ | ||
255 | decode_putfh_maxsz + \ | 324 | decode_putfh_maxsz + \ |
256 | decode_readlink_maxsz) | 325 | decode_readlink_maxsz) |
257 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ | 326 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ |
327 | encode_sequence_maxsz + \ | ||
258 | encode_putfh_maxsz + \ | 328 | encode_putfh_maxsz + \ |
259 | encode_readdir_maxsz) | 329 | encode_readdir_maxsz) |
260 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ | 330 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ |
331 | decode_sequence_maxsz + \ | ||
261 | decode_putfh_maxsz + \ | 332 | decode_putfh_maxsz + \ |
262 | decode_readdir_maxsz) | 333 | decode_readdir_maxsz) |
263 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ | 334 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ |
335 | encode_sequence_maxsz + \ | ||
264 | encode_putfh_maxsz + \ | 336 | encode_putfh_maxsz + \ |
265 | encode_write_maxsz + \ | 337 | encode_write_maxsz + \ |
266 | encode_getattr_maxsz) | 338 | encode_getattr_maxsz) |
267 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ | 339 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ |
340 | decode_sequence_maxsz + \ | ||
268 | decode_putfh_maxsz + \ | 341 | decode_putfh_maxsz + \ |
269 | decode_write_maxsz + \ | 342 | decode_write_maxsz + \ |
270 | decode_getattr_maxsz) | 343 | decode_getattr_maxsz) |
271 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ | 344 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ |
345 | encode_sequence_maxsz + \ | ||
272 | encode_putfh_maxsz + \ | 346 | encode_putfh_maxsz + \ |
273 | encode_commit_maxsz + \ | 347 | encode_commit_maxsz + \ |
274 | encode_getattr_maxsz) | 348 | encode_getattr_maxsz) |
275 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ | 349 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ |
350 | decode_sequence_maxsz + \ | ||
276 | decode_putfh_maxsz + \ | 351 | decode_putfh_maxsz + \ |
277 | decode_commit_maxsz + \ | 352 | decode_commit_maxsz + \ |
278 | decode_getattr_maxsz) | 353 | decode_getattr_maxsz) |
279 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ | 354 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ |
355 | encode_sequence_maxsz + \ | ||
280 | encode_putfh_maxsz + \ | 356 | encode_putfh_maxsz + \ |
281 | encode_savefh_maxsz + \ | 357 | encode_savefh_maxsz + \ |
282 | encode_open_maxsz + \ | 358 | encode_open_maxsz + \ |
@@ -285,6 +361,7 @@ static int nfs4_stat_to_errno(int); | |||
285 | encode_restorefh_maxsz + \ | 361 | encode_restorefh_maxsz + \ |
286 | encode_getattr_maxsz) | 362 | encode_getattr_maxsz) |
287 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | 363 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ |
364 | decode_sequence_maxsz + \ | ||
288 | decode_putfh_maxsz + \ | 365 | decode_putfh_maxsz + \ |
289 | decode_savefh_maxsz + \ | 366 | decode_savefh_maxsz + \ |
290 | decode_open_maxsz + \ | 367 | decode_open_maxsz + \ |
@@ -301,43 +378,53 @@ static int nfs4_stat_to_errno(int); | |||
301 | decode_putfh_maxsz + \ | 378 | decode_putfh_maxsz + \ |
302 | decode_open_confirm_maxsz) | 379 | decode_open_confirm_maxsz) |
303 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ | 380 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ |
381 | encode_sequence_maxsz + \ | ||
304 | encode_putfh_maxsz + \ | 382 | encode_putfh_maxsz + \ |
305 | encode_open_maxsz + \ | 383 | encode_open_maxsz + \ |
306 | encode_getattr_maxsz) | 384 | encode_getattr_maxsz) |
307 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | 385 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ |
386 | decode_sequence_maxsz + \ | ||
308 | decode_putfh_maxsz + \ | 387 | decode_putfh_maxsz + \ |
309 | decode_open_maxsz + \ | 388 | decode_open_maxsz + \ |
310 | decode_getattr_maxsz) | 389 | decode_getattr_maxsz) |
311 | #define NFS4_enc_open_downgrade_sz \ | 390 | #define NFS4_enc_open_downgrade_sz \ |
312 | (compound_encode_hdr_maxsz + \ | 391 | (compound_encode_hdr_maxsz + \ |
392 | encode_sequence_maxsz + \ | ||
313 | encode_putfh_maxsz + \ | 393 | encode_putfh_maxsz + \ |
314 | encode_open_downgrade_maxsz + \ | 394 | encode_open_downgrade_maxsz + \ |
315 | encode_getattr_maxsz) | 395 | encode_getattr_maxsz) |
316 | #define NFS4_dec_open_downgrade_sz \ | 396 | #define NFS4_dec_open_downgrade_sz \ |
317 | (compound_decode_hdr_maxsz + \ | 397 | (compound_decode_hdr_maxsz + \ |
398 | decode_sequence_maxsz + \ | ||
318 | decode_putfh_maxsz + \ | 399 | decode_putfh_maxsz + \ |
319 | decode_open_downgrade_maxsz + \ | 400 | decode_open_downgrade_maxsz + \ |
320 | decode_getattr_maxsz) | 401 | decode_getattr_maxsz) |
321 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ | 402 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ |
403 | encode_sequence_maxsz + \ | ||
322 | encode_putfh_maxsz + \ | 404 | encode_putfh_maxsz + \ |
323 | encode_close_maxsz + \ | 405 | encode_close_maxsz + \ |
324 | encode_getattr_maxsz) | 406 | encode_getattr_maxsz) |
325 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ | 407 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ |
408 | decode_sequence_maxsz + \ | ||
326 | decode_putfh_maxsz + \ | 409 | decode_putfh_maxsz + \ |
327 | decode_close_maxsz + \ | 410 | decode_close_maxsz + \ |
328 | decode_getattr_maxsz) | 411 | decode_getattr_maxsz) |
329 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 412 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
413 | encode_sequence_maxsz + \ | ||
330 | encode_putfh_maxsz + \ | 414 | encode_putfh_maxsz + \ |
331 | encode_setattr_maxsz + \ | 415 | encode_setattr_maxsz + \ |
332 | encode_getattr_maxsz) | 416 | encode_getattr_maxsz) |
333 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 417 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
418 | decode_sequence_maxsz + \ | ||
334 | decode_putfh_maxsz + \ | 419 | decode_putfh_maxsz + \ |
335 | decode_setattr_maxsz + \ | 420 | decode_setattr_maxsz + \ |
336 | decode_getattr_maxsz) | 421 | decode_getattr_maxsz) |
337 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ | 422 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ |
423 | encode_sequence_maxsz + \ | ||
338 | encode_putfh_maxsz + \ | 424 | encode_putfh_maxsz + \ |
339 | encode_fsinfo_maxsz) | 425 | encode_fsinfo_maxsz) |
340 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ | 426 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ |
427 | decode_sequence_maxsz + \ | ||
341 | decode_putfh_maxsz + \ | 428 | decode_putfh_maxsz + \ |
342 | decode_fsinfo_maxsz) | 429 | decode_fsinfo_maxsz) |
343 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ | 430 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ |
@@ -359,64 +446,81 @@ static int nfs4_stat_to_errno(int); | |||
359 | decode_putrootfh_maxsz + \ | 446 | decode_putrootfh_maxsz + \ |
360 | decode_fsinfo_maxsz) | 447 | decode_fsinfo_maxsz) |
361 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ | 448 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ |
449 | encode_sequence_maxsz + \ | ||
362 | encode_putfh_maxsz + \ | 450 | encode_putfh_maxsz + \ |
363 | encode_lock_maxsz) | 451 | encode_lock_maxsz) |
364 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ | 452 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ |
453 | decode_sequence_maxsz + \ | ||
365 | decode_putfh_maxsz + \ | 454 | decode_putfh_maxsz + \ |
366 | decode_lock_maxsz) | 455 | decode_lock_maxsz) |
367 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ | 456 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ |
457 | encode_sequence_maxsz + \ | ||
368 | encode_putfh_maxsz + \ | 458 | encode_putfh_maxsz + \ |
369 | encode_lockt_maxsz) | 459 | encode_lockt_maxsz) |
370 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ | 460 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ |
461 | decode_sequence_maxsz + \ | ||
371 | decode_putfh_maxsz + \ | 462 | decode_putfh_maxsz + \ |
372 | decode_lockt_maxsz) | 463 | decode_lockt_maxsz) |
373 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ | 464 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ |
465 | encode_sequence_maxsz + \ | ||
374 | encode_putfh_maxsz + \ | 466 | encode_putfh_maxsz + \ |
375 | encode_locku_maxsz) | 467 | encode_locku_maxsz) |
376 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ | 468 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ |
469 | decode_sequence_maxsz + \ | ||
377 | decode_putfh_maxsz + \ | 470 | decode_putfh_maxsz + \ |
378 | decode_locku_maxsz) | 471 | decode_locku_maxsz) |
379 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 472 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
473 | encode_sequence_maxsz + \ | ||
380 | encode_putfh_maxsz + \ | 474 | encode_putfh_maxsz + \ |
381 | encode_access_maxsz + \ | 475 | encode_access_maxsz + \ |
382 | encode_getattr_maxsz) | 476 | encode_getattr_maxsz) |
383 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ | 477 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ |
478 | decode_sequence_maxsz + \ | ||
384 | decode_putfh_maxsz + \ | 479 | decode_putfh_maxsz + \ |
385 | decode_access_maxsz + \ | 480 | decode_access_maxsz + \ |
386 | decode_getattr_maxsz) | 481 | decode_getattr_maxsz) |
387 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 482 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
483 | encode_sequence_maxsz + \ | ||
388 | encode_putfh_maxsz + \ | 484 | encode_putfh_maxsz + \ |
389 | encode_getattr_maxsz) | 485 | encode_getattr_maxsz) |
390 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 486 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
487 | decode_sequence_maxsz + \ | ||
391 | decode_putfh_maxsz + \ | 488 | decode_putfh_maxsz + \ |
392 | decode_getattr_maxsz) | 489 | decode_getattr_maxsz) |
393 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 490 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
491 | encode_sequence_maxsz + \ | ||
394 | encode_putfh_maxsz + \ | 492 | encode_putfh_maxsz + \ |
395 | encode_lookup_maxsz + \ | 493 | encode_lookup_maxsz + \ |
396 | encode_getattr_maxsz + \ | 494 | encode_getattr_maxsz + \ |
397 | encode_getfh_maxsz) | 495 | encode_getfh_maxsz) |
398 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ | 496 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ |
497 | decode_sequence_maxsz + \ | ||
399 | decode_putfh_maxsz + \ | 498 | decode_putfh_maxsz + \ |
400 | decode_lookup_maxsz + \ | 499 | decode_lookup_maxsz + \ |
401 | decode_getattr_maxsz + \ | 500 | decode_getattr_maxsz + \ |
402 | decode_getfh_maxsz) | 501 | decode_getfh_maxsz) |
403 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ | 502 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ |
503 | encode_sequence_maxsz + \ | ||
404 | encode_putrootfh_maxsz + \ | 504 | encode_putrootfh_maxsz + \ |
405 | encode_getattr_maxsz + \ | 505 | encode_getattr_maxsz + \ |
406 | encode_getfh_maxsz) | 506 | encode_getfh_maxsz) |
407 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ | 507 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ |
508 | decode_sequence_maxsz + \ | ||
408 | decode_putrootfh_maxsz + \ | 509 | decode_putrootfh_maxsz + \ |
409 | decode_getattr_maxsz + \ | 510 | decode_getattr_maxsz + \ |
410 | decode_getfh_maxsz) | 511 | decode_getfh_maxsz) |
411 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ | 512 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ |
513 | encode_sequence_maxsz + \ | ||
412 | encode_putfh_maxsz + \ | 514 | encode_putfh_maxsz + \ |
413 | encode_remove_maxsz + \ | 515 | encode_remove_maxsz + \ |
414 | encode_getattr_maxsz) | 516 | encode_getattr_maxsz) |
415 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ | 517 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ |
518 | decode_sequence_maxsz + \ | ||
416 | decode_putfh_maxsz + \ | 519 | decode_putfh_maxsz + \ |
417 | op_decode_hdr_maxsz + 5 + \ | 520 | decode_remove_maxsz + \ |
418 | decode_getattr_maxsz) | 521 | decode_getattr_maxsz) |
419 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ | 522 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ |
523 | encode_sequence_maxsz + \ | ||
420 | encode_putfh_maxsz + \ | 524 | encode_putfh_maxsz + \ |
421 | encode_savefh_maxsz + \ | 525 | encode_savefh_maxsz + \ |
422 | encode_putfh_maxsz + \ | 526 | encode_putfh_maxsz + \ |
@@ -425,6 +529,7 @@ static int nfs4_stat_to_errno(int); | |||
425 | encode_restorefh_maxsz + \ | 529 | encode_restorefh_maxsz + \ |
426 | encode_getattr_maxsz) | 530 | encode_getattr_maxsz) |
427 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ | 531 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ |
532 | decode_sequence_maxsz + \ | ||
428 | decode_putfh_maxsz + \ | 533 | decode_putfh_maxsz + \ |
429 | decode_savefh_maxsz + \ | 534 | decode_savefh_maxsz + \ |
430 | decode_putfh_maxsz + \ | 535 | decode_putfh_maxsz + \ |
@@ -433,6 +538,7 @@ static int nfs4_stat_to_errno(int); | |||
433 | decode_restorefh_maxsz + \ | 538 | decode_restorefh_maxsz + \ |
434 | decode_getattr_maxsz) | 539 | decode_getattr_maxsz) |
435 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ | 540 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ |
541 | encode_sequence_maxsz + \ | ||
436 | encode_putfh_maxsz + \ | 542 | encode_putfh_maxsz + \ |
437 | encode_savefh_maxsz + \ | 543 | encode_savefh_maxsz + \ |
438 | encode_putfh_maxsz + \ | 544 | encode_putfh_maxsz + \ |
@@ -441,6 +547,7 @@ static int nfs4_stat_to_errno(int); | |||
441 | encode_restorefh_maxsz + \ | 547 | encode_restorefh_maxsz + \ |
442 | decode_getattr_maxsz) | 548 | decode_getattr_maxsz) |
443 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ | 549 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ |
550 | decode_sequence_maxsz + \ | ||
444 | decode_putfh_maxsz + \ | 551 | decode_putfh_maxsz + \ |
445 | decode_savefh_maxsz + \ | 552 | decode_savefh_maxsz + \ |
446 | decode_putfh_maxsz + \ | 553 | decode_putfh_maxsz + \ |
@@ -449,16 +556,19 @@ static int nfs4_stat_to_errno(int); | |||
449 | decode_restorefh_maxsz + \ | 556 | decode_restorefh_maxsz + \ |
450 | decode_getattr_maxsz) | 557 | decode_getattr_maxsz) |
451 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ | 558 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ |
559 | encode_sequence_maxsz + \ | ||
452 | encode_putfh_maxsz + \ | 560 | encode_putfh_maxsz + \ |
453 | encode_symlink_maxsz + \ | 561 | encode_symlink_maxsz + \ |
454 | encode_getattr_maxsz + \ | 562 | encode_getattr_maxsz + \ |
455 | encode_getfh_maxsz) | 563 | encode_getfh_maxsz) |
456 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ | 564 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ |
565 | decode_sequence_maxsz + \ | ||
457 | decode_putfh_maxsz + \ | 566 | decode_putfh_maxsz + \ |
458 | decode_symlink_maxsz + \ | 567 | decode_symlink_maxsz + \ |
459 | decode_getattr_maxsz + \ | 568 | decode_getattr_maxsz + \ |
460 | decode_getfh_maxsz) | 569 | decode_getfh_maxsz) |
461 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ | 570 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ |
571 | encode_sequence_maxsz + \ | ||
462 | encode_putfh_maxsz + \ | 572 | encode_putfh_maxsz + \ |
463 | encode_savefh_maxsz + \ | 573 | encode_savefh_maxsz + \ |
464 | encode_create_maxsz + \ | 574 | encode_create_maxsz + \ |
@@ -467,6 +577,7 @@ static int nfs4_stat_to_errno(int); | |||
467 | encode_restorefh_maxsz + \ | 577 | encode_restorefh_maxsz + \ |
468 | encode_getattr_maxsz) | 578 | encode_getattr_maxsz) |
469 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ | 579 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ |
580 | decode_sequence_maxsz + \ | ||
470 | decode_putfh_maxsz + \ | 581 | decode_putfh_maxsz + \ |
471 | decode_savefh_maxsz + \ | 582 | decode_savefh_maxsz + \ |
472 | decode_create_maxsz + \ | 583 | decode_create_maxsz + \ |
@@ -475,52 +586,98 @@ static int nfs4_stat_to_errno(int); | |||
475 | decode_restorefh_maxsz + \ | 586 | decode_restorefh_maxsz + \ |
476 | decode_getattr_maxsz) | 587 | decode_getattr_maxsz) |
477 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ | 588 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ |
589 | encode_sequence_maxsz + \ | ||
478 | encode_putfh_maxsz + \ | 590 | encode_putfh_maxsz + \ |
479 | encode_getattr_maxsz) | 591 | encode_getattr_maxsz) |
480 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ | 592 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ |
593 | decode_sequence_maxsz + \ | ||
481 | decode_putfh_maxsz + \ | 594 | decode_putfh_maxsz + \ |
482 | decode_getattr_maxsz) | 595 | decode_getattr_maxsz) |
483 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ | 596 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ |
597 | encode_sequence_maxsz + \ | ||
484 | encode_putfh_maxsz + \ | 598 | encode_putfh_maxsz + \ |
485 | encode_statfs_maxsz) | 599 | encode_statfs_maxsz) |
486 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ | 600 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ |
601 | decode_sequence_maxsz + \ | ||
487 | decode_putfh_maxsz + \ | 602 | decode_putfh_maxsz + \ |
488 | decode_statfs_maxsz) | 603 | decode_statfs_maxsz) |
489 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ | 604 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ |
605 | encode_sequence_maxsz + \ | ||
490 | encode_putfh_maxsz + \ | 606 | encode_putfh_maxsz + \ |
491 | encode_getattr_maxsz) | 607 | encode_getattr_maxsz) |
492 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ | 608 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ |
609 | decode_sequence_maxsz + \ | ||
493 | decode_putfh_maxsz + \ | 610 | decode_putfh_maxsz + \ |
494 | decode_getattr_maxsz) | 611 | decode_getattr_maxsz) |
495 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 612 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
613 | encode_sequence_maxsz + \ | ||
496 | encode_putfh_maxsz + \ | 614 | encode_putfh_maxsz + \ |
497 | encode_delegreturn_maxsz + \ | 615 | encode_delegreturn_maxsz + \ |
498 | encode_getattr_maxsz) | 616 | encode_getattr_maxsz) |
499 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 617 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
618 | decode_sequence_maxsz + \ | ||
500 | decode_delegreturn_maxsz + \ | 619 | decode_delegreturn_maxsz + \ |
501 | decode_getattr_maxsz) | 620 | decode_getattr_maxsz) |
502 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | 621 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ |
622 | encode_sequence_maxsz + \ | ||
503 | encode_putfh_maxsz + \ | 623 | encode_putfh_maxsz + \ |
504 | encode_getacl_maxsz) | 624 | encode_getacl_maxsz) |
505 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | 625 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ |
626 | decode_sequence_maxsz + \ | ||
506 | decode_putfh_maxsz + \ | 627 | decode_putfh_maxsz + \ |
507 | decode_getacl_maxsz) | 628 | decode_getacl_maxsz) |
508 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | 629 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ |
630 | encode_sequence_maxsz + \ | ||
509 | encode_putfh_maxsz + \ | 631 | encode_putfh_maxsz + \ |
510 | encode_setacl_maxsz) | 632 | encode_setacl_maxsz) |
511 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | 633 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ |
634 | decode_sequence_maxsz + \ | ||
512 | decode_putfh_maxsz + \ | 635 | decode_putfh_maxsz + \ |
513 | decode_setacl_maxsz) | 636 | decode_setacl_maxsz) |
514 | #define NFS4_enc_fs_locations_sz \ | 637 | #define NFS4_enc_fs_locations_sz \ |
515 | (compound_encode_hdr_maxsz + \ | 638 | (compound_encode_hdr_maxsz + \ |
639 | encode_sequence_maxsz + \ | ||
516 | encode_putfh_maxsz + \ | 640 | encode_putfh_maxsz + \ |
517 | encode_lookup_maxsz + \ | 641 | encode_lookup_maxsz + \ |
518 | encode_fs_locations_maxsz) | 642 | encode_fs_locations_maxsz) |
519 | #define NFS4_dec_fs_locations_sz \ | 643 | #define NFS4_dec_fs_locations_sz \ |
520 | (compound_decode_hdr_maxsz + \ | 644 | (compound_decode_hdr_maxsz + \ |
645 | decode_sequence_maxsz + \ | ||
521 | decode_putfh_maxsz + \ | 646 | decode_putfh_maxsz + \ |
522 | decode_lookup_maxsz + \ | 647 | decode_lookup_maxsz + \ |
523 | decode_fs_locations_maxsz) | 648 | decode_fs_locations_maxsz) |
649 | #if defined(CONFIG_NFS_V4_1) | ||
650 | #define NFS4_enc_exchange_id_sz \ | ||
651 | (compound_encode_hdr_maxsz + \ | ||
652 | encode_exchange_id_maxsz) | ||
653 | #define NFS4_dec_exchange_id_sz \ | ||
654 | (compound_decode_hdr_maxsz + \ | ||
655 | decode_exchange_id_maxsz) | ||
656 | #define NFS4_enc_create_session_sz \ | ||
657 | (compound_encode_hdr_maxsz + \ | ||
658 | encode_create_session_maxsz) | ||
659 | #define NFS4_dec_create_session_sz \ | ||
660 | (compound_decode_hdr_maxsz + \ | ||
661 | decode_create_session_maxsz) | ||
662 | #define NFS4_enc_destroy_session_sz (compound_encode_hdr_maxsz + \ | ||
663 | encode_destroy_session_maxsz) | ||
664 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ | ||
665 | decode_destroy_session_maxsz) | ||
666 | #define NFS4_enc_sequence_sz \ | ||
667 | (compound_decode_hdr_maxsz + \ | ||
668 | encode_sequence_maxsz) | ||
669 | #define NFS4_dec_sequence_sz \ | ||
670 | (compound_decode_hdr_maxsz + \ | ||
671 | decode_sequence_maxsz) | ||
672 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ | ||
673 | encode_sequence_maxsz + \ | ||
674 | encode_putrootfh_maxsz + \ | ||
675 | encode_fsinfo_maxsz) | ||
676 | #define NFS4_dec_get_lease_time_sz (compound_decode_hdr_maxsz + \ | ||
677 | decode_sequence_maxsz + \ | ||
678 | decode_putrootfh_maxsz + \ | ||
679 | decode_fsinfo_maxsz) | ||
680 | #endif /* CONFIG_NFS_V4_1 */ | ||
524 | 681 | ||
525 | static const umode_t nfs_type2fmt[] = { | 682 | static const umode_t nfs_type2fmt[] = { |
526 | [NF4BAD] = 0, | 683 | [NF4BAD] = 0, |
@@ -541,6 +698,8 @@ struct compound_hdr { | |||
541 | __be32 * nops_p; | 698 | __be32 * nops_p; |
542 | uint32_t taglen; | 699 | uint32_t taglen; |
543 | char * tag; | 700 | char * tag; |
701 | uint32_t replen; /* expected reply words */ | ||
702 | u32 minorversion; | ||
544 | }; | 703 | }; |
545 | 704 | ||
546 | /* | 705 | /* |
@@ -576,22 +735,31 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * | |||
576 | xdr_encode_opaque(p, str, len); | 735 | xdr_encode_opaque(p, str, len); |
577 | } | 736 | } |
578 | 737 | ||
579 | static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 738 | static void encode_compound_hdr(struct xdr_stream *xdr, |
739 | struct rpc_rqst *req, | ||
740 | struct compound_hdr *hdr) | ||
580 | { | 741 | { |
581 | __be32 *p; | 742 | __be32 *p; |
743 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
744 | |||
745 | /* initialize running count of expected bytes in reply. | ||
746 | * NOTE: the replied tag SHOULD be the same is the one sent, | ||
747 | * but this is not required as a MUST for the server to do so. */ | ||
748 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; | ||
582 | 749 | ||
583 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | 750 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); |
584 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 751 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
585 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); | 752 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); |
586 | WRITE32(hdr->taglen); | 753 | WRITE32(hdr->taglen); |
587 | WRITEMEM(hdr->tag, hdr->taglen); | 754 | WRITEMEM(hdr->tag, hdr->taglen); |
588 | WRITE32(NFS4_MINOR_VERSION); | 755 | WRITE32(hdr->minorversion); |
589 | hdr->nops_p = p; | 756 | hdr->nops_p = p; |
590 | WRITE32(hdr->nops); | 757 | WRITE32(hdr->nops); |
591 | } | 758 | } |
592 | 759 | ||
593 | static void encode_nops(struct compound_hdr *hdr) | 760 | static void encode_nops(struct compound_hdr *hdr) |
594 | { | 761 | { |
762 | BUG_ON(hdr->nops > NFS4_MAX_OPS); | ||
595 | *hdr->nops_p = htonl(hdr->nops); | 763 | *hdr->nops_p = htonl(hdr->nops); |
596 | } | 764 | } |
597 | 765 | ||
@@ -736,6 +904,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd | |||
736 | WRITE32(OP_ACCESS); | 904 | WRITE32(OP_ACCESS); |
737 | WRITE32(access); | 905 | WRITE32(access); |
738 | hdr->nops++; | 906 | hdr->nops++; |
907 | hdr->replen += decode_access_maxsz; | ||
739 | } | 908 | } |
740 | 909 | ||
741 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 910 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -747,6 +916,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg | |||
747 | WRITE32(arg->seqid->sequence->counter); | 916 | WRITE32(arg->seqid->sequence->counter); |
748 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 917 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
749 | hdr->nops++; | 918 | hdr->nops++; |
919 | hdr->replen += decode_close_maxsz; | ||
750 | } | 920 | } |
751 | 921 | ||
752 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 922 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -758,6 +928,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar | |||
758 | WRITE64(args->offset); | 928 | WRITE64(args->offset); |
759 | WRITE32(args->count); | 929 | WRITE32(args->count); |
760 | hdr->nops++; | 930 | hdr->nops++; |
931 | hdr->replen += decode_commit_maxsz; | ||
761 | } | 932 | } |
762 | 933 | ||
763 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) | 934 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
@@ -789,6 +960,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
789 | WRITE32(create->name->len); | 960 | WRITE32(create->name->len); |
790 | WRITEMEM(create->name->name, create->name->len); | 961 | WRITEMEM(create->name->name, create->name->len); |
791 | hdr->nops++; | 962 | hdr->nops++; |
963 | hdr->replen += decode_create_maxsz; | ||
792 | 964 | ||
793 | encode_attrs(xdr, create->attrs, create->server); | 965 | encode_attrs(xdr, create->attrs, create->server); |
794 | } | 966 | } |
@@ -802,6 +974,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
802 | WRITE32(1); | 974 | WRITE32(1); |
803 | WRITE32(bitmap); | 975 | WRITE32(bitmap); |
804 | hdr->nops++; | 976 | hdr->nops++; |
977 | hdr->replen += decode_getattr_maxsz; | ||
805 | } | 978 | } |
806 | 979 | ||
807 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | 980 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
@@ -814,6 +987,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm | |||
814 | WRITE32(bm0); | 987 | WRITE32(bm0); |
815 | WRITE32(bm1); | 988 | WRITE32(bm1); |
816 | hdr->nops++; | 989 | hdr->nops++; |
990 | hdr->replen += decode_getattr_maxsz; | ||
817 | } | 991 | } |
818 | 992 | ||
819 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 993 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
@@ -841,6 +1015,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
841 | RESERVE_SPACE(4); | 1015 | RESERVE_SPACE(4); |
842 | WRITE32(OP_GETFH); | 1016 | WRITE32(OP_GETFH); |
843 | hdr->nops++; | 1017 | hdr->nops++; |
1018 | hdr->replen += decode_getfh_maxsz; | ||
844 | } | 1019 | } |
845 | 1020 | ||
846 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1021 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -852,6 +1027,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
852 | WRITE32(name->len); | 1027 | WRITE32(name->len); |
853 | WRITEMEM(name->name, name->len); | 1028 | WRITEMEM(name->name, name->len); |
854 | hdr->nops++; | 1029 | hdr->nops++; |
1030 | hdr->replen += decode_link_maxsz; | ||
855 | } | 1031 | } |
856 | 1032 | ||
857 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1033 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
@@ -899,6 +1075,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
899 | WRITE32(args->lock_seqid->sequence->counter); | 1075 | WRITE32(args->lock_seqid->sequence->counter); |
900 | } | 1076 | } |
901 | hdr->nops++; | 1077 | hdr->nops++; |
1078 | hdr->replen += decode_lock_maxsz; | ||
902 | } | 1079 | } |
903 | 1080 | ||
904 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) | 1081 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
@@ -915,6 +1092,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
915 | WRITEMEM("lock id:", 8); | 1092 | WRITEMEM("lock id:", 8); |
916 | WRITE64(args->lock_owner.id); | 1093 | WRITE64(args->lock_owner.id); |
917 | hdr->nops++; | 1094 | hdr->nops++; |
1095 | hdr->replen += decode_lockt_maxsz; | ||
918 | } | 1096 | } |
919 | 1097 | ||
920 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) | 1098 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
@@ -929,6 +1107,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
929 | WRITE64(args->fl->fl_start); | 1107 | WRITE64(args->fl->fl_start); |
930 | WRITE64(nfs4_lock_length(args->fl)); | 1108 | WRITE64(nfs4_lock_length(args->fl)); |
931 | hdr->nops++; | 1109 | hdr->nops++; |
1110 | hdr->replen += decode_locku_maxsz; | ||
932 | } | 1111 | } |
933 | 1112 | ||
934 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1113 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -941,6 +1120,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc | |||
941 | WRITE32(len); | 1120 | WRITE32(len); |
942 | WRITEMEM(name->name, len); | 1121 | WRITEMEM(name->name, len); |
943 | hdr->nops++; | 1122 | hdr->nops++; |
1123 | hdr->replen += decode_lookup_maxsz; | ||
944 | } | 1124 | } |
945 | 1125 | ||
946 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | 1126 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
@@ -1080,6 +1260,7 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
1080 | BUG(); | 1260 | BUG(); |
1081 | } | 1261 | } |
1082 | hdr->nops++; | 1262 | hdr->nops++; |
1263 | hdr->replen += decode_open_maxsz; | ||
1083 | } | 1264 | } |
1084 | 1265 | ||
1085 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) | 1266 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
@@ -1091,6 +1272,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co | |||
1091 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1272 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
1092 | WRITE32(arg->seqid->sequence->counter); | 1273 | WRITE32(arg->seqid->sequence->counter); |
1093 | hdr->nops++; | 1274 | hdr->nops++; |
1275 | hdr->replen += decode_open_confirm_maxsz; | ||
1094 | } | 1276 | } |
1095 | 1277 | ||
1096 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1278 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -1103,6 +1285,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close | |||
1103 | WRITE32(arg->seqid->sequence->counter); | 1285 | WRITE32(arg->seqid->sequence->counter); |
1104 | encode_share_access(xdr, arg->fmode); | 1286 | encode_share_access(xdr, arg->fmode); |
1105 | hdr->nops++; | 1287 | hdr->nops++; |
1288 | hdr->replen += decode_open_downgrade_maxsz; | ||
1106 | } | 1289 | } |
1107 | 1290 | ||
1108 | static void | 1291 | static void |
@@ -1116,6 +1299,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd | |||
1116 | WRITE32(len); | 1299 | WRITE32(len); |
1117 | WRITEMEM(fh->data, len); | 1300 | WRITEMEM(fh->data, len); |
1118 | hdr->nops++; | 1301 | hdr->nops++; |
1302 | hdr->replen += decode_putfh_maxsz; | ||
1119 | } | 1303 | } |
1120 | 1304 | ||
1121 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1305 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
@@ -1125,6 +1309,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1125 | RESERVE_SPACE(4); | 1309 | RESERVE_SPACE(4); |
1126 | WRITE32(OP_PUTROOTFH); | 1310 | WRITE32(OP_PUTROOTFH); |
1127 | hdr->nops++; | 1311 | hdr->nops++; |
1312 | hdr->replen += decode_putrootfh_maxsz; | ||
1128 | } | 1313 | } |
1129 | 1314 | ||
1130 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1315 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
@@ -1153,6 +1338,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1153 | WRITE64(args->offset); | 1338 | WRITE64(args->offset); |
1154 | WRITE32(args->count); | 1339 | WRITE32(args->count); |
1155 | hdr->nops++; | 1340 | hdr->nops++; |
1341 | hdr->replen += decode_read_maxsz; | ||
1156 | } | 1342 | } |
1157 | 1343 | ||
1158 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1344 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
@@ -1178,6 +1364,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1178 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1364 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1179 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1365 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1180 | hdr->nops++; | 1366 | hdr->nops++; |
1367 | hdr->replen += decode_readdir_maxsz; | ||
1181 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1368 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1182 | __func__, | 1369 | __func__, |
1183 | (unsigned long long)readdir->cookie, | 1370 | (unsigned long long)readdir->cookie, |
@@ -1194,6 +1381,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * | |||
1194 | RESERVE_SPACE(4); | 1381 | RESERVE_SPACE(4); |
1195 | WRITE32(OP_READLINK); | 1382 | WRITE32(OP_READLINK); |
1196 | hdr->nops++; | 1383 | hdr->nops++; |
1384 | hdr->replen += decode_readlink_maxsz; | ||
1197 | } | 1385 | } |
1198 | 1386 | ||
1199 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1387 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -1205,6 +1393,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc | |||
1205 | WRITE32(name->len); | 1393 | WRITE32(name->len); |
1206 | WRITEMEM(name->name, name->len); | 1394 | WRITEMEM(name->name, name->len); |
1207 | hdr->nops++; | 1395 | hdr->nops++; |
1396 | hdr->replen += decode_remove_maxsz; | ||
1208 | } | 1397 | } |
1209 | 1398 | ||
1210 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) | 1399 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
@@ -1220,6 +1409,7 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co | |||
1220 | WRITE32(newname->len); | 1409 | WRITE32(newname->len); |
1221 | WRITEMEM(newname->name, newname->len); | 1410 | WRITEMEM(newname->name, newname->len); |
1222 | hdr->nops++; | 1411 | hdr->nops++; |
1412 | hdr->replen += decode_rename_maxsz; | ||
1223 | } | 1413 | } |
1224 | 1414 | ||
1225 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) | 1415 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) |
@@ -1230,6 +1420,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client | |||
1230 | WRITE32(OP_RENEW); | 1420 | WRITE32(OP_RENEW); |
1231 | WRITE64(client_stateid->cl_clientid); | 1421 | WRITE64(client_stateid->cl_clientid); |
1232 | hdr->nops++; | 1422 | hdr->nops++; |
1423 | hdr->replen += decode_renew_maxsz; | ||
1233 | } | 1424 | } |
1234 | 1425 | ||
1235 | static void | 1426 | static void |
@@ -1240,6 +1431,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1240 | RESERVE_SPACE(4); | 1431 | RESERVE_SPACE(4); |
1241 | WRITE32(OP_RESTOREFH); | 1432 | WRITE32(OP_RESTOREFH); |
1242 | hdr->nops++; | 1433 | hdr->nops++; |
1434 | hdr->replen += decode_restorefh_maxsz; | ||
1243 | } | 1435 | } |
1244 | 1436 | ||
1245 | static int | 1437 | static int |
@@ -1259,6 +1451,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
1259 | WRITE32(arg->acl_len); | 1451 | WRITE32(arg->acl_len); |
1260 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1452 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
1261 | hdr->nops++; | 1453 | hdr->nops++; |
1454 | hdr->replen += decode_setacl_maxsz; | ||
1262 | return 0; | 1455 | return 0; |
1263 | } | 1456 | } |
1264 | 1457 | ||
@@ -1270,6 +1463,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1270 | RESERVE_SPACE(4); | 1463 | RESERVE_SPACE(4); |
1271 | WRITE32(OP_SAVEFH); | 1464 | WRITE32(OP_SAVEFH); |
1272 | hdr->nops++; | 1465 | hdr->nops++; |
1466 | hdr->replen += decode_savefh_maxsz; | ||
1273 | } | 1467 | } |
1274 | 1468 | ||
1275 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) | 1469 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
@@ -1280,6 +1474,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
1280 | WRITE32(OP_SETATTR); | 1474 | WRITE32(OP_SETATTR); |
1281 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | 1475 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); |
1282 | hdr->nops++; | 1476 | hdr->nops++; |
1477 | hdr->replen += decode_setattr_maxsz; | ||
1283 | encode_attrs(xdr, arg->iap, server); | 1478 | encode_attrs(xdr, arg->iap, server); |
1284 | } | 1479 | } |
1285 | 1480 | ||
@@ -1299,6 +1494,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
1299 | RESERVE_SPACE(4); | 1494 | RESERVE_SPACE(4); |
1300 | WRITE32(setclientid->sc_cb_ident); | 1495 | WRITE32(setclientid->sc_cb_ident); |
1301 | hdr->nops++; | 1496 | hdr->nops++; |
1497 | hdr->replen += decode_setclientid_maxsz; | ||
1302 | } | 1498 | } |
1303 | 1499 | ||
1304 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1500 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) |
@@ -1310,6 +1506,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ | |||
1310 | WRITE64(client_state->cl_clientid); | 1506 | WRITE64(client_state->cl_clientid); |
1311 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1507 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); |
1312 | hdr->nops++; | 1508 | hdr->nops++; |
1509 | hdr->replen += decode_setclientid_confirm_maxsz; | ||
1313 | } | 1510 | } |
1314 | 1511 | ||
1315 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1512 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -1328,6 +1525,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
1328 | 1525 | ||
1329 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1526 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
1330 | hdr->nops++; | 1527 | hdr->nops++; |
1528 | hdr->replen += decode_write_maxsz; | ||
1331 | } | 1529 | } |
1332 | 1530 | ||
1333 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) | 1531 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
@@ -1339,11 +1537,163 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1339 | WRITE32(OP_DELEGRETURN); | 1537 | WRITE32(OP_DELEGRETURN); |
1340 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1538 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); |
1341 | hdr->nops++; | 1539 | hdr->nops++; |
1540 | hdr->replen += decode_delegreturn_maxsz; | ||
1541 | } | ||
1542 | |||
1543 | #if defined(CONFIG_NFS_V4_1) | ||
1544 | /* NFSv4.1 operations */ | ||
1545 | static void encode_exchange_id(struct xdr_stream *xdr, | ||
1546 | struct nfs41_exchange_id_args *args, | ||
1547 | struct compound_hdr *hdr) | ||
1548 | { | ||
1549 | __be32 *p; | ||
1550 | |||
1551 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | ||
1552 | WRITE32(OP_EXCHANGE_ID); | ||
1553 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | ||
1554 | |||
1555 | encode_string(xdr, args->id_len, args->id); | ||
1556 | |||
1557 | RESERVE_SPACE(12); | ||
1558 | WRITE32(args->flags); | ||
1559 | WRITE32(0); /* zero length state_protect4_a */ | ||
1560 | WRITE32(0); /* zero length implementation id array */ | ||
1561 | hdr->nops++; | ||
1562 | hdr->replen += decode_exchange_id_maxsz; | ||
1563 | } | ||
1564 | |||
1565 | static void encode_create_session(struct xdr_stream *xdr, | ||
1566 | struct nfs41_create_session_args *args, | ||
1567 | struct compound_hdr *hdr) | ||
1568 | { | ||
1569 | __be32 *p; | ||
1570 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | ||
1571 | uint32_t len; | ||
1572 | struct nfs_client *clp = args->client; | ||
1573 | |||
1574 | RESERVE_SPACE(4); | ||
1575 | WRITE32(OP_CREATE_SESSION); | ||
1576 | |||
1577 | RESERVE_SPACE(8); | ||
1578 | WRITE64(clp->cl_ex_clid); | ||
1579 | |||
1580 | RESERVE_SPACE(8); | ||
1581 | WRITE32(clp->cl_seqid); /*Sequence id */ | ||
1582 | WRITE32(args->flags); /*flags */ | ||
1583 | |||
1584 | RESERVE_SPACE(2*28); /* 2 channel_attrs */ | ||
1585 | /* Fore Channel */ | ||
1586 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1587 | WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ | ||
1588 | WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ | ||
1589 | WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1590 | WRITE32(args->fc_attrs.max_ops); /* max operations */ | ||
1591 | WRITE32(args->fc_attrs.max_reqs); /* max requests */ | ||
1592 | WRITE32(0); /* rdmachannel_attrs */ | ||
1593 | |||
1594 | /* Back Channel */ | ||
1595 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1596 | WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ | ||
1597 | WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ | ||
1598 | WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1599 | WRITE32(args->bc_attrs.max_ops); /* max operations */ | ||
1600 | WRITE32(args->bc_attrs.max_reqs); /* max requests */ | ||
1601 | WRITE32(0); /* rdmachannel_attrs */ | ||
1602 | |||
1603 | RESERVE_SPACE(4); | ||
1604 | WRITE32(args->cb_program); /* cb_program */ | ||
1605 | |||
1606 | RESERVE_SPACE(4); /* # of security flavors */ | ||
1607 | WRITE32(1); | ||
1608 | |||
1609 | RESERVE_SPACE(4); | ||
1610 | WRITE32(RPC_AUTH_UNIX); /* auth_sys */ | ||
1611 | |||
1612 | /* authsys_parms rfc1831 */ | ||
1613 | RESERVE_SPACE(4); | ||
1614 | WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ | ||
1615 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | ||
1616 | clp->cl_ipaddr); | ||
1617 | RESERVE_SPACE(16 + len); | ||
1618 | WRITE32(len); | ||
1619 | WRITEMEM(machine_name, len); | ||
1620 | WRITE32(0); /* UID */ | ||
1621 | WRITE32(0); /* GID */ | ||
1622 | WRITE32(0); /* No more gids */ | ||
1623 | hdr->nops++; | ||
1624 | hdr->replen += decode_create_session_maxsz; | ||
1625 | } | ||
1626 | |||
1627 | static void encode_destroy_session(struct xdr_stream *xdr, | ||
1628 | struct nfs4_session *session, | ||
1629 | struct compound_hdr *hdr) | ||
1630 | { | ||
1631 | __be32 *p; | ||
1632 | RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); | ||
1633 | WRITE32(OP_DESTROY_SESSION); | ||
1634 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1635 | hdr->nops++; | ||
1636 | hdr->replen += decode_destroy_session_maxsz; | ||
1342 | } | 1637 | } |
1638 | #endif /* CONFIG_NFS_V4_1 */ | ||
1639 | |||
1640 | static void encode_sequence(struct xdr_stream *xdr, | ||
1641 | const struct nfs4_sequence_args *args, | ||
1642 | struct compound_hdr *hdr) | ||
1643 | { | ||
1644 | #if defined(CONFIG_NFS_V4_1) | ||
1645 | struct nfs4_session *session = args->sa_session; | ||
1646 | struct nfs4_slot_table *tp; | ||
1647 | struct nfs4_slot *slot; | ||
1648 | __be32 *p; | ||
1649 | |||
1650 | if (!session) | ||
1651 | return; | ||
1652 | |||
1653 | tp = &session->fc_slot_table; | ||
1654 | |||
1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | ||
1656 | slot = tp->slots + args->sa_slotid; | ||
1657 | |||
1658 | RESERVE_SPACE(4); | ||
1659 | WRITE32(OP_SEQUENCE); | ||
1660 | |||
1661 | /* | ||
1662 | * Sessionid + seqid + slotid + max slotid + cache_this | ||
1663 | */ | ||
1664 | dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d " | ||
1665 | "max_slotid=%d cache_this=%d\n", | ||
1666 | __func__, | ||
1667 | ((u32 *)session->sess_id.data)[0], | ||
1668 | ((u32 *)session->sess_id.data)[1], | ||
1669 | ((u32 *)session->sess_id.data)[2], | ||
1670 | ((u32 *)session->sess_id.data)[3], | ||
1671 | slot->seq_nr, args->sa_slotid, | ||
1672 | tp->highest_used_slotid, args->sa_cache_this); | ||
1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | ||
1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1675 | WRITE32(slot->seq_nr); | ||
1676 | WRITE32(args->sa_slotid); | ||
1677 | WRITE32(tp->highest_used_slotid); | ||
1678 | WRITE32(args->sa_cache_this); | ||
1679 | hdr->nops++; | ||
1680 | hdr->replen += decode_sequence_maxsz; | ||
1681 | #endif /* CONFIG_NFS_V4_1 */ | ||
1682 | } | ||
1683 | |||
1343 | /* | 1684 | /* |
1344 | * END OF "GENERIC" ENCODE ROUTINES. | 1685 | * END OF "GENERIC" ENCODE ROUTINES. |
1345 | */ | 1686 | */ |
1346 | 1687 | ||
1688 | static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | ||
1689 | { | ||
1690 | #if defined(CONFIG_NFS_V4_1) | ||
1691 | if (args->sa_session) | ||
1692 | return args->sa_session->clp->cl_minorversion; | ||
1693 | #endif /* CONFIG_NFS_V4_1 */ | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1347 | /* | 1697 | /* |
1348 | * Encode an ACCESS request | 1698 | * Encode an ACCESS request |
1349 | */ | 1699 | */ |
@@ -1351,11 +1701,12 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1351 | { | 1701 | { |
1352 | struct xdr_stream xdr; | 1702 | struct xdr_stream xdr; |
1353 | struct compound_hdr hdr = { | 1703 | struct compound_hdr hdr = { |
1354 | .nops = 0, | 1704 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1355 | }; | 1705 | }; |
1356 | 1706 | ||
1357 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1707 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1358 | encode_compound_hdr(&xdr, &hdr); | 1708 | encode_compound_hdr(&xdr, req, &hdr); |
1709 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1359 | encode_putfh(&xdr, args->fh, &hdr); | 1710 | encode_putfh(&xdr, args->fh, &hdr); |
1360 | encode_access(&xdr, args->access, &hdr); | 1711 | encode_access(&xdr, args->access, &hdr); |
1361 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1712 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1370,11 +1721,12 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1370 | { | 1721 | { |
1371 | struct xdr_stream xdr; | 1722 | struct xdr_stream xdr; |
1372 | struct compound_hdr hdr = { | 1723 | struct compound_hdr hdr = { |
1373 | .nops = 0, | 1724 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1374 | }; | 1725 | }; |
1375 | 1726 | ||
1376 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1727 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1377 | encode_compound_hdr(&xdr, &hdr); | 1728 | encode_compound_hdr(&xdr, req, &hdr); |
1729 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1378 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1730 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1379 | encode_lookup(&xdr, args->name, &hdr); | 1731 | encode_lookup(&xdr, args->name, &hdr); |
1380 | encode_getfh(&xdr, &hdr); | 1732 | encode_getfh(&xdr, &hdr); |
@@ -1390,11 +1742,12 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc | |||
1390 | { | 1742 | { |
1391 | struct xdr_stream xdr; | 1743 | struct xdr_stream xdr; |
1392 | struct compound_hdr hdr = { | 1744 | struct compound_hdr hdr = { |
1393 | .nops = 0, | 1745 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1394 | }; | 1746 | }; |
1395 | 1747 | ||
1396 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1748 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1397 | encode_compound_hdr(&xdr, &hdr); | 1749 | encode_compound_hdr(&xdr, req, &hdr); |
1750 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1398 | encode_putrootfh(&xdr, &hdr); | 1751 | encode_putrootfh(&xdr, &hdr); |
1399 | encode_getfh(&xdr, &hdr); | 1752 | encode_getfh(&xdr, &hdr); |
1400 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1753 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1409,11 +1762,12 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1409 | { | 1762 | { |
1410 | struct xdr_stream xdr; | 1763 | struct xdr_stream xdr; |
1411 | struct compound_hdr hdr = { | 1764 | struct compound_hdr hdr = { |
1412 | .nops = 0, | 1765 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1413 | }; | 1766 | }; |
1414 | 1767 | ||
1415 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1768 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1416 | encode_compound_hdr(&xdr, &hdr); | 1769 | encode_compound_hdr(&xdr, req, &hdr); |
1770 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1417 | encode_putfh(&xdr, args->fh, &hdr); | 1771 | encode_putfh(&xdr, args->fh, &hdr); |
1418 | encode_remove(&xdr, &args->name, &hdr); | 1772 | encode_remove(&xdr, &args->name, &hdr); |
1419 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1773 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1428,11 +1782,12 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1428 | { | 1782 | { |
1429 | struct xdr_stream xdr; | 1783 | struct xdr_stream xdr; |
1430 | struct compound_hdr hdr = { | 1784 | struct compound_hdr hdr = { |
1431 | .nops = 0, | 1785 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1432 | }; | 1786 | }; |
1433 | 1787 | ||
1434 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1788 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1435 | encode_compound_hdr(&xdr, &hdr); | 1789 | encode_compound_hdr(&xdr, req, &hdr); |
1790 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1436 | encode_putfh(&xdr, args->old_dir, &hdr); | 1791 | encode_putfh(&xdr, args->old_dir, &hdr); |
1437 | encode_savefh(&xdr, &hdr); | 1792 | encode_savefh(&xdr, &hdr); |
1438 | encode_putfh(&xdr, args->new_dir, &hdr); | 1793 | encode_putfh(&xdr, args->new_dir, &hdr); |
@@ -1451,11 +1806,12 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_ | |||
1451 | { | 1806 | { |
1452 | struct xdr_stream xdr; | 1807 | struct xdr_stream xdr; |
1453 | struct compound_hdr hdr = { | 1808 | struct compound_hdr hdr = { |
1454 | .nops = 0, | 1809 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1455 | }; | 1810 | }; |
1456 | 1811 | ||
1457 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1812 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1458 | encode_compound_hdr(&xdr, &hdr); | 1813 | encode_compound_hdr(&xdr, req, &hdr); |
1814 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1459 | encode_putfh(&xdr, args->fh, &hdr); | 1815 | encode_putfh(&xdr, args->fh, &hdr); |
1460 | encode_savefh(&xdr, &hdr); | 1816 | encode_savefh(&xdr, &hdr); |
1461 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1817 | encode_putfh(&xdr, args->dir_fh, &hdr); |
@@ -1474,11 +1830,12 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1474 | { | 1830 | { |
1475 | struct xdr_stream xdr; | 1831 | struct xdr_stream xdr; |
1476 | struct compound_hdr hdr = { | 1832 | struct compound_hdr hdr = { |
1477 | .nops = 0, | 1833 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1478 | }; | 1834 | }; |
1479 | 1835 | ||
1480 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1836 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1481 | encode_compound_hdr(&xdr, &hdr); | 1837 | encode_compound_hdr(&xdr, req, &hdr); |
1838 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1482 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1839 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1483 | encode_savefh(&xdr, &hdr); | 1840 | encode_savefh(&xdr, &hdr); |
1484 | encode_create(&xdr, args, &hdr); | 1841 | encode_create(&xdr, args, &hdr); |
@@ -1505,11 +1862,12 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1505 | { | 1862 | { |
1506 | struct xdr_stream xdr; | 1863 | struct xdr_stream xdr; |
1507 | struct compound_hdr hdr = { | 1864 | struct compound_hdr hdr = { |
1508 | .nops = 0, | 1865 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1509 | }; | 1866 | }; |
1510 | 1867 | ||
1511 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1868 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1512 | encode_compound_hdr(&xdr, &hdr); | 1869 | encode_compound_hdr(&xdr, req, &hdr); |
1870 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1513 | encode_putfh(&xdr, args->fh, &hdr); | 1871 | encode_putfh(&xdr, args->fh, &hdr); |
1514 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1872 | encode_getfattr(&xdr, args->bitmask, &hdr); |
1515 | encode_nops(&hdr); | 1873 | encode_nops(&hdr); |
@@ -1523,11 +1881,12 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea | |||
1523 | { | 1881 | { |
1524 | struct xdr_stream xdr; | 1882 | struct xdr_stream xdr; |
1525 | struct compound_hdr hdr = { | 1883 | struct compound_hdr hdr = { |
1526 | .nops = 0, | 1884 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1527 | }; | 1885 | }; |
1528 | 1886 | ||
1529 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1887 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1530 | encode_compound_hdr(&xdr, &hdr); | 1888 | encode_compound_hdr(&xdr, req, &hdr); |
1889 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1531 | encode_putfh(&xdr, args->fh, &hdr); | 1890 | encode_putfh(&xdr, args->fh, &hdr); |
1532 | encode_close(&xdr, args, &hdr); | 1891 | encode_close(&xdr, args, &hdr); |
1533 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1892 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1542,11 +1901,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg | |||
1542 | { | 1901 | { |
1543 | struct xdr_stream xdr; | 1902 | struct xdr_stream xdr; |
1544 | struct compound_hdr hdr = { | 1903 | struct compound_hdr hdr = { |
1545 | .nops = 0, | 1904 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1546 | }; | 1905 | }; |
1547 | 1906 | ||
1548 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1907 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1549 | encode_compound_hdr(&xdr, &hdr); | 1908 | encode_compound_hdr(&xdr, req, &hdr); |
1909 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1550 | encode_putfh(&xdr, args->fh, &hdr); | 1910 | encode_putfh(&xdr, args->fh, &hdr); |
1551 | encode_savefh(&xdr, &hdr); | 1911 | encode_savefh(&xdr, &hdr); |
1552 | encode_open(&xdr, args, &hdr); | 1912 | encode_open(&xdr, args, &hdr); |
@@ -1569,7 +1929,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1569 | }; | 1929 | }; |
1570 | 1930 | ||
1571 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1572 | encode_compound_hdr(&xdr, &hdr); | 1932 | encode_compound_hdr(&xdr, req, &hdr); |
1573 | encode_putfh(&xdr, args->fh, &hdr); | 1933 | encode_putfh(&xdr, args->fh, &hdr); |
1574 | encode_open_confirm(&xdr, args, &hdr); | 1934 | encode_open_confirm(&xdr, args, &hdr); |
1575 | encode_nops(&hdr); | 1935 | encode_nops(&hdr); |
@@ -1583,11 +1943,12 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_ | |||
1583 | { | 1943 | { |
1584 | struct xdr_stream xdr; | 1944 | struct xdr_stream xdr; |
1585 | struct compound_hdr hdr = { | 1945 | struct compound_hdr hdr = { |
1586 | .nops = 0, | 1946 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1587 | }; | 1947 | }; |
1588 | 1948 | ||
1589 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1949 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1590 | encode_compound_hdr(&xdr, &hdr); | 1950 | encode_compound_hdr(&xdr, req, &hdr); |
1951 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1591 | encode_putfh(&xdr, args->fh, &hdr); | 1952 | encode_putfh(&xdr, args->fh, &hdr); |
1592 | encode_open(&xdr, args, &hdr); | 1953 | encode_open(&xdr, args, &hdr); |
1593 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1954 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1602,11 +1963,12 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n | |||
1602 | { | 1963 | { |
1603 | struct xdr_stream xdr; | 1964 | struct xdr_stream xdr; |
1604 | struct compound_hdr hdr = { | 1965 | struct compound_hdr hdr = { |
1605 | .nops = 0, | 1966 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1606 | }; | 1967 | }; |
1607 | 1968 | ||
1608 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1969 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1609 | encode_compound_hdr(&xdr, &hdr); | 1970 | encode_compound_hdr(&xdr, req, &hdr); |
1971 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1610 | encode_putfh(&xdr, args->fh, &hdr); | 1972 | encode_putfh(&xdr, args->fh, &hdr); |
1611 | encode_open_downgrade(&xdr, args, &hdr); | 1973 | encode_open_downgrade(&xdr, args, &hdr); |
1612 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1974 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1621,11 +1983,12 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar | |||
1621 | { | 1983 | { |
1622 | struct xdr_stream xdr; | 1984 | struct xdr_stream xdr; |
1623 | struct compound_hdr hdr = { | 1985 | struct compound_hdr hdr = { |
1624 | .nops = 0, | 1986 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1625 | }; | 1987 | }; |
1626 | 1988 | ||
1627 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1989 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1628 | encode_compound_hdr(&xdr, &hdr); | 1990 | encode_compound_hdr(&xdr, req, &hdr); |
1991 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1629 | encode_putfh(&xdr, args->fh, &hdr); | 1992 | encode_putfh(&xdr, args->fh, &hdr); |
1630 | encode_lock(&xdr, args, &hdr); | 1993 | encode_lock(&xdr, args, &hdr); |
1631 | encode_nops(&hdr); | 1994 | encode_nops(&hdr); |
@@ -1639,11 +2002,12 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_ | |||
1639 | { | 2002 | { |
1640 | struct xdr_stream xdr; | 2003 | struct xdr_stream xdr; |
1641 | struct compound_hdr hdr = { | 2004 | struct compound_hdr hdr = { |
1642 | .nops = 0, | 2005 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1643 | }; | 2006 | }; |
1644 | 2007 | ||
1645 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2008 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1646 | encode_compound_hdr(&xdr, &hdr); | 2009 | encode_compound_hdr(&xdr, req, &hdr); |
2010 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1647 | encode_putfh(&xdr, args->fh, &hdr); | 2011 | encode_putfh(&xdr, args->fh, &hdr); |
1648 | encode_lockt(&xdr, args, &hdr); | 2012 | encode_lockt(&xdr, args, &hdr); |
1649 | encode_nops(&hdr); | 2013 | encode_nops(&hdr); |
@@ -1657,11 +2021,12 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
1657 | { | 2021 | { |
1658 | struct xdr_stream xdr; | 2022 | struct xdr_stream xdr; |
1659 | struct compound_hdr hdr = { | 2023 | struct compound_hdr hdr = { |
1660 | .nops = 0, | 2024 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1661 | }; | 2025 | }; |
1662 | 2026 | ||
1663 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2027 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1664 | encode_compound_hdr(&xdr, &hdr); | 2028 | encode_compound_hdr(&xdr, req, &hdr); |
2029 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1665 | encode_putfh(&xdr, args->fh, &hdr); | 2030 | encode_putfh(&xdr, args->fh, &hdr); |
1666 | encode_locku(&xdr, args, &hdr); | 2031 | encode_locku(&xdr, args, &hdr); |
1667 | encode_nops(&hdr); | 2032 | encode_nops(&hdr); |
@@ -1675,22 +2040,16 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
1675 | { | 2040 | { |
1676 | struct xdr_stream xdr; | 2041 | struct xdr_stream xdr; |
1677 | struct compound_hdr hdr = { | 2042 | struct compound_hdr hdr = { |
1678 | .nops = 0, | 2043 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1679 | }; | 2044 | }; |
1680 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1681 | unsigned int replen; | ||
1682 | 2045 | ||
1683 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2046 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1684 | encode_compound_hdr(&xdr, &hdr); | 2047 | encode_compound_hdr(&xdr, req, &hdr); |
2048 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1685 | encode_putfh(&xdr, args->fh, &hdr); | 2049 | encode_putfh(&xdr, args->fh, &hdr); |
1686 | encode_readlink(&xdr, args, req, &hdr); | 2050 | encode_readlink(&xdr, args, req, &hdr); |
1687 | 2051 | ||
1688 | /* set up reply kvec | 2052 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1689 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1690 | * + OP_READLINK + status + string length = 8 | ||
1691 | */ | ||
1692 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; | ||
1693 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1694 | args->pgbase, args->pglen); | 2053 | args->pgbase, args->pglen); |
1695 | encode_nops(&hdr); | 2054 | encode_nops(&hdr); |
1696 | return 0; | 2055 | return 0; |
@@ -1703,25 +2062,19 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1703 | { | 2062 | { |
1704 | struct xdr_stream xdr; | 2063 | struct xdr_stream xdr; |
1705 | struct compound_hdr hdr = { | 2064 | struct compound_hdr hdr = { |
1706 | .nops = 0, | 2065 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1707 | }; | 2066 | }; |
1708 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1709 | int replen; | ||
1710 | 2067 | ||
1711 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2068 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1712 | encode_compound_hdr(&xdr, &hdr); | 2069 | encode_compound_hdr(&xdr, req, &hdr); |
2070 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1713 | encode_putfh(&xdr, args->fh, &hdr); | 2071 | encode_putfh(&xdr, args->fh, &hdr); |
1714 | encode_readdir(&xdr, args, req, &hdr); | 2072 | encode_readdir(&xdr, args, req, &hdr); |
1715 | 2073 | ||
1716 | /* set up reply kvec | 2074 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1717 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1718 | * + OP_READDIR + status + verifer(2) = 9 | ||
1719 | */ | ||
1720 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2; | ||
1721 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1722 | args->pgbase, args->count); | 2075 | args->pgbase, args->count); |
1723 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | 2076 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", |
1724 | __func__, replen, args->pages, | 2077 | __func__, hdr.replen << 2, args->pages, |
1725 | args->pgbase, args->count); | 2078 | args->pgbase, args->count); |
1726 | encode_nops(&hdr); | 2079 | encode_nops(&hdr); |
1727 | return 0; | 2080 | return 0; |
@@ -1732,24 +2085,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1732 | */ | 2085 | */ |
1733 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 2086 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
1734 | { | 2087 | { |
1735 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1736 | struct xdr_stream xdr; | 2088 | struct xdr_stream xdr; |
1737 | struct compound_hdr hdr = { | 2089 | struct compound_hdr hdr = { |
1738 | .nops = 0, | 2090 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1739 | }; | 2091 | }; |
1740 | int replen; | ||
1741 | 2092 | ||
1742 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2093 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1743 | encode_compound_hdr(&xdr, &hdr); | 2094 | encode_compound_hdr(&xdr, req, &hdr); |
2095 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1744 | encode_putfh(&xdr, args->fh, &hdr); | 2096 | encode_putfh(&xdr, args->fh, &hdr); |
1745 | encode_read(&xdr, args, &hdr); | 2097 | encode_read(&xdr, args, &hdr); |
1746 | 2098 | ||
1747 | /* set up reply kvec | 2099 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, |
1748 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status | ||
1749 | * + OP_READ + status + eof + datalen = 9 | ||
1750 | */ | ||
1751 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; | ||
1752 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1753 | args->pages, args->pgbase, args->count); | 2100 | args->pages, args->pgbase, args->count); |
1754 | req->rq_rcv_buf.flags |= XDRBUF_READ; | 2101 | req->rq_rcv_buf.flags |= XDRBUF_READ; |
1755 | encode_nops(&hdr); | 2102 | encode_nops(&hdr); |
@@ -1763,11 +2110,12 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta | |||
1763 | { | 2110 | { |
1764 | struct xdr_stream xdr; | 2111 | struct xdr_stream xdr; |
1765 | struct compound_hdr hdr = { | 2112 | struct compound_hdr hdr = { |
1766 | .nops = 0, | 2113 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1767 | }; | 2114 | }; |
1768 | 2115 | ||
1769 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2116 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1770 | encode_compound_hdr(&xdr, &hdr); | 2117 | encode_compound_hdr(&xdr, req, &hdr); |
2118 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1771 | encode_putfh(&xdr, args->fh, &hdr); | 2119 | encode_putfh(&xdr, args->fh, &hdr); |
1772 | encode_setattr(&xdr, args, args->server, &hdr); | 2120 | encode_setattr(&xdr, args, args->server, &hdr); |
1773 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2121 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1783,20 +2131,19 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
1783 | struct nfs_getaclargs *args) | 2131 | struct nfs_getaclargs *args) |
1784 | { | 2132 | { |
1785 | struct xdr_stream xdr; | 2133 | struct xdr_stream xdr; |
1786 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1787 | struct compound_hdr hdr = { | 2134 | struct compound_hdr hdr = { |
1788 | .nops = 0, | 2135 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1789 | }; | 2136 | }; |
1790 | int replen; | 2137 | uint32_t replen; |
1791 | 2138 | ||
1792 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2139 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1793 | encode_compound_hdr(&xdr, &hdr); | 2140 | encode_compound_hdr(&xdr, req, &hdr); |
2141 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1794 | encode_putfh(&xdr, args->fh, &hdr); | 2142 | encode_putfh(&xdr, args->fh, &hdr); |
2143 | replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1; | ||
1795 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2144 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
1796 | 2145 | ||
1797 | /* set up reply buffer: */ | 2146 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
1798 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1799 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1800 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2147 | args->acl_pages, args->acl_pgbase, args->acl_len); |
1801 | encode_nops(&hdr); | 2148 | encode_nops(&hdr); |
1802 | return 0; | 2149 | return 0; |
@@ -1809,11 +2156,12 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea | |||
1809 | { | 2156 | { |
1810 | struct xdr_stream xdr; | 2157 | struct xdr_stream xdr; |
1811 | struct compound_hdr hdr = { | 2158 | struct compound_hdr hdr = { |
1812 | .nops = 0, | 2159 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1813 | }; | 2160 | }; |
1814 | 2161 | ||
1815 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2162 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1816 | encode_compound_hdr(&xdr, &hdr); | 2163 | encode_compound_hdr(&xdr, req, &hdr); |
2164 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1817 | encode_putfh(&xdr, args->fh, &hdr); | 2165 | encode_putfh(&xdr, args->fh, &hdr); |
1818 | encode_write(&xdr, args, &hdr); | 2166 | encode_write(&xdr, args, &hdr); |
1819 | req->rq_snd_buf.flags |= XDRBUF_WRITE; | 2167 | req->rq_snd_buf.flags |= XDRBUF_WRITE; |
@@ -1829,11 +2177,12 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write | |||
1829 | { | 2177 | { |
1830 | struct xdr_stream xdr; | 2178 | struct xdr_stream xdr; |
1831 | struct compound_hdr hdr = { | 2179 | struct compound_hdr hdr = { |
1832 | .nops = 0, | 2180 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1833 | }; | 2181 | }; |
1834 | 2182 | ||
1835 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2183 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1836 | encode_compound_hdr(&xdr, &hdr); | 2184 | encode_compound_hdr(&xdr, req, &hdr); |
2185 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1837 | encode_putfh(&xdr, args->fh, &hdr); | 2186 | encode_putfh(&xdr, args->fh, &hdr); |
1838 | encode_commit(&xdr, args, &hdr); | 2187 | encode_commit(&xdr, args, &hdr); |
1839 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2188 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1848,11 +2197,12 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin | |||
1848 | { | 2197 | { |
1849 | struct xdr_stream xdr; | 2198 | struct xdr_stream xdr; |
1850 | struct compound_hdr hdr = { | 2199 | struct compound_hdr hdr = { |
1851 | .nops = 0, | 2200 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1852 | }; | 2201 | }; |
1853 | 2202 | ||
1854 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2203 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1855 | encode_compound_hdr(&xdr, &hdr); | 2204 | encode_compound_hdr(&xdr, req, &hdr); |
2205 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1856 | encode_putfh(&xdr, args->fh, &hdr); | 2206 | encode_putfh(&xdr, args->fh, &hdr); |
1857 | encode_fsinfo(&xdr, args->bitmask, &hdr); | 2207 | encode_fsinfo(&xdr, args->bitmask, &hdr); |
1858 | encode_nops(&hdr); | 2208 | encode_nops(&hdr); |
@@ -1866,11 +2216,12 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n | |||
1866 | { | 2216 | { |
1867 | struct xdr_stream xdr; | 2217 | struct xdr_stream xdr; |
1868 | struct compound_hdr hdr = { | 2218 | struct compound_hdr hdr = { |
1869 | .nops = 0, | 2219 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1870 | }; | 2220 | }; |
1871 | 2221 | ||
1872 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2222 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1873 | encode_compound_hdr(&xdr, &hdr); | 2223 | encode_compound_hdr(&xdr, req, &hdr); |
2224 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1874 | encode_putfh(&xdr, args->fh, &hdr); | 2225 | encode_putfh(&xdr, args->fh, &hdr); |
1875 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], | 2226 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], |
1876 | &hdr); | 2227 | &hdr); |
@@ -1885,11 +2236,12 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1885 | { | 2236 | { |
1886 | struct xdr_stream xdr; | 2237 | struct xdr_stream xdr; |
1887 | struct compound_hdr hdr = { | 2238 | struct compound_hdr hdr = { |
1888 | .nops = 0, | 2239 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1889 | }; | 2240 | }; |
1890 | 2241 | ||
1891 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2242 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1892 | encode_compound_hdr(&xdr, &hdr); | 2243 | encode_compound_hdr(&xdr, req, &hdr); |
2244 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1893 | encode_putfh(&xdr, args->fh, &hdr); | 2245 | encode_putfh(&xdr, args->fh, &hdr); |
1894 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], | 2246 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], |
1895 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); | 2247 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); |
@@ -1900,16 +2252,18 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1900 | /* | 2252 | /* |
1901 | * GETATTR_BITMAP request | 2253 | * GETATTR_BITMAP request |
1902 | */ | 2254 | */ |
1903 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle) | 2255 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, |
2256 | struct nfs4_server_caps_arg *args) | ||
1904 | { | 2257 | { |
1905 | struct xdr_stream xdr; | 2258 | struct xdr_stream xdr; |
1906 | struct compound_hdr hdr = { | 2259 | struct compound_hdr hdr = { |
1907 | .nops = 0, | 2260 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1908 | }; | 2261 | }; |
1909 | 2262 | ||
1910 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2263 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1911 | encode_compound_hdr(&xdr, &hdr); | 2264 | encode_compound_hdr(&xdr, req, &hdr); |
1912 | encode_putfh(&xdr, fhandle, &hdr); | 2265 | encode_sequence(&xdr, &args->seq_args, &hdr); |
2266 | encode_putfh(&xdr, args->fhandle, &hdr); | ||
1913 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 2267 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
1914 | FATTR4_WORD0_LINK_SUPPORT| | 2268 | FATTR4_WORD0_LINK_SUPPORT| |
1915 | FATTR4_WORD0_SYMLINK_SUPPORT| | 2269 | FATTR4_WORD0_SYMLINK_SUPPORT| |
@@ -1929,7 +2283,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client | |||
1929 | }; | 2283 | }; |
1930 | 2284 | ||
1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2285 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1932 | encode_compound_hdr(&xdr, &hdr); | 2286 | encode_compound_hdr(&xdr, req, &hdr); |
1933 | encode_renew(&xdr, clp, &hdr); | 2287 | encode_renew(&xdr, clp, &hdr); |
1934 | encode_nops(&hdr); | 2288 | encode_nops(&hdr); |
1935 | return 0; | 2289 | return 0; |
@@ -1946,7 +2300,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
1946 | }; | 2300 | }; |
1947 | 2301 | ||
1948 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2302 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1949 | encode_compound_hdr(&xdr, &hdr); | 2303 | encode_compound_hdr(&xdr, req, &hdr); |
1950 | encode_setclientid(&xdr, sc, &hdr); | 2304 | encode_setclientid(&xdr, sc, &hdr); |
1951 | encode_nops(&hdr); | 2305 | encode_nops(&hdr); |
1952 | return 0; | 2306 | return 0; |
@@ -1964,7 +2318,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
1964 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | 2318 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; |
1965 | 2319 | ||
1966 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2320 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1967 | encode_compound_hdr(&xdr, &hdr); | 2321 | encode_compound_hdr(&xdr, req, &hdr); |
1968 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2322 | encode_setclientid_confirm(&xdr, clp, &hdr); |
1969 | encode_putrootfh(&xdr, &hdr); | 2323 | encode_putrootfh(&xdr, &hdr); |
1970 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2324 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
@@ -1979,11 +2333,12 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc | |||
1979 | { | 2333 | { |
1980 | struct xdr_stream xdr; | 2334 | struct xdr_stream xdr; |
1981 | struct compound_hdr hdr = { | 2335 | struct compound_hdr hdr = { |
1982 | .nops = 0, | 2336 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1983 | }; | 2337 | }; |
1984 | 2338 | ||
1985 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2339 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1986 | encode_compound_hdr(&xdr, &hdr); | 2340 | encode_compound_hdr(&xdr, req, &hdr); |
2341 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1987 | encode_putfh(&xdr, args->fhandle, &hdr); | 2342 | encode_putfh(&xdr, args->fhandle, &hdr); |
1988 | encode_delegreturn(&xdr, args->stateid, &hdr); | 2343 | encode_delegreturn(&xdr, args->stateid, &hdr); |
1989 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2344 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1998,28 +2353,119 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1998 | { | 2353 | { |
1999 | struct xdr_stream xdr; | 2354 | struct xdr_stream xdr; |
2000 | struct compound_hdr hdr = { | 2355 | struct compound_hdr hdr = { |
2001 | .nops = 0, | 2356 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
2002 | }; | 2357 | }; |
2003 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 2358 | uint32_t replen; |
2004 | int replen; | ||
2005 | 2359 | ||
2006 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2360 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
2007 | encode_compound_hdr(&xdr, &hdr); | 2361 | encode_compound_hdr(&xdr, req, &hdr); |
2362 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2008 | encode_putfh(&xdr, args->dir_fh, &hdr); | 2363 | encode_putfh(&xdr, args->dir_fh, &hdr); |
2009 | encode_lookup(&xdr, args->name, &hdr); | 2364 | encode_lookup(&xdr, args->name, &hdr); |
2365 | replen = hdr.replen; /* get the attribute into args->page */ | ||
2010 | encode_fs_locations(&xdr, args->bitmask, &hdr); | 2366 | encode_fs_locations(&xdr, args->bitmask, &hdr); |
2011 | 2367 | ||
2012 | /* set up reply | 2368 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, |
2013 | * toplevel_status + OP_PUTFH + status | ||
2014 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 | ||
2015 | */ | ||
2016 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; | ||
2017 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, | ||
2018 | 0, PAGE_SIZE); | 2369 | 0, PAGE_SIZE); |
2019 | encode_nops(&hdr); | 2370 | encode_nops(&hdr); |
2020 | return 0; | 2371 | return 0; |
2021 | } | 2372 | } |
2022 | 2373 | ||
2374 | #if defined(CONFIG_NFS_V4_1) | ||
2375 | /* | ||
2376 | * EXCHANGE_ID request | ||
2377 | */ | ||
2378 | static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | ||
2379 | struct nfs41_exchange_id_args *args) | ||
2380 | { | ||
2381 | struct xdr_stream xdr; | ||
2382 | struct compound_hdr hdr = { | ||
2383 | .minorversion = args->client->cl_minorversion, | ||
2384 | }; | ||
2385 | |||
2386 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2387 | encode_compound_hdr(&xdr, req, &hdr); | ||
2388 | encode_exchange_id(&xdr, args, &hdr); | ||
2389 | encode_nops(&hdr); | ||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | /* | ||
2394 | * a CREATE_SESSION request | ||
2395 | */ | ||
2396 | static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | ||
2397 | struct nfs41_create_session_args *args) | ||
2398 | { | ||
2399 | struct xdr_stream xdr; | ||
2400 | struct compound_hdr hdr = { | ||
2401 | .minorversion = args->client->cl_minorversion, | ||
2402 | }; | ||
2403 | |||
2404 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2405 | encode_compound_hdr(&xdr, req, &hdr); | ||
2406 | encode_create_session(&xdr, args, &hdr); | ||
2407 | encode_nops(&hdr); | ||
2408 | return 0; | ||
2409 | } | ||
2410 | |||
2411 | /* | ||
2412 | * a DESTROY_SESSION request | ||
2413 | */ | ||
2414 | static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | ||
2415 | struct nfs4_session *session) | ||
2416 | { | ||
2417 | struct xdr_stream xdr; | ||
2418 | struct compound_hdr hdr = { | ||
2419 | .minorversion = session->clp->cl_minorversion, | ||
2420 | }; | ||
2421 | |||
2422 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2423 | encode_compound_hdr(&xdr, req, &hdr); | ||
2424 | encode_destroy_session(&xdr, session, &hdr); | ||
2425 | encode_nops(&hdr); | ||
2426 | return 0; | ||
2427 | } | ||
2428 | |||
2429 | /* | ||
2430 | * a SEQUENCE request | ||
2431 | */ | ||
2432 | static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p, | ||
2433 | struct nfs4_sequence_args *args) | ||
2434 | { | ||
2435 | struct xdr_stream xdr; | ||
2436 | struct compound_hdr hdr = { | ||
2437 | .minorversion = nfs4_xdr_minorversion(args), | ||
2438 | }; | ||
2439 | |||
2440 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2441 | encode_compound_hdr(&xdr, req, &hdr); | ||
2442 | encode_sequence(&xdr, args, &hdr); | ||
2443 | encode_nops(&hdr); | ||
2444 | return 0; | ||
2445 | } | ||
2446 | |||
2447 | /* | ||
2448 | * a GET_LEASE_TIME request | ||
2449 | */ | ||
2450 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | ||
2451 | struct nfs4_get_lease_time_args *args) | ||
2452 | { | ||
2453 | struct xdr_stream xdr; | ||
2454 | struct compound_hdr hdr = { | ||
2455 | .minorversion = nfs4_xdr_minorversion(&args->la_seq_args), | ||
2456 | }; | ||
2457 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | ||
2458 | |||
2459 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2460 | encode_compound_hdr(&xdr, req, &hdr); | ||
2461 | encode_sequence(&xdr, &args->la_seq_args, &hdr); | ||
2462 | encode_putrootfh(&xdr, &hdr); | ||
2463 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | ||
2464 | encode_nops(&hdr); | ||
2465 | return 0; | ||
2466 | } | ||
2467 | #endif /* CONFIG_NFS_V4_1 */ | ||
2468 | |||
2023 | /* | 2469 | /* |
2024 | * START OF "GENERIC" DECODE ROUTINES. | 2470 | * START OF "GENERIC" DECODE ROUTINES. |
2025 | * These may look a little ugly since they are imported from a "generic" | 2471 | * These may look a little ugly since they are imported from a "generic" |
@@ -3657,7 +4103,7 @@ decode_savefh(struct xdr_stream *xdr) | |||
3657 | return decode_op_hdr(xdr, OP_SAVEFH); | 4103 | return decode_op_hdr(xdr, OP_SAVEFH); |
3658 | } | 4104 | } |
3659 | 4105 | ||
3660 | static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | 4106 | static int decode_setattr(struct xdr_stream *xdr) |
3661 | { | 4107 | { |
3662 | __be32 *p; | 4108 | __be32 *p; |
3663 | uint32_t bmlen; | 4109 | uint32_t bmlen; |
@@ -3735,6 +4181,169 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
3735 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4181 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
3736 | } | 4182 | } |
3737 | 4183 | ||
4184 | #if defined(CONFIG_NFS_V4_1) | ||
4185 | static int decode_exchange_id(struct xdr_stream *xdr, | ||
4186 | struct nfs41_exchange_id_res *res) | ||
4187 | { | ||
4188 | __be32 *p; | ||
4189 | uint32_t dummy; | ||
4190 | int status; | ||
4191 | struct nfs_client *clp = res->client; | ||
4192 | |||
4193 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | ||
4194 | if (status) | ||
4195 | return status; | ||
4196 | |||
4197 | READ_BUF(8); | ||
4198 | READ64(clp->cl_ex_clid); | ||
4199 | READ_BUF(12); | ||
4200 | READ32(clp->cl_seqid); | ||
4201 | READ32(clp->cl_exchange_flags); | ||
4202 | |||
4203 | /* We ask for SP4_NONE */ | ||
4204 | READ32(dummy); | ||
4205 | if (dummy != SP4_NONE) | ||
4206 | return -EIO; | ||
4207 | |||
4208 | /* Throw away minor_id */ | ||
4209 | READ_BUF(8); | ||
4210 | |||
4211 | /* Throw away Major id */ | ||
4212 | READ_BUF(4); | ||
4213 | READ32(dummy); | ||
4214 | READ_BUF(dummy); | ||
4215 | |||
4216 | /* Throw away server_scope */ | ||
4217 | READ_BUF(4); | ||
4218 | READ32(dummy); | ||
4219 | READ_BUF(dummy); | ||
4220 | |||
4221 | /* Throw away Implementation id array */ | ||
4222 | READ_BUF(4); | ||
4223 | READ32(dummy); | ||
4224 | READ_BUF(dummy); | ||
4225 | |||
4226 | return 0; | ||
4227 | } | ||
4228 | |||
4229 | static int decode_chan_attrs(struct xdr_stream *xdr, | ||
4230 | struct nfs4_channel_attrs *attrs) | ||
4231 | { | ||
4232 | __be32 *p; | ||
4233 | u32 nr_attrs; | ||
4234 | |||
4235 | READ_BUF(28); | ||
4236 | READ32(attrs->headerpadsz); | ||
4237 | READ32(attrs->max_rqst_sz); | ||
4238 | READ32(attrs->max_resp_sz); | ||
4239 | READ32(attrs->max_resp_sz_cached); | ||
4240 | READ32(attrs->max_ops); | ||
4241 | READ32(attrs->max_reqs); | ||
4242 | READ32(nr_attrs); | ||
4243 | if (unlikely(nr_attrs > 1)) { | ||
4244 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | ||
4245 | __func__, nr_attrs); | ||
4246 | return -EINVAL; | ||
4247 | } | ||
4248 | if (nr_attrs == 1) | ||
4249 | READ_BUF(4); /* skip rdma_attrs */ | ||
4250 | return 0; | ||
4251 | } | ||
4252 | |||
4253 | static int decode_create_session(struct xdr_stream *xdr, | ||
4254 | struct nfs41_create_session_res *res) | ||
4255 | { | ||
4256 | __be32 *p; | ||
4257 | int status; | ||
4258 | struct nfs_client *clp = res->client; | ||
4259 | struct nfs4_session *session = clp->cl_session; | ||
4260 | |||
4261 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | ||
4262 | |||
4263 | if (status) | ||
4264 | return status; | ||
4265 | |||
4266 | /* sessionid */ | ||
4267 | READ_BUF(NFS4_MAX_SESSIONID_LEN); | ||
4268 | COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); | ||
4269 | |||
4270 | /* seqid, flags */ | ||
4271 | READ_BUF(8); | ||
4272 | READ32(clp->cl_seqid); | ||
4273 | READ32(session->flags); | ||
4274 | |||
4275 | /* Channel attributes */ | ||
4276 | status = decode_chan_attrs(xdr, &session->fc_attrs); | ||
4277 | if (!status) | ||
4278 | status = decode_chan_attrs(xdr, &session->bc_attrs); | ||
4279 | return status; | ||
4280 | } | ||
4281 | |||
4282 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | ||
4283 | { | ||
4284 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); | ||
4285 | } | ||
4286 | #endif /* CONFIG_NFS_V4_1 */ | ||
4287 | |||
4288 | static int decode_sequence(struct xdr_stream *xdr, | ||
4289 | struct nfs4_sequence_res *res, | ||
4290 | struct rpc_rqst *rqstp) | ||
4291 | { | ||
4292 | #if defined(CONFIG_NFS_V4_1) | ||
4293 | struct nfs4_slot *slot; | ||
4294 | struct nfs4_sessionid id; | ||
4295 | u32 dummy; | ||
4296 | int status; | ||
4297 | __be32 *p; | ||
4298 | |||
4299 | if (!res->sr_session) | ||
4300 | return 0; | ||
4301 | |||
4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); | ||
4303 | if (status) | ||
4304 | goto out_err; | ||
4305 | |||
4306 | /* | ||
4307 | * If the server returns different values for sessionID, slotID or | ||
4308 | * sequence number, the server is looney tunes. | ||
4309 | */ | ||
4310 | status = -ESERVERFAULT; | ||
4311 | |||
4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | ||
4316 | NFS4_MAX_SESSIONID_LEN)) { | ||
4317 | dprintk("%s Invalid session id\n", __func__); | ||
4318 | goto out_err; | ||
4319 | } | ||
4320 | /* seqid */ | ||
4321 | READ32(dummy); | ||
4322 | if (dummy != slot->seq_nr) { | ||
4323 | dprintk("%s Invalid sequence number\n", __func__); | ||
4324 | goto out_err; | ||
4325 | } | ||
4326 | /* slot id */ | ||
4327 | READ32(dummy); | ||
4328 | if (dummy != res->sr_slotid) { | ||
4329 | dprintk("%s Invalid slot id\n", __func__); | ||
4330 | goto out_err; | ||
4331 | } | ||
4332 | /* highest slot id - currently not processed */ | ||
4333 | READ32(dummy); | ||
4334 | /* target highest slot id - currently not processed */ | ||
4335 | READ32(dummy); | ||
4336 | /* result flags - currently not processed */ | ||
4337 | READ32(dummy); | ||
4338 | status = 0; | ||
4339 | out_err: | ||
4340 | res->sr_status = status; | ||
4341 | return status; | ||
4342 | #else /* CONFIG_NFS_V4_1 */ | ||
4343 | return 0; | ||
4344 | #endif /* CONFIG_NFS_V4_1 */ | ||
4345 | } | ||
4346 | |||
3738 | /* | 4347 | /* |
3739 | * END OF "GENERIC" DECODE ROUTINES. | 4348 | * END OF "GENERIC" DECODE ROUTINES. |
3740 | */ | 4349 | */ |
@@ -3752,6 +4361,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
3752 | status = decode_compound_hdr(&xdr, &hdr); | 4361 | status = decode_compound_hdr(&xdr, &hdr); |
3753 | if (status) | 4362 | if (status) |
3754 | goto out; | 4363 | goto out; |
4364 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4365 | if (status) | ||
4366 | goto out; | ||
3755 | status = decode_putfh(&xdr); | 4367 | status = decode_putfh(&xdr); |
3756 | if (status) | 4368 | if (status) |
3757 | goto out; | 4369 | goto out; |
@@ -3773,7 +4385,11 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
3773 | int status; | 4385 | int status; |
3774 | 4386 | ||
3775 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4387 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3776 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4388 | status = decode_compound_hdr(&xdr, &hdr); |
4389 | if (status) | ||
4390 | goto out; | ||
4391 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4392 | if (status) | ||
3777 | goto out; | 4393 | goto out; |
3778 | status = decode_putfh(&xdr); | 4394 | status = decode_putfh(&xdr); |
3779 | if (status != 0) | 4395 | if (status != 0) |
@@ -3796,7 +4412,11 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
3796 | int status; | 4412 | int status; |
3797 | 4413 | ||
3798 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4414 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3799 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4415 | status = decode_compound_hdr(&xdr, &hdr); |
4416 | if (status) | ||
4417 | goto out; | ||
4418 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4419 | if (status) | ||
3800 | goto out; | 4420 | goto out; |
3801 | if ((status = decode_putfh(&xdr)) != 0) | 4421 | if ((status = decode_putfh(&xdr)) != 0) |
3802 | goto out; | 4422 | goto out; |
@@ -3819,7 +4439,11 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
3819 | int status; | 4439 | int status; |
3820 | 4440 | ||
3821 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4441 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3822 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4442 | status = decode_compound_hdr(&xdr, &hdr); |
4443 | if (status) | ||
4444 | goto out; | ||
4445 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4446 | if (status) | ||
3823 | goto out; | 4447 | goto out; |
3824 | if ((status = decode_putrootfh(&xdr)) != 0) | 4448 | if ((status = decode_putrootfh(&xdr)) != 0) |
3825 | goto out; | 4449 | goto out; |
@@ -3839,7 +4463,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
3839 | int status; | 4463 | int status; |
3840 | 4464 | ||
3841 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4465 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3842 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4466 | status = decode_compound_hdr(&xdr, &hdr); |
4467 | if (status) | ||
4468 | goto out; | ||
4469 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4470 | if (status) | ||
3843 | goto out; | 4471 | goto out; |
3844 | if ((status = decode_putfh(&xdr)) != 0) | 4472 | if ((status = decode_putfh(&xdr)) != 0) |
3845 | goto out; | 4473 | goto out; |
@@ -3860,7 +4488,11 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
3860 | int status; | 4488 | int status; |
3861 | 4489 | ||
3862 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4490 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3863 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4491 | status = decode_compound_hdr(&xdr, &hdr); |
4492 | if (status) | ||
4493 | goto out; | ||
4494 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4495 | if (status) | ||
3864 | goto out; | 4496 | goto out; |
3865 | if ((status = decode_putfh(&xdr)) != 0) | 4497 | if ((status = decode_putfh(&xdr)) != 0) |
3866 | goto out; | 4498 | goto out; |
@@ -3890,7 +4522,11 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
3890 | int status; | 4522 | int status; |
3891 | 4523 | ||
3892 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4524 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3893 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4525 | status = decode_compound_hdr(&xdr, &hdr); |
4526 | if (status) | ||
4527 | goto out; | ||
4528 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4529 | if (status) | ||
3894 | goto out; | 4530 | goto out; |
3895 | if ((status = decode_putfh(&xdr)) != 0) | 4531 | if ((status = decode_putfh(&xdr)) != 0) |
3896 | goto out; | 4532 | goto out; |
@@ -3923,7 +4559,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
3923 | int status; | 4559 | int status; |
3924 | 4560 | ||
3925 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4561 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3926 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4562 | status = decode_compound_hdr(&xdr, &hdr); |
4563 | if (status) | ||
4564 | goto out; | ||
4565 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4566 | if (status) | ||
3927 | goto out; | 4567 | goto out; |
3928 | if ((status = decode_putfh(&xdr)) != 0) | 4568 | if ((status = decode_putfh(&xdr)) != 0) |
3929 | goto out; | 4569 | goto out; |
@@ -3963,6 +4603,9 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
3963 | status = decode_compound_hdr(&xdr, &hdr); | 4603 | status = decode_compound_hdr(&xdr, &hdr); |
3964 | if (status) | 4604 | if (status) |
3965 | goto out; | 4605 | goto out; |
4606 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4607 | if (status) | ||
4608 | goto out; | ||
3966 | status = decode_putfh(&xdr); | 4609 | status = decode_putfh(&xdr); |
3967 | if (status) | 4610 | if (status) |
3968 | goto out; | 4611 | goto out; |
@@ -3979,12 +4622,13 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3979 | { | 4622 | { |
3980 | struct xdr_stream xdr; | 4623 | struct xdr_stream xdr; |
3981 | struct compound_hdr hdr = { | 4624 | struct compound_hdr hdr = { |
3982 | .nops = 0, | 4625 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
3983 | }; | 4626 | }; |
3984 | int status; | 4627 | int status; |
3985 | 4628 | ||
3986 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 4629 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
3987 | encode_compound_hdr(&xdr, &hdr); | 4630 | encode_compound_hdr(&xdr, req, &hdr); |
4631 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
3988 | encode_putfh(&xdr, args->fh, &hdr); | 4632 | encode_putfh(&xdr, args->fh, &hdr); |
3989 | status = encode_setacl(&xdr, args, &hdr); | 4633 | status = encode_setacl(&xdr, args, &hdr); |
3990 | encode_nops(&hdr); | 4634 | encode_nops(&hdr); |
@@ -3995,7 +4639,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3995 | * Decode SETACL response | 4639 | * Decode SETACL response |
3996 | */ | 4640 | */ |
3997 | static int | 4641 | static int |
3998 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4642 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, |
4643 | struct nfs_setaclres *res) | ||
3999 | { | 4644 | { |
4000 | struct xdr_stream xdr; | 4645 | struct xdr_stream xdr; |
4001 | struct compound_hdr hdr; | 4646 | struct compound_hdr hdr; |
@@ -4005,10 +4650,13 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4005 | status = decode_compound_hdr(&xdr, &hdr); | 4650 | status = decode_compound_hdr(&xdr, &hdr); |
4006 | if (status) | 4651 | if (status) |
4007 | goto out; | 4652 | goto out; |
4653 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4654 | if (status) | ||
4655 | goto out; | ||
4008 | status = decode_putfh(&xdr); | 4656 | status = decode_putfh(&xdr); |
4009 | if (status) | 4657 | if (status) |
4010 | goto out; | 4658 | goto out; |
4011 | status = decode_setattr(&xdr, res); | 4659 | status = decode_setattr(&xdr); |
4012 | out: | 4660 | out: |
4013 | return status; | 4661 | return status; |
4014 | } | 4662 | } |
@@ -4017,7 +4665,8 @@ out: | |||
4017 | * Decode GETACL response | 4665 | * Decode GETACL response |
4018 | */ | 4666 | */ |
4019 | static int | 4667 | static int |
4020 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | 4668 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, |
4669 | struct nfs_getaclres *res) | ||
4021 | { | 4670 | { |
4022 | struct xdr_stream xdr; | 4671 | struct xdr_stream xdr; |
4023 | struct compound_hdr hdr; | 4672 | struct compound_hdr hdr; |
@@ -4027,10 +4676,13 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | |||
4027 | status = decode_compound_hdr(&xdr, &hdr); | 4676 | status = decode_compound_hdr(&xdr, &hdr); |
4028 | if (status) | 4677 | if (status) |
4029 | goto out; | 4678 | goto out; |
4679 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4680 | if (status) | ||
4681 | goto out; | ||
4030 | status = decode_putfh(&xdr); | 4682 | status = decode_putfh(&xdr); |
4031 | if (status) | 4683 | if (status) |
4032 | goto out; | 4684 | goto out; |
4033 | status = decode_getacl(&xdr, rqstp, acl_len); | 4685 | status = decode_getacl(&xdr, rqstp, &res->acl_len); |
4034 | 4686 | ||
4035 | out: | 4687 | out: |
4036 | return status; | 4688 | return status; |
@@ -4049,6 +4701,9 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
4049 | status = decode_compound_hdr(&xdr, &hdr); | 4701 | status = decode_compound_hdr(&xdr, &hdr); |
4050 | if (status) | 4702 | if (status) |
4051 | goto out; | 4703 | goto out; |
4704 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4705 | if (status) | ||
4706 | goto out; | ||
4052 | status = decode_putfh(&xdr); | 4707 | status = decode_putfh(&xdr); |
4053 | if (status) | 4708 | if (status) |
4054 | goto out; | 4709 | goto out; |
@@ -4079,6 +4734,9 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
4079 | status = decode_compound_hdr(&xdr, &hdr); | 4734 | status = decode_compound_hdr(&xdr, &hdr); |
4080 | if (status) | 4735 | if (status) |
4081 | goto out; | 4736 | goto out; |
4737 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4738 | if (status) | ||
4739 | goto out; | ||
4082 | status = decode_putfh(&xdr); | 4740 | status = decode_putfh(&xdr); |
4083 | if (status) | 4741 | if (status) |
4084 | goto out; | 4742 | goto out; |
@@ -4133,6 +4791,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4133 | status = decode_compound_hdr(&xdr, &hdr); | 4791 | status = decode_compound_hdr(&xdr, &hdr); |
4134 | if (status) | 4792 | if (status) |
4135 | goto out; | 4793 | goto out; |
4794 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4795 | if (status) | ||
4796 | goto out; | ||
4136 | status = decode_putfh(&xdr); | 4797 | status = decode_putfh(&xdr); |
4137 | if (status) | 4798 | if (status) |
4138 | goto out; | 4799 | goto out; |
@@ -4157,10 +4818,13 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
4157 | status = decode_compound_hdr(&xdr, &hdr); | 4818 | status = decode_compound_hdr(&xdr, &hdr); |
4158 | if (status) | 4819 | if (status) |
4159 | goto out; | 4820 | goto out; |
4821 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4822 | if (status) | ||
4823 | goto out; | ||
4160 | status = decode_putfh(&xdr); | 4824 | status = decode_putfh(&xdr); |
4161 | if (status) | 4825 | if (status) |
4162 | goto out; | 4826 | goto out; |
4163 | status = decode_setattr(&xdr, res); | 4827 | status = decode_setattr(&xdr); |
4164 | if (status) | 4828 | if (status) |
4165 | goto out; | 4829 | goto out; |
4166 | decode_getfattr(&xdr, res->fattr, res->server); | 4830 | decode_getfattr(&xdr, res->fattr, res->server); |
@@ -4181,6 +4845,9 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_ | |||
4181 | status = decode_compound_hdr(&xdr, &hdr); | 4845 | status = decode_compound_hdr(&xdr, &hdr); |
4182 | if (status) | 4846 | if (status) |
4183 | goto out; | 4847 | goto out; |
4848 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4849 | if (status) | ||
4850 | goto out; | ||
4184 | status = decode_putfh(&xdr); | 4851 | status = decode_putfh(&xdr); |
4185 | if (status) | 4852 | if (status) |
4186 | goto out; | 4853 | goto out; |
@@ -4202,6 +4869,9 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4202 | status = decode_compound_hdr(&xdr, &hdr); | 4869 | status = decode_compound_hdr(&xdr, &hdr); |
4203 | if (status) | 4870 | if (status) |
4204 | goto out; | 4871 | goto out; |
4872 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4873 | if (status) | ||
4874 | goto out; | ||
4205 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
4206 | if (status) | 4876 | if (status) |
4207 | goto out; | 4877 | goto out; |
@@ -4223,6 +4893,9 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4223 | status = decode_compound_hdr(&xdr, &hdr); | 4893 | status = decode_compound_hdr(&xdr, &hdr); |
4224 | if (status) | 4894 | if (status) |
4225 | goto out; | 4895 | goto out; |
4896 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4897 | if (status) | ||
4898 | goto out; | ||
4226 | status = decode_putfh(&xdr); | 4899 | status = decode_putfh(&xdr); |
4227 | if (status) | 4900 | if (status) |
4228 | goto out; | 4901 | goto out; |
@@ -4234,7 +4907,8 @@ out: | |||
4234 | /* | 4907 | /* |
4235 | * Decode READLINK response | 4908 | * Decode READLINK response |
4236 | */ | 4909 | */ |
4237 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4910 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, |
4911 | struct nfs4_readlink_res *res) | ||
4238 | { | 4912 | { |
4239 | struct xdr_stream xdr; | 4913 | struct xdr_stream xdr; |
4240 | struct compound_hdr hdr; | 4914 | struct compound_hdr hdr; |
@@ -4244,6 +4918,9 @@ static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4244 | status = decode_compound_hdr(&xdr, &hdr); | 4918 | status = decode_compound_hdr(&xdr, &hdr); |
4245 | if (status) | 4919 | if (status) |
4246 | goto out; | 4920 | goto out; |
4921 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4922 | if (status) | ||
4923 | goto out; | ||
4247 | status = decode_putfh(&xdr); | 4924 | status = decode_putfh(&xdr); |
4248 | if (status) | 4925 | if (status) |
4249 | goto out; | 4926 | goto out; |
@@ -4265,6 +4942,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_r | |||
4265 | status = decode_compound_hdr(&xdr, &hdr); | 4942 | status = decode_compound_hdr(&xdr, &hdr); |
4266 | if (status) | 4943 | if (status) |
4267 | goto out; | 4944 | goto out; |
4945 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4946 | if (status) | ||
4947 | goto out; | ||
4268 | status = decode_putfh(&xdr); | 4948 | status = decode_putfh(&xdr); |
4269 | if (status) | 4949 | if (status) |
4270 | goto out; | 4950 | goto out; |
@@ -4286,6 +4966,9 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readr | |||
4286 | status = decode_compound_hdr(&xdr, &hdr); | 4966 | status = decode_compound_hdr(&xdr, &hdr); |
4287 | if (status) | 4967 | if (status) |
4288 | goto out; | 4968 | goto out; |
4969 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4970 | if (status) | ||
4971 | goto out; | ||
4289 | status = decode_putfh(&xdr); | 4972 | status = decode_putfh(&xdr); |
4290 | if (status) | 4973 | if (status) |
4291 | goto out; | 4974 | goto out; |
@@ -4309,6 +4992,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
4309 | status = decode_compound_hdr(&xdr, &hdr); | 4992 | status = decode_compound_hdr(&xdr, &hdr); |
4310 | if (status) | 4993 | if (status) |
4311 | goto out; | 4994 | goto out; |
4995 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4996 | if (status) | ||
4997 | goto out; | ||
4312 | status = decode_putfh(&xdr); | 4998 | status = decode_putfh(&xdr); |
4313 | if (status) | 4999 | if (status) |
4314 | goto out; | 5000 | goto out; |
@@ -4335,6 +5021,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
4335 | status = decode_compound_hdr(&xdr, &hdr); | 5021 | status = decode_compound_hdr(&xdr, &hdr); |
4336 | if (status) | 5022 | if (status) |
4337 | goto out; | 5023 | goto out; |
5024 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5025 | if (status) | ||
5026 | goto out; | ||
4338 | status = decode_putfh(&xdr); | 5027 | status = decode_putfh(&xdr); |
4339 | if (status) | 5028 | if (status) |
4340 | goto out; | 5029 | goto out; |
@@ -4349,7 +5038,8 @@ out: | |||
4349 | /* | 5038 | /* |
4350 | * FSINFO request | 5039 | * FSINFO request |
4351 | */ | 5040 | */ |
4352 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) | 5041 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, |
5042 | struct nfs4_fsinfo_res *res) | ||
4353 | { | 5043 | { |
4354 | struct xdr_stream xdr; | 5044 | struct xdr_stream xdr; |
4355 | struct compound_hdr hdr; | 5045 | struct compound_hdr hdr; |
@@ -4358,16 +5048,19 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4358 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5048 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4359 | status = decode_compound_hdr(&xdr, &hdr); | 5049 | status = decode_compound_hdr(&xdr, &hdr); |
4360 | if (!status) | 5050 | if (!status) |
5051 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5052 | if (!status) | ||
4361 | status = decode_putfh(&xdr); | 5053 | status = decode_putfh(&xdr); |
4362 | if (!status) | 5054 | if (!status) |
4363 | status = decode_fsinfo(&xdr, fsinfo); | 5055 | status = decode_fsinfo(&xdr, res->fsinfo); |
4364 | return status; | 5056 | return status; |
4365 | } | 5057 | } |
4366 | 5058 | ||
4367 | /* | 5059 | /* |
4368 | * PATHCONF request | 5060 | * PATHCONF request |
4369 | */ | 5061 | */ |
4370 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf) | 5062 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, |
5063 | struct nfs4_pathconf_res *res) | ||
4371 | { | 5064 | { |
4372 | struct xdr_stream xdr; | 5065 | struct xdr_stream xdr; |
4373 | struct compound_hdr hdr; | 5066 | struct compound_hdr hdr; |
@@ -4376,16 +5069,19 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat | |||
4376 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5069 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4377 | status = decode_compound_hdr(&xdr, &hdr); | 5070 | status = decode_compound_hdr(&xdr, &hdr); |
4378 | if (!status) | 5071 | if (!status) |
5072 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5073 | if (!status) | ||
4379 | status = decode_putfh(&xdr); | 5074 | status = decode_putfh(&xdr); |
4380 | if (!status) | 5075 | if (!status) |
4381 | status = decode_pathconf(&xdr, pathconf); | 5076 | status = decode_pathconf(&xdr, res->pathconf); |
4382 | return status; | 5077 | return status; |
4383 | } | 5078 | } |
4384 | 5079 | ||
4385 | /* | 5080 | /* |
4386 | * STATFS request | 5081 | * STATFS request |
4387 | */ | 5082 | */ |
4388 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat) | 5083 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, |
5084 | struct nfs4_statfs_res *res) | ||
4389 | { | 5085 | { |
4390 | struct xdr_stream xdr; | 5086 | struct xdr_stream xdr; |
4391 | struct compound_hdr hdr; | 5087 | struct compound_hdr hdr; |
@@ -4394,9 +5090,11 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta | |||
4394 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5090 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4395 | status = decode_compound_hdr(&xdr, &hdr); | 5091 | status = decode_compound_hdr(&xdr, &hdr); |
4396 | if (!status) | 5092 | if (!status) |
5093 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5094 | if (!status) | ||
4397 | status = decode_putfh(&xdr); | 5095 | status = decode_putfh(&xdr); |
4398 | if (!status) | 5096 | if (!status) |
4399 | status = decode_statfs(&xdr, fsstat); | 5097 | status = decode_statfs(&xdr, res->fsstat); |
4400 | return status; | 5098 | return status; |
4401 | } | 5099 | } |
4402 | 5100 | ||
@@ -4410,7 +5108,11 @@ static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
4410 | int status; | 5108 | int status; |
4411 | 5109 | ||
4412 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5110 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4413 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 5111 | status = decode_compound_hdr(&xdr, &hdr); |
5112 | if (status) | ||
5113 | goto out; | ||
5114 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5115 | if (status) | ||
4414 | goto out; | 5116 | goto out; |
4415 | if ((status = decode_putfh(&xdr)) != 0) | 5117 | if ((status = decode_putfh(&xdr)) != 0) |
4416 | goto out; | 5118 | goto out; |
@@ -4483,7 +5185,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4483 | 5185 | ||
4484 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 5186 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
4485 | status = decode_compound_hdr(&xdr, &hdr); | 5187 | status = decode_compound_hdr(&xdr, &hdr); |
4486 | if (status != 0) | 5188 | if (status) |
5189 | goto out; | ||
5190 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5191 | if (status) | ||
4487 | goto out; | 5192 | goto out; |
4488 | status = decode_putfh(&xdr); | 5193 | status = decode_putfh(&xdr); |
4489 | if (status != 0) | 5194 | if (status != 0) |
@@ -4497,7 +5202,8 @@ out: | |||
4497 | /* | 5202 | /* |
4498 | * FS_LOCATIONS request | 5203 | * FS_LOCATIONS request |
4499 | */ | 5204 | */ |
4500 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res) | 5205 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, |
5206 | struct nfs4_fs_locations_res *res) | ||
4501 | { | 5207 | { |
4502 | struct xdr_stream xdr; | 5208 | struct xdr_stream xdr; |
4503 | struct compound_hdr hdr; | 5209 | struct compound_hdr hdr; |
@@ -4505,18 +5211,113 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
4505 | 5211 | ||
4506 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5212 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4507 | status = decode_compound_hdr(&xdr, &hdr); | 5213 | status = decode_compound_hdr(&xdr, &hdr); |
4508 | if (status != 0) | 5214 | if (status) |
5215 | goto out; | ||
5216 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5217 | if (status) | ||
4509 | goto out; | 5218 | goto out; |
4510 | if ((status = decode_putfh(&xdr)) != 0) | 5219 | if ((status = decode_putfh(&xdr)) != 0) |
4511 | goto out; | 5220 | goto out; |
4512 | if ((status = decode_lookup(&xdr)) != 0) | 5221 | if ((status = decode_lookup(&xdr)) != 0) |
4513 | goto out; | 5222 | goto out; |
4514 | xdr_enter_page(&xdr, PAGE_SIZE); | 5223 | xdr_enter_page(&xdr, PAGE_SIZE); |
4515 | status = decode_getfattr(&xdr, &res->fattr, res->server); | 5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
5225 | res->fs_locations->server); | ||
4516 | out: | 5226 | out: |
4517 | return status; | 5227 | return status; |
4518 | } | 5228 | } |
4519 | 5229 | ||
5230 | #if defined(CONFIG_NFS_V4_1) | ||
5231 | /* | ||
5232 | * EXCHANGE_ID request | ||
5233 | */ | ||
5234 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | ||
5235 | void *res) | ||
5236 | { | ||
5237 | struct xdr_stream xdr; | ||
5238 | struct compound_hdr hdr; | ||
5239 | int status; | ||
5240 | |||
5241 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5242 | status = decode_compound_hdr(&xdr, &hdr); | ||
5243 | if (!status) | ||
5244 | status = decode_exchange_id(&xdr, res); | ||
5245 | return status; | ||
5246 | } | ||
5247 | |||
5248 | /* | ||
5249 | * a CREATE_SESSION request | ||
5250 | */ | ||
5251 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5252 | struct nfs41_create_session_res *res) | ||
5253 | { | ||
5254 | struct xdr_stream xdr; | ||
5255 | struct compound_hdr hdr; | ||
5256 | int status; | ||
5257 | |||
5258 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5259 | status = decode_compound_hdr(&xdr, &hdr); | ||
5260 | if (!status) | ||
5261 | status = decode_create_session(&xdr, res); | ||
5262 | return status; | ||
5263 | } | ||
5264 | |||
5265 | /* | ||
5266 | * a DESTROY_SESSION request | ||
5267 | */ | ||
5268 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5269 | void *dummy) | ||
5270 | { | ||
5271 | struct xdr_stream xdr; | ||
5272 | struct compound_hdr hdr; | ||
5273 | int status; | ||
5274 | |||
5275 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5276 | status = decode_compound_hdr(&xdr, &hdr); | ||
5277 | if (!status) | ||
5278 | status = decode_destroy_session(&xdr, dummy); | ||
5279 | return status; | ||
5280 | } | ||
5281 | |||
5282 | /* | ||
5283 | * a SEQUENCE request | ||
5284 | */ | ||
5285 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | ||
5286 | struct nfs4_sequence_res *res) | ||
5287 | { | ||
5288 | struct xdr_stream xdr; | ||
5289 | struct compound_hdr hdr; | ||
5290 | int status; | ||
5291 | |||
5292 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5293 | status = decode_compound_hdr(&xdr, &hdr); | ||
5294 | if (!status) | ||
5295 | status = decode_sequence(&xdr, res, rqstp); | ||
5296 | return status; | ||
5297 | } | ||
5298 | |||
5299 | /* | ||
5300 | * a GET_LEASE_TIME request | ||
5301 | */ | ||
5302 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | ||
5303 | struct nfs4_get_lease_time_res *res) | ||
5304 | { | ||
5305 | struct xdr_stream xdr; | ||
5306 | struct compound_hdr hdr; | ||
5307 | int status; | ||
5308 | |||
5309 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5310 | status = decode_compound_hdr(&xdr, &hdr); | ||
5311 | if (!status) | ||
5312 | status = decode_sequence(&xdr, &res->lr_seq_res, rqstp); | ||
5313 | if (!status) | ||
5314 | status = decode_putrootfh(&xdr); | ||
5315 | if (!status) | ||
5316 | status = decode_fsinfo(&xdr, res->lr_fsinfo); | ||
5317 | return status; | ||
5318 | } | ||
5319 | #endif /* CONFIG_NFS_V4_1 */ | ||
5320 | |||
4520 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5321 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
4521 | { | 5322 | { |
4522 | uint32_t bitmap[2] = {0}; | 5323 | uint32_t bitmap[2] = {0}; |
@@ -4686,6 +5487,13 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4686 | PROC(GETACL, enc_getacl, dec_getacl), | 5487 | PROC(GETACL, enc_getacl, dec_getacl), |
4687 | PROC(SETACL, enc_setacl, dec_setacl), | 5488 | PROC(SETACL, enc_setacl, dec_setacl), |
4688 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5489 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
5490 | #if defined(CONFIG_NFS_V4_1) | ||
5491 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | ||
5492 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | ||
5493 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | ||
5494 | PROC(SEQUENCE, enc_sequence, dec_sequence), | ||
5495 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | ||
5496 | #endif /* CONFIG_NFS_V4_1 */ | ||
4689 | }; | 5497 | }; |
4690 | 5498 | ||
4691 | struct rpc_version nfs_version4 = { | 5499 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e3ed5908820b..8c55b27c0de4 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -92,6 +92,9 @@ | |||
92 | #undef NFSROOT_DEBUG | 92 | #undef NFSROOT_DEBUG |
93 | #define NFSDBG_FACILITY NFSDBG_ROOT | 93 | #define NFSDBG_FACILITY NFSDBG_ROOT |
94 | 94 | ||
95 | /* Default port to use if server is not running a portmapper */ | ||
96 | #define NFS_MNT_PORT 627 | ||
97 | |||
95 | /* Default path we try to mount. "%s" gets replaced by our IP address */ | 98 | /* Default path we try to mount. "%s" gets replaced by our IP address */ |
96 | #define NFS_ROOT "/tftpboot/%s" | 99 | #define NFS_ROOT "/tftpboot/%s" |
97 | 100 | ||
@@ -487,6 +490,7 @@ static int __init root_nfs_get_handle(void) | |||
487 | { | 490 | { |
488 | struct nfs_fh fh; | 491 | struct nfs_fh fh; |
489 | struct sockaddr_in sin; | 492 | struct sockaddr_in sin; |
493 | unsigned int auth_flav_len = 0; | ||
490 | struct nfs_mount_request request = { | 494 | struct nfs_mount_request request = { |
491 | .sap = (struct sockaddr *)&sin, | 495 | .sap = (struct sockaddr *)&sin, |
492 | .salen = sizeof(sin), | 496 | .salen = sizeof(sin), |
@@ -496,6 +500,7 @@ static int __init root_nfs_get_handle(void) | |||
496 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? | 500 | .protocol = (nfs_data.flags & NFS_MOUNT_TCP) ? |
497 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, | 501 | XPRT_TRANSPORT_TCP : XPRT_TRANSPORT_UDP, |
498 | .fh = &fh, | 502 | .fh = &fh, |
503 | .auth_flav_len = &auth_flav_len, | ||
499 | }; | 504 | }; |
500 | int status; | 505 | int status; |
501 | 506 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4ace3c50a8eb..12c9e66d3f1d 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -18,10 +18,10 @@ | |||
18 | #include <linux/sunrpc/clnt.h> | 18 | #include <linux/sunrpc/clnt.h> |
19 | #include <linux/nfs_fs.h> | 19 | #include <linux/nfs_fs.h> |
20 | #include <linux/nfs_page.h> | 20 | #include <linux/nfs_page.h> |
21 | #include <linux/smp_lock.h> | ||
22 | 21 | ||
23 | #include <asm/system.h> | 22 | #include <asm/system.h> |
24 | 23 | ||
24 | #include "nfs4_fs.h" | ||
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | #include "iostat.h" | 26 | #include "iostat.h" |
27 | #include "fscache.h" | 27 | #include "fscache.h" |
@@ -46,6 +46,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
46 | memset(p, 0, sizeof(*p)); | 46 | memset(p, 0, sizeof(*p)); |
47 | INIT_LIST_HEAD(&p->pages); | 47 | INIT_LIST_HEAD(&p->pages); |
48 | p->npages = pagecount; | 48 | p->npages = pagecount; |
49 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
49 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 50 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
50 | p->pagevec = p->page_array; | 51 | p->pagevec = p->page_array; |
51 | else { | 52 | else { |
@@ -59,17 +60,15 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
59 | return p; | 60 | return p; |
60 | } | 61 | } |
61 | 62 | ||
62 | static void nfs_readdata_free(struct nfs_read_data *p) | 63 | void nfs_readdata_free(struct nfs_read_data *p) |
63 | { | 64 | { |
64 | if (p && (p->pagevec != &p->page_array[0])) | 65 | if (p && (p->pagevec != &p->page_array[0])) |
65 | kfree(p->pagevec); | 66 | kfree(p->pagevec); |
66 | mempool_free(p, nfs_rdata_mempool); | 67 | mempool_free(p, nfs_rdata_mempool); |
67 | } | 68 | } |
68 | 69 | ||
69 | void nfs_readdata_release(void *data) | 70 | static void nfs_readdata_release(struct nfs_read_data *rdata) |
70 | { | 71 | { |
71 | struct nfs_read_data *rdata = data; | ||
72 | |||
73 | put_nfs_open_context(rdata->args.context); | 72 | put_nfs_open_context(rdata->args.context); |
74 | nfs_readdata_free(rdata); | 73 | nfs_readdata_free(rdata); |
75 | } | 74 | } |
@@ -357,19 +356,25 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
357 | struct nfs_readres *resp = &data->res; | 356 | struct nfs_readres *resp = &data->res; |
358 | 357 | ||
359 | if (resp->eof || resp->count == argp->count) | 358 | if (resp->eof || resp->count == argp->count) |
360 | return; | 359 | goto out; |
361 | 360 | ||
362 | /* This is a short read! */ | 361 | /* This is a short read! */ |
363 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 362 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
364 | /* Has the server at least made some progress? */ | 363 | /* Has the server at least made some progress? */ |
365 | if (resp->count == 0) | 364 | if (resp->count == 0) |
366 | return; | 365 | goto out; |
367 | 366 | ||
368 | /* Yes, so retry the read at the end of the data */ | 367 | /* Yes, so retry the read at the end of the data */ |
369 | argp->offset += resp->count; | 368 | argp->offset += resp->count; |
370 | argp->pgbase += resp->count; | 369 | argp->pgbase += resp->count; |
371 | argp->count -= resp->count; | 370 | argp->count -= resp->count; |
372 | rpc_restart_call(task); | 371 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); |
372 | return; | ||
373 | out: | ||
374 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | ||
375 | &data->res.seq_res); | ||
376 | return; | ||
377 | |||
373 | } | 378 | } |
374 | 379 | ||
375 | /* | 380 | /* |
@@ -406,7 +411,23 @@ static void nfs_readpage_release_partial(void *calldata) | |||
406 | nfs_readdata_release(calldata); | 411 | nfs_readdata_release(calldata); |
407 | } | 412 | } |
408 | 413 | ||
414 | #if defined(CONFIG_NFS_V4_1) | ||
415 | void nfs_read_prepare(struct rpc_task *task, void *calldata) | ||
416 | { | ||
417 | struct nfs_read_data *data = calldata; | ||
418 | |||
419 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | ||
420 | &data->args.seq_args, &data->res.seq_res, | ||
421 | 0, task)) | ||
422 | return; | ||
423 | rpc_call_start(task); | ||
424 | } | ||
425 | #endif /* CONFIG_NFS_V4_1 */ | ||
426 | |||
409 | static const struct rpc_call_ops nfs_read_partial_ops = { | 427 | static const struct rpc_call_ops nfs_read_partial_ops = { |
428 | #if defined(CONFIG_NFS_V4_1) | ||
429 | .rpc_call_prepare = nfs_read_prepare, | ||
430 | #endif /* CONFIG_NFS_V4_1 */ | ||
410 | .rpc_call_done = nfs_readpage_result_partial, | 431 | .rpc_call_done = nfs_readpage_result_partial, |
411 | .rpc_release = nfs_readpage_release_partial, | 432 | .rpc_release = nfs_readpage_release_partial, |
412 | }; | 433 | }; |
@@ -470,6 +491,9 @@ static void nfs_readpage_release_full(void *calldata) | |||
470 | } | 491 | } |
471 | 492 | ||
472 | static const struct rpc_call_ops nfs_read_full_ops = { | 493 | static const struct rpc_call_ops nfs_read_full_ops = { |
494 | #if defined(CONFIG_NFS_V4_1) | ||
495 | .rpc_call_prepare = nfs_read_prepare, | ||
496 | #endif /* CONFIG_NFS_V4_1 */ | ||
473 | .rpc_call_done = nfs_readpage_result_full, | 497 | .rpc_call_done = nfs_readpage_result_full, |
474 | .rpc_release = nfs_readpage_release_full, | 498 | .rpc_release = nfs_readpage_release_full, |
475 | }; | 499 | }; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 26127b69a275..0b4cbdc60abd 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -42,6 +42,8 @@ | |||
42 | #include <linux/smp_lock.h> | 42 | #include <linux/smp_lock.h> |
43 | #include <linux/seq_file.h> | 43 | #include <linux/seq_file.h> |
44 | #include <linux/mount.h> | 44 | #include <linux/mount.h> |
45 | #include <linux/mnt_namespace.h> | ||
46 | #include <linux/namei.h> | ||
45 | #include <linux/nfs_idmap.h> | 47 | #include <linux/nfs_idmap.h> |
46 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
47 | #include <linux/inet.h> | 49 | #include <linux/inet.h> |
@@ -90,6 +92,7 @@ enum { | |||
90 | Opt_mountport, | 92 | Opt_mountport, |
91 | Opt_mountvers, | 93 | Opt_mountvers, |
92 | Opt_nfsvers, | 94 | Opt_nfsvers, |
95 | Opt_minorversion, | ||
93 | 96 | ||
94 | /* Mount options that take string arguments */ | 97 | /* Mount options that take string arguments */ |
95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 98 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
@@ -139,22 +142,23 @@ static const match_table_t nfs_mount_option_tokens = { | |||
139 | { Opt_fscache_uniq, "fsc=%s" }, | 142 | { Opt_fscache_uniq, "fsc=%s" }, |
140 | { Opt_nofscache, "nofsc" }, | 143 | { Opt_nofscache, "nofsc" }, |
141 | 144 | ||
142 | { Opt_port, "port=%u" }, | 145 | { Opt_port, "port=%s" }, |
143 | { Opt_rsize, "rsize=%u" }, | 146 | { Opt_rsize, "rsize=%s" }, |
144 | { Opt_wsize, "wsize=%u" }, | 147 | { Opt_wsize, "wsize=%s" }, |
145 | { Opt_bsize, "bsize=%u" }, | 148 | { Opt_bsize, "bsize=%s" }, |
146 | { Opt_timeo, "timeo=%u" }, | 149 | { Opt_timeo, "timeo=%s" }, |
147 | { Opt_retrans, "retrans=%u" }, | 150 | { Opt_retrans, "retrans=%s" }, |
148 | { Opt_acregmin, "acregmin=%u" }, | 151 | { Opt_acregmin, "acregmin=%s" }, |
149 | { Opt_acregmax, "acregmax=%u" }, | 152 | { Opt_acregmax, "acregmax=%s" }, |
150 | { Opt_acdirmin, "acdirmin=%u" }, | 153 | { Opt_acdirmin, "acdirmin=%s" }, |
151 | { Opt_acdirmax, "acdirmax=%u" }, | 154 | { Opt_acdirmax, "acdirmax=%s" }, |
152 | { Opt_actimeo, "actimeo=%u" }, | 155 | { Opt_actimeo, "actimeo=%s" }, |
153 | { Opt_namelen, "namlen=%u" }, | 156 | { Opt_namelen, "namlen=%s" }, |
154 | { Opt_mountport, "mountport=%u" }, | 157 | { Opt_mountport, "mountport=%s" }, |
155 | { Opt_mountvers, "mountvers=%u" }, | 158 | { Opt_mountvers, "mountvers=%s" }, |
156 | { Opt_nfsvers, "nfsvers=%u" }, | 159 | { Opt_nfsvers, "nfsvers=%s" }, |
157 | { Opt_nfsvers, "vers=%u" }, | 160 | { Opt_nfsvers, "vers=%s" }, |
161 | { Opt_minorversion, "minorversion=%u" }, | ||
158 | 162 | ||
159 | { Opt_sec, "sec=%s" }, | 163 | { Opt_sec, "sec=%s" }, |
160 | { Opt_proto, "proto=%s" }, | 164 | { Opt_proto, "proto=%s" }, |
@@ -270,10 +274,14 @@ static const struct super_operations nfs_sops = { | |||
270 | #ifdef CONFIG_NFS_V4 | 274 | #ifdef CONFIG_NFS_V4 |
271 | static int nfs4_get_sb(struct file_system_type *fs_type, | 275 | static int nfs4_get_sb(struct file_system_type *fs_type, |
272 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
277 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, | ||
278 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
273 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, | 279 | static int nfs4_xdev_get_sb(struct file_system_type *fs_type, |
274 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 280 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
275 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | 281 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, |
276 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 282 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
283 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | ||
284 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | ||
277 | static void nfs4_kill_super(struct super_block *sb); | 285 | static void nfs4_kill_super(struct super_block *sb); |
278 | 286 | ||
279 | static struct file_system_type nfs4_fs_type = { | 287 | static struct file_system_type nfs4_fs_type = { |
@@ -284,6 +292,14 @@ static struct file_system_type nfs4_fs_type = { | |||
284 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
285 | }; | 293 | }; |
286 | 294 | ||
295 | static struct file_system_type nfs4_remote_fs_type = { | ||
296 | .owner = THIS_MODULE, | ||
297 | .name = "nfs4", | ||
298 | .get_sb = nfs4_remote_get_sb, | ||
299 | .kill_sb = nfs4_kill_super, | ||
300 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
301 | }; | ||
302 | |||
287 | struct file_system_type nfs4_xdev_fs_type = { | 303 | struct file_system_type nfs4_xdev_fs_type = { |
288 | .owner = THIS_MODULE, | 304 | .owner = THIS_MODULE, |
289 | .name = "nfs4", | 305 | .name = "nfs4", |
@@ -292,6 +308,14 @@ struct file_system_type nfs4_xdev_fs_type = { | |||
292 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 308 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
293 | }; | 309 | }; |
294 | 310 | ||
311 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
312 | .owner = THIS_MODULE, | ||
313 | .name = "nfs4", | ||
314 | .get_sb = nfs4_remote_referral_get_sb, | ||
315 | .kill_sb = nfs4_kill_super, | ||
316 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
317 | }; | ||
318 | |||
295 | struct file_system_type nfs4_referral_fs_type = { | 319 | struct file_system_type nfs4_referral_fs_type = { |
296 | .owner = THIS_MODULE, | 320 | .owner = THIS_MODULE, |
297 | .name = "nfs4", | 321 | .name = "nfs4", |
@@ -514,7 +538,6 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
514 | const char *nostr; | 538 | const char *nostr; |
515 | } nfs_info[] = { | 539 | } nfs_info[] = { |
516 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, | 540 | { NFS_MOUNT_SOFT, ",soft", ",hard" }, |
517 | { NFS_MOUNT_INTR, ",intr", ",nointr" }, | ||
518 | { NFS_MOUNT_POSIX, ",posix", "" }, | 541 | { NFS_MOUNT_POSIX, ",posix", "" }, |
519 | { NFS_MOUNT_NOCTO, ",nocto", "" }, | 542 | { NFS_MOUNT_NOCTO, ",nocto", "" }, |
520 | { NFS_MOUNT_NOAC, ",noac", "" }, | 543 | { NFS_MOUNT_NOAC, ",noac", "" }, |
@@ -943,11 +966,6 @@ static int nfs_parse_security_flavors(char *value, | |||
943 | return 1; | 966 | return 1; |
944 | } | 967 | } |
945 | 968 | ||
946 | static void nfs_parse_invalid_value(const char *option) | ||
947 | { | ||
948 | dfprintk(MOUNT, "NFS: bad value specified for %s option\n", option); | ||
949 | } | ||
950 | |||
951 | /* | 969 | /* |
952 | * Error-check and convert a string of mount options from user space into | 970 | * Error-check and convert a string of mount options from user space into |
953 | * a data structure. The whole mount string is processed; bad options are | 971 | * a data structure. The whole mount string is processed; bad options are |
@@ -958,7 +976,7 @@ static int nfs_parse_mount_options(char *raw, | |||
958 | struct nfs_parsed_mount_data *mnt) | 976 | struct nfs_parsed_mount_data *mnt) |
959 | { | 977 | { |
960 | char *p, *string, *secdata; | 978 | char *p, *string, *secdata; |
961 | int rc, sloppy = 0, errors = 0; | 979 | int rc, sloppy = 0, invalid_option = 0; |
962 | 980 | ||
963 | if (!raw) { | 981 | if (!raw) { |
964 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 982 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -982,7 +1000,9 @@ static int nfs_parse_mount_options(char *raw, | |||
982 | 1000 | ||
983 | while ((p = strsep(&raw, ",")) != NULL) { | 1001 | while ((p = strsep(&raw, ",")) != NULL) { |
984 | substring_t args[MAX_OPT_ARGS]; | 1002 | substring_t args[MAX_OPT_ARGS]; |
985 | int option, token; | 1003 | unsigned long option; |
1004 | int int_option; | ||
1005 | int token; | ||
986 | 1006 | ||
987 | if (!*p) | 1007 | if (!*p) |
988 | continue; | 1008 | continue; |
@@ -1091,114 +1111,156 @@ static int nfs_parse_mount_options(char *raw, | |||
1091 | * options that take numeric values | 1111 | * options that take numeric values |
1092 | */ | 1112 | */ |
1093 | case Opt_port: | 1113 | case Opt_port: |
1094 | if (match_int(args, &option) || | 1114 | string = match_strdup(args); |
1095 | option < 0 || option > USHORT_MAX) { | 1115 | if (string == NULL) |
1096 | errors++; | 1116 | goto out_nomem; |
1097 | nfs_parse_invalid_value("port"); | 1117 | rc = strict_strtoul(string, 10, &option); |
1098 | } else | 1118 | kfree(string); |
1099 | mnt->nfs_server.port = option; | 1119 | if (rc != 0 || option > USHORT_MAX) |
1120 | goto out_invalid_value; | ||
1121 | mnt->nfs_server.port = option; | ||
1100 | break; | 1122 | break; |
1101 | case Opt_rsize: | 1123 | case Opt_rsize: |
1102 | if (match_int(args, &option) || option < 0) { | 1124 | string = match_strdup(args); |
1103 | errors++; | 1125 | if (string == NULL) |
1104 | nfs_parse_invalid_value("rsize"); | 1126 | goto out_nomem; |
1105 | } else | 1127 | rc = strict_strtoul(string, 10, &option); |
1106 | mnt->rsize = option; | 1128 | kfree(string); |
1129 | if (rc != 0) | ||
1130 | goto out_invalid_value; | ||
1131 | mnt->rsize = option; | ||
1107 | break; | 1132 | break; |
1108 | case Opt_wsize: | 1133 | case Opt_wsize: |
1109 | if (match_int(args, &option) || option < 0) { | 1134 | string = match_strdup(args); |
1110 | errors++; | 1135 | if (string == NULL) |
1111 | nfs_parse_invalid_value("wsize"); | 1136 | goto out_nomem; |
1112 | } else | 1137 | rc = strict_strtoul(string, 10, &option); |
1113 | mnt->wsize = option; | 1138 | kfree(string); |
1139 | if (rc != 0) | ||
1140 | goto out_invalid_value; | ||
1141 | mnt->wsize = option; | ||
1114 | break; | 1142 | break; |
1115 | case Opt_bsize: | 1143 | case Opt_bsize: |
1116 | if (match_int(args, &option) || option < 0) { | 1144 | string = match_strdup(args); |
1117 | errors++; | 1145 | if (string == NULL) |
1118 | nfs_parse_invalid_value("bsize"); | 1146 | goto out_nomem; |
1119 | } else | 1147 | rc = strict_strtoul(string, 10, &option); |
1120 | mnt->bsize = option; | 1148 | kfree(string); |
1149 | if (rc != 0) | ||
1150 | goto out_invalid_value; | ||
1151 | mnt->bsize = option; | ||
1121 | break; | 1152 | break; |
1122 | case Opt_timeo: | 1153 | case Opt_timeo: |
1123 | if (match_int(args, &option) || option <= 0) { | 1154 | string = match_strdup(args); |
1124 | errors++; | 1155 | if (string == NULL) |
1125 | nfs_parse_invalid_value("timeo"); | 1156 | goto out_nomem; |
1126 | } else | 1157 | rc = strict_strtoul(string, 10, &option); |
1127 | mnt->timeo = option; | 1158 | kfree(string); |
1159 | if (rc != 0 || option == 0) | ||
1160 | goto out_invalid_value; | ||
1161 | mnt->timeo = option; | ||
1128 | break; | 1162 | break; |
1129 | case Opt_retrans: | 1163 | case Opt_retrans: |
1130 | if (match_int(args, &option) || option <= 0) { | 1164 | string = match_strdup(args); |
1131 | errors++; | 1165 | if (string == NULL) |
1132 | nfs_parse_invalid_value("retrans"); | 1166 | goto out_nomem; |
1133 | } else | 1167 | rc = strict_strtoul(string, 10, &option); |
1134 | mnt->retrans = option; | 1168 | kfree(string); |
1169 | if (rc != 0 || option == 0) | ||
1170 | goto out_invalid_value; | ||
1171 | mnt->retrans = option; | ||
1135 | break; | 1172 | break; |
1136 | case Opt_acregmin: | 1173 | case Opt_acregmin: |
1137 | if (match_int(args, &option) || option < 0) { | 1174 | string = match_strdup(args); |
1138 | errors++; | 1175 | if (string == NULL) |
1139 | nfs_parse_invalid_value("acregmin"); | 1176 | goto out_nomem; |
1140 | } else | 1177 | rc = strict_strtoul(string, 10, &option); |
1141 | mnt->acregmin = option; | 1178 | kfree(string); |
1179 | if (rc != 0) | ||
1180 | goto out_invalid_value; | ||
1181 | mnt->acregmin = option; | ||
1142 | break; | 1182 | break; |
1143 | case Opt_acregmax: | 1183 | case Opt_acregmax: |
1144 | if (match_int(args, &option) || option < 0) { | 1184 | string = match_strdup(args); |
1145 | errors++; | 1185 | if (string == NULL) |
1146 | nfs_parse_invalid_value("acregmax"); | 1186 | goto out_nomem; |
1147 | } else | 1187 | rc = strict_strtoul(string, 10, &option); |
1148 | mnt->acregmax = option; | 1188 | kfree(string); |
1189 | if (rc != 0) | ||
1190 | goto out_invalid_value; | ||
1191 | mnt->acregmax = option; | ||
1149 | break; | 1192 | break; |
1150 | case Opt_acdirmin: | 1193 | case Opt_acdirmin: |
1151 | if (match_int(args, &option) || option < 0) { | 1194 | string = match_strdup(args); |
1152 | errors++; | 1195 | if (string == NULL) |
1153 | nfs_parse_invalid_value("acdirmin"); | 1196 | goto out_nomem; |
1154 | } else | 1197 | rc = strict_strtoul(string, 10, &option); |
1155 | mnt->acdirmin = option; | 1198 | kfree(string); |
1199 | if (rc != 0) | ||
1200 | goto out_invalid_value; | ||
1201 | mnt->acdirmin = option; | ||
1156 | break; | 1202 | break; |
1157 | case Opt_acdirmax: | 1203 | case Opt_acdirmax: |
1158 | if (match_int(args, &option) || option < 0) { | 1204 | string = match_strdup(args); |
1159 | errors++; | 1205 | if (string == NULL) |
1160 | nfs_parse_invalid_value("acdirmax"); | 1206 | goto out_nomem; |
1161 | } else | 1207 | rc = strict_strtoul(string, 10, &option); |
1162 | mnt->acdirmax = option; | 1208 | kfree(string); |
1209 | if (rc != 0) | ||
1210 | goto out_invalid_value; | ||
1211 | mnt->acdirmax = option; | ||
1163 | break; | 1212 | break; |
1164 | case Opt_actimeo: | 1213 | case Opt_actimeo: |
1165 | if (match_int(args, &option) || option < 0) { | 1214 | string = match_strdup(args); |
1166 | errors++; | 1215 | if (string == NULL) |
1167 | nfs_parse_invalid_value("actimeo"); | 1216 | goto out_nomem; |
1168 | } else | 1217 | rc = strict_strtoul(string, 10, &option); |
1169 | mnt->acregmin = mnt->acregmax = | 1218 | kfree(string); |
1170 | mnt->acdirmin = mnt->acdirmax = option; | 1219 | if (rc != 0) |
1220 | goto out_invalid_value; | ||
1221 | mnt->acregmin = mnt->acregmax = | ||
1222 | mnt->acdirmin = mnt->acdirmax = option; | ||
1171 | break; | 1223 | break; |
1172 | case Opt_namelen: | 1224 | case Opt_namelen: |
1173 | if (match_int(args, &option) || option < 0) { | 1225 | string = match_strdup(args); |
1174 | errors++; | 1226 | if (string == NULL) |
1175 | nfs_parse_invalid_value("namlen"); | 1227 | goto out_nomem; |
1176 | } else | 1228 | rc = strict_strtoul(string, 10, &option); |
1177 | mnt->namlen = option; | 1229 | kfree(string); |
1230 | if (rc != 0) | ||
1231 | goto out_invalid_value; | ||
1232 | mnt->namlen = option; | ||
1178 | break; | 1233 | break; |
1179 | case Opt_mountport: | 1234 | case Opt_mountport: |
1180 | if (match_int(args, &option) || | 1235 | string = match_strdup(args); |
1181 | option < 0 || option > USHORT_MAX) { | 1236 | if (string == NULL) |
1182 | errors++; | 1237 | goto out_nomem; |
1183 | nfs_parse_invalid_value("mountport"); | 1238 | rc = strict_strtoul(string, 10, &option); |
1184 | } else | 1239 | kfree(string); |
1185 | mnt->mount_server.port = option; | 1240 | if (rc != 0 || option > USHORT_MAX) |
1241 | goto out_invalid_value; | ||
1242 | mnt->mount_server.port = option; | ||
1186 | break; | 1243 | break; |
1187 | case Opt_mountvers: | 1244 | case Opt_mountvers: |
1188 | if (match_int(args, &option) || | 1245 | string = match_strdup(args); |
1246 | if (string == NULL) | ||
1247 | goto out_nomem; | ||
1248 | rc = strict_strtoul(string, 10, &option); | ||
1249 | kfree(string); | ||
1250 | if (rc != 0 || | ||
1189 | option < NFS_MNT_VERSION || | 1251 | option < NFS_MNT_VERSION || |
1190 | option > NFS_MNT3_VERSION) { | 1252 | option > NFS_MNT3_VERSION) |
1191 | errors++; | 1253 | goto out_invalid_value; |
1192 | nfs_parse_invalid_value("mountvers"); | 1254 | mnt->mount_server.version = option; |
1193 | } else | ||
1194 | mnt->mount_server.version = option; | ||
1195 | break; | 1255 | break; |
1196 | case Opt_nfsvers: | 1256 | case Opt_nfsvers: |
1197 | if (match_int(args, &option)) { | 1257 | string = match_strdup(args); |
1198 | errors++; | 1258 | if (string == NULL) |
1199 | nfs_parse_invalid_value("nfsvers"); | 1259 | goto out_nomem; |
1200 | break; | 1260 | rc = strict_strtoul(string, 10, &option); |
1201 | } | 1261 | kfree(string); |
1262 | if (rc != 0) | ||
1263 | goto out_invalid_value; | ||
1202 | switch (option) { | 1264 | switch (option) { |
1203 | case NFS2_VERSION: | 1265 | case NFS2_VERSION: |
1204 | mnt->flags &= ~NFS_MOUNT_VER3; | 1266 | mnt->flags &= ~NFS_MOUNT_VER3; |
@@ -1207,10 +1269,16 @@ static int nfs_parse_mount_options(char *raw, | |||
1207 | mnt->flags |= NFS_MOUNT_VER3; | 1269 | mnt->flags |= NFS_MOUNT_VER3; |
1208 | break; | 1270 | break; |
1209 | default: | 1271 | default: |
1210 | errors++; | 1272 | goto out_invalid_value; |
1211 | nfs_parse_invalid_value("nfsvers"); | ||
1212 | } | 1273 | } |
1213 | break; | 1274 | break; |
1275 | case Opt_minorversion: | ||
1276 | if (match_int(args, &int_option)) | ||
1277 | return 0; | ||
1278 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | ||
1279 | return 0; | ||
1280 | mnt->minorversion = int_option; | ||
1281 | break; | ||
1214 | 1282 | ||
1215 | /* | 1283 | /* |
1216 | * options that take text values | 1284 | * options that take text values |
@@ -1222,9 +1290,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1222 | rc = nfs_parse_security_flavors(string, mnt); | 1290 | rc = nfs_parse_security_flavors(string, mnt); |
1223 | kfree(string); | 1291 | kfree(string); |
1224 | if (!rc) { | 1292 | if (!rc) { |
1225 | errors++; | ||
1226 | dfprintk(MOUNT, "NFS: unrecognized " | 1293 | dfprintk(MOUNT, "NFS: unrecognized " |
1227 | "security flavor\n"); | 1294 | "security flavor\n"); |
1295 | return 0; | ||
1228 | } | 1296 | } |
1229 | break; | 1297 | break; |
1230 | case Opt_proto: | 1298 | case Opt_proto: |
@@ -1238,23 +1306,25 @@ static int nfs_parse_mount_options(char *raw, | |||
1238 | case Opt_xprt_udp: | 1306 | case Opt_xprt_udp: |
1239 | mnt->flags &= ~NFS_MOUNT_TCP; | 1307 | mnt->flags &= ~NFS_MOUNT_TCP; |
1240 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1308 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1309 | kfree(string); | ||
1241 | break; | 1310 | break; |
1242 | case Opt_xprt_tcp: | 1311 | case Opt_xprt_tcp: |
1243 | mnt->flags |= NFS_MOUNT_TCP; | 1312 | mnt->flags |= NFS_MOUNT_TCP; |
1244 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1313 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
1314 | kfree(string); | ||
1245 | break; | 1315 | break; |
1246 | case Opt_xprt_rdma: | 1316 | case Opt_xprt_rdma: |
1247 | /* vector side protocols to TCP */ | 1317 | /* vector side protocols to TCP */ |
1248 | mnt->flags |= NFS_MOUNT_TCP; | 1318 | mnt->flags |= NFS_MOUNT_TCP; |
1249 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; | 1319 | mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA; |
1250 | xprt_load_transport(string); | 1320 | xprt_load_transport(string); |
1321 | kfree(string); | ||
1251 | break; | 1322 | break; |
1252 | default: | 1323 | default: |
1253 | errors++; | ||
1254 | dfprintk(MOUNT, "NFS: unrecognized " | 1324 | dfprintk(MOUNT, "NFS: unrecognized " |
1255 | "transport protocol\n"); | 1325 | "transport protocol\n"); |
1326 | return 0; | ||
1256 | } | 1327 | } |
1257 | kfree(string); | ||
1258 | break; | 1328 | break; |
1259 | case Opt_mountproto: | 1329 | case Opt_mountproto: |
1260 | string = match_strdup(args); | 1330 | string = match_strdup(args); |
@@ -1273,9 +1343,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1273 | break; | 1343 | break; |
1274 | case Opt_xprt_rdma: /* not used for side protocols */ | 1344 | case Opt_xprt_rdma: /* not used for side protocols */ |
1275 | default: | 1345 | default: |
1276 | errors++; | ||
1277 | dfprintk(MOUNT, "NFS: unrecognized " | 1346 | dfprintk(MOUNT, "NFS: unrecognized " |
1278 | "transport protocol\n"); | 1347 | "transport protocol\n"); |
1348 | return 0; | ||
1279 | } | 1349 | } |
1280 | break; | 1350 | break; |
1281 | case Opt_addr: | 1351 | case Opt_addr: |
@@ -1331,9 +1401,9 @@ static int nfs_parse_mount_options(char *raw, | |||
1331 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; | 1401 | mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE; |
1332 | break; | 1402 | break; |
1333 | default: | 1403 | default: |
1334 | errors++; | ||
1335 | dfprintk(MOUNT, "NFS: invalid " | 1404 | dfprintk(MOUNT, "NFS: invalid " |
1336 | "lookupcache argument\n"); | 1405 | "lookupcache argument\n"); |
1406 | return 0; | ||
1337 | }; | 1407 | }; |
1338 | break; | 1408 | break; |
1339 | 1409 | ||
@@ -1351,20 +1421,20 @@ static int nfs_parse_mount_options(char *raw, | |||
1351 | break; | 1421 | break; |
1352 | 1422 | ||
1353 | default: | 1423 | default: |
1354 | errors++; | 1424 | invalid_option = 1; |
1355 | dfprintk(MOUNT, "NFS: unrecognized mount option " | 1425 | dfprintk(MOUNT, "NFS: unrecognized mount option " |
1356 | "'%s'\n", p); | 1426 | "'%s'\n", p); |
1357 | } | 1427 | } |
1358 | } | 1428 | } |
1359 | 1429 | ||
1360 | if (errors > 0) { | 1430 | if (!sloppy && invalid_option) |
1361 | dfprintk(MOUNT, "NFS: parsing encountered %d error%s\n", | 1431 | return 0; |
1362 | errors, (errors == 1 ? "" : "s")); | 1432 | |
1363 | if (!sloppy) | ||
1364 | return 0; | ||
1365 | } | ||
1366 | return 1; | 1433 | return 1; |
1367 | 1434 | ||
1435 | out_invalid_value: | ||
1436 | printk(KERN_INFO "NFS: bad mount option value specified: %s \n", p); | ||
1437 | return 0; | ||
1368 | out_nomem: | 1438 | out_nomem: |
1369 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1439 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
1370 | return 0; | 1440 | return 0; |
@@ -1381,6 +1451,7 @@ out_security_failure: | |||
1381 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, | 1451 | static int nfs_try_mount(struct nfs_parsed_mount_data *args, |
1382 | struct nfs_fh *root_fh) | 1452 | struct nfs_fh *root_fh) |
1383 | { | 1453 | { |
1454 | unsigned int auth_flavor_len = 0; | ||
1384 | struct nfs_mount_request request = { | 1455 | struct nfs_mount_request request = { |
1385 | .sap = (struct sockaddr *) | 1456 | .sap = (struct sockaddr *) |
1386 | &args->mount_server.address, | 1457 | &args->mount_server.address, |
@@ -1388,6 +1459,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, | |||
1388 | .protocol = args->mount_server.protocol, | 1459 | .protocol = args->mount_server.protocol, |
1389 | .fh = root_fh, | 1460 | .fh = root_fh, |
1390 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, | 1461 | .noresvport = args->flags & NFS_MOUNT_NORESVPORT, |
1462 | .auth_flav_len = &auth_flavor_len, | ||
1391 | }; | 1463 | }; |
1392 | int status; | 1464 | int status; |
1393 | 1465 | ||
@@ -2240,6 +2312,11 @@ static void nfs4_fill_super(struct super_block *sb) | |||
2240 | nfs_initialise_sb(sb); | 2312 | nfs_initialise_sb(sb); |
2241 | } | 2313 | } |
2242 | 2314 | ||
2315 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | ||
2316 | { | ||
2317 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3); | ||
2318 | } | ||
2319 | |||
2243 | /* | 2320 | /* |
2244 | * Validate NFSv4 mount options | 2321 | * Validate NFSv4 mount options |
2245 | */ | 2322 | */ |
@@ -2263,6 +2340,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2263 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2340 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
2264 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2341 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2265 | args->auth_flavor_len = 0; | 2342 | args->auth_flavor_len = 0; |
2343 | args->minorversion = 0; | ||
2266 | 2344 | ||
2267 | switch (data->version) { | 2345 | switch (data->version) { |
2268 | case 1: | 2346 | case 1: |
@@ -2336,6 +2414,8 @@ static int nfs4_validate_mount_data(void *options, | |||
2336 | 2414 | ||
2337 | nfs_validate_transport_protocol(args); | 2415 | nfs_validate_transport_protocol(args); |
2338 | 2416 | ||
2417 | nfs4_validate_mount_flags(args); | ||
2418 | |||
2339 | if (args->auth_flavor_len > 1) | 2419 | if (args->auth_flavor_len > 1) |
2340 | goto out_inval_auth; | 2420 | goto out_inval_auth; |
2341 | 2421 | ||
@@ -2375,12 +2455,12 @@ out_no_client_address: | |||
2375 | } | 2455 | } |
2376 | 2456 | ||
2377 | /* | 2457 | /* |
2378 | * Get the superblock for an NFS4 mountpoint | 2458 | * Get the superblock for the NFS4 root partition |
2379 | */ | 2459 | */ |
2380 | static int nfs4_get_sb(struct file_system_type *fs_type, | 2460 | static int nfs4_remote_get_sb(struct file_system_type *fs_type, |
2381 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2461 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) |
2382 | { | 2462 | { |
2383 | struct nfs_parsed_mount_data *data; | 2463 | struct nfs_parsed_mount_data *data = raw_data; |
2384 | struct super_block *s; | 2464 | struct super_block *s; |
2385 | struct nfs_server *server; | 2465 | struct nfs_server *server; |
2386 | struct nfs_fh *mntfh; | 2466 | struct nfs_fh *mntfh; |
@@ -2391,18 +2471,12 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2391 | }; | 2471 | }; |
2392 | int error = -ENOMEM; | 2472 | int error = -ENOMEM; |
2393 | 2473 | ||
2394 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2395 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); | 2474 | mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL); |
2396 | if (data == NULL || mntfh == NULL) | 2475 | if (data == NULL || mntfh == NULL) |
2397 | goto out_free_fh; | 2476 | goto out_free_fh; |
2398 | 2477 | ||
2399 | security_init_mnt_opts(&data->lsm_opts); | 2478 | security_init_mnt_opts(&data->lsm_opts); |
2400 | 2479 | ||
2401 | /* Validate the mount data */ | ||
2402 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2403 | if (error < 0) | ||
2404 | goto out; | ||
2405 | |||
2406 | /* Get a volume representation */ | 2480 | /* Get a volume representation */ |
2407 | server = nfs4_create_server(data, mntfh); | 2481 | server = nfs4_create_server(data, mntfh); |
2408 | if (IS_ERR(server)) { | 2482 | if (IS_ERR(server)) { |
@@ -2415,7 +2489,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2415 | compare_super = NULL; | 2489 | compare_super = NULL; |
2416 | 2490 | ||
2417 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2491 | /* Get a superblock - note that we may end up sharing one that already exists */ |
2418 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); | 2492 | s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata); |
2419 | if (IS_ERR(s)) { | 2493 | if (IS_ERR(s)) { |
2420 | error = PTR_ERR(s); | 2494 | error = PTR_ERR(s); |
2421 | goto out_free; | 2495 | goto out_free; |
@@ -2452,14 +2526,9 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
2452 | error = 0; | 2526 | error = 0; |
2453 | 2527 | ||
2454 | out: | 2528 | out: |
2455 | kfree(data->client_address); | ||
2456 | kfree(data->nfs_server.export_path); | ||
2457 | kfree(data->nfs_server.hostname); | ||
2458 | kfree(data->fscache_uniq); | ||
2459 | security_free_mnt_opts(&data->lsm_opts); | 2529 | security_free_mnt_opts(&data->lsm_opts); |
2460 | out_free_fh: | 2530 | out_free_fh: |
2461 | kfree(mntfh); | 2531 | kfree(mntfh); |
2462 | kfree(data); | ||
2463 | return error; | 2532 | return error; |
2464 | 2533 | ||
2465 | out_free: | 2534 | out_free: |
@@ -2473,16 +2542,137 @@ error_splat_super: | |||
2473 | goto out; | 2542 | goto out; |
2474 | } | 2543 | } |
2475 | 2544 | ||
2545 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
2546 | int flags, void *data, const char *hostname) | ||
2547 | { | ||
2548 | struct vfsmount *root_mnt; | ||
2549 | char *root_devname; | ||
2550 | size_t len; | ||
2551 | |||
2552 | len = strlen(hostname) + 3; | ||
2553 | root_devname = kmalloc(len, GFP_KERNEL); | ||
2554 | if (root_devname == NULL) | ||
2555 | return ERR_PTR(-ENOMEM); | ||
2556 | snprintf(root_devname, len, "%s:/", hostname); | ||
2557 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
2558 | kfree(root_devname); | ||
2559 | return root_mnt; | ||
2560 | } | ||
2561 | |||
2562 | static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | ||
2563 | { | ||
2564 | char *page = (char *) __get_free_page(GFP_KERNEL); | ||
2565 | char *devname, *tmp; | ||
2566 | |||
2567 | if (page == NULL) | ||
2568 | return; | ||
2569 | devname = nfs_path(path->mnt->mnt_devname, | ||
2570 | path->mnt->mnt_root, path->dentry, | ||
2571 | page, PAGE_SIZE); | ||
2572 | if (devname == NULL) | ||
2573 | goto out_freepage; | ||
2574 | tmp = kstrdup(devname, GFP_KERNEL); | ||
2575 | if (tmp == NULL) | ||
2576 | goto out_freepage; | ||
2577 | kfree(mnt->mnt_devname); | ||
2578 | mnt->mnt_devname = tmp; | ||
2579 | out_freepage: | ||
2580 | free_page((unsigned long)page); | ||
2581 | } | ||
2582 | |||
2583 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
2584 | const char *export_path, struct vfsmount *mnt_target) | ||
2585 | { | ||
2586 | struct mnt_namespace *ns_private; | ||
2587 | struct nameidata nd; | ||
2588 | struct super_block *s; | ||
2589 | int ret; | ||
2590 | |||
2591 | ns_private = create_mnt_ns(root_mnt); | ||
2592 | ret = PTR_ERR(ns_private); | ||
2593 | if (IS_ERR(ns_private)) | ||
2594 | goto out_mntput; | ||
2595 | |||
2596 | ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, | ||
2597 | export_path, LOOKUP_FOLLOW, &nd); | ||
2598 | |||
2599 | put_mnt_ns(ns_private); | ||
2600 | |||
2601 | if (ret != 0) | ||
2602 | goto out_err; | ||
2603 | |||
2604 | s = nd.path.mnt->mnt_sb; | ||
2605 | atomic_inc(&s->s_active); | ||
2606 | mnt_target->mnt_sb = s; | ||
2607 | mnt_target->mnt_root = dget(nd.path.dentry); | ||
2608 | |||
2609 | /* Correct the device pathname */ | ||
2610 | nfs_fix_devname(&nd.path, mnt_target); | ||
2611 | |||
2612 | path_put(&nd.path); | ||
2613 | down_write(&s->s_umount); | ||
2614 | return 0; | ||
2615 | out_mntput: | ||
2616 | mntput(root_mnt); | ||
2617 | out_err: | ||
2618 | return ret; | ||
2619 | } | ||
2620 | |||
2621 | /* | ||
2622 | * Get the superblock for an NFS4 mountpoint | ||
2623 | */ | ||
2624 | static int nfs4_get_sb(struct file_system_type *fs_type, | ||
2625 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | ||
2626 | { | ||
2627 | struct nfs_parsed_mount_data *data; | ||
2628 | char *export_path; | ||
2629 | struct vfsmount *root_mnt; | ||
2630 | int error = -ENOMEM; | ||
2631 | |||
2632 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
2633 | if (data == NULL) | ||
2634 | goto out_free_data; | ||
2635 | |||
2636 | /* Validate the mount data */ | ||
2637 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | ||
2638 | if (error < 0) | ||
2639 | goto out; | ||
2640 | |||
2641 | export_path = data->nfs_server.export_path; | ||
2642 | data->nfs_server.export_path = "/"; | ||
2643 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data, | ||
2644 | data->nfs_server.hostname); | ||
2645 | data->nfs_server.export_path = export_path; | ||
2646 | |||
2647 | error = PTR_ERR(root_mnt); | ||
2648 | if (IS_ERR(root_mnt)) | ||
2649 | goto out; | ||
2650 | |||
2651 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2652 | |||
2653 | out: | ||
2654 | kfree(data->client_address); | ||
2655 | kfree(data->nfs_server.export_path); | ||
2656 | kfree(data->nfs_server.hostname); | ||
2657 | kfree(data->fscache_uniq); | ||
2658 | out_free_data: | ||
2659 | kfree(data); | ||
2660 | dprintk("<-- nfs4_get_sb() = %d%s\n", error, | ||
2661 | error != 0 ? " [error]" : ""); | ||
2662 | return error; | ||
2663 | } | ||
2664 | |||
2476 | static void nfs4_kill_super(struct super_block *sb) | 2665 | static void nfs4_kill_super(struct super_block *sb) |
2477 | { | 2666 | { |
2478 | struct nfs_server *server = NFS_SB(sb); | 2667 | struct nfs_server *server = NFS_SB(sb); |
2479 | 2668 | ||
2669 | dprintk("--> %s\n", __func__); | ||
2480 | nfs_super_return_all_delegations(sb); | 2670 | nfs_super_return_all_delegations(sb); |
2481 | kill_anon_super(sb); | 2671 | kill_anon_super(sb); |
2482 | |||
2483 | nfs4_renewd_prepare_shutdown(server); | 2672 | nfs4_renewd_prepare_shutdown(server); |
2484 | nfs_fscache_release_super_cookie(sb); | 2673 | nfs_fscache_release_super_cookie(sb); |
2485 | nfs_free_server(server); | 2674 | nfs_free_server(server); |
2675 | dprintk("<-- %s\n", __func__); | ||
2486 | } | 2676 | } |
2487 | 2677 | ||
2488 | /* | 2678 | /* |
@@ -2568,12 +2758,9 @@ error_splat_super: | |||
2568 | return error; | 2758 | return error; |
2569 | } | 2759 | } |
2570 | 2760 | ||
2571 | /* | 2761 | static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, |
2572 | * Create an NFS4 server record on referral traversal | 2762 | int flags, const char *dev_name, void *raw_data, |
2573 | */ | 2763 | struct vfsmount *mnt) |
2574 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags, | ||
2575 | const char *dev_name, void *raw_data, | ||
2576 | struct vfsmount *mnt) | ||
2577 | { | 2764 | { |
2578 | struct nfs_clone_mount *data = raw_data; | 2765 | struct nfs_clone_mount *data = raw_data; |
2579 | struct super_block *s; | 2766 | struct super_block *s; |
@@ -2652,4 +2839,36 @@ error_splat_super: | |||
2652 | return error; | 2839 | return error; |
2653 | } | 2840 | } |
2654 | 2841 | ||
2842 | /* | ||
2843 | * Create an NFS4 server record on referral traversal | ||
2844 | */ | ||
2845 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | ||
2846 | int flags, const char *dev_name, void *raw_data, | ||
2847 | struct vfsmount *mnt) | ||
2848 | { | ||
2849 | struct nfs_clone_mount *data = raw_data; | ||
2850 | char *export_path; | ||
2851 | struct vfsmount *root_mnt; | ||
2852 | int error; | ||
2853 | |||
2854 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
2855 | |||
2856 | export_path = data->mnt_path; | ||
2857 | data->mnt_path = "/"; | ||
2858 | |||
2859 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
2860 | flags, data, data->hostname); | ||
2861 | data->mnt_path = export_path; | ||
2862 | |||
2863 | error = PTR_ERR(root_mnt); | ||
2864 | if (IS_ERR(root_mnt)) | ||
2865 | goto out; | ||
2866 | |||
2867 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | ||
2868 | out: | ||
2869 | dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error, | ||
2870 | error != 0 ? " [error]" : ""); | ||
2871 | return error; | ||
2872 | } | ||
2873 | |||
2655 | #endif /* CONFIG_NFS_V4 */ | 2874 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index ecc295347775..1064c91ae810 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
16 | 16 | ||
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | #include "nfs4_fs.h" | ||
18 | 19 | ||
19 | struct nfs_unlinkdata { | 20 | struct nfs_unlinkdata { |
20 | struct hlist_node list; | 21 | struct hlist_node list; |
@@ -82,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
82 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
83 | 84 | ||
84 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
85 | rpc_restart_call(task); | 86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); |
86 | } | 87 | } |
87 | 88 | ||
88 | /** | 89 | /** |
@@ -102,9 +103,25 @@ static void nfs_async_unlink_release(void *calldata) | |||
102 | nfs_sb_deactive(sb); | 103 | nfs_sb_deactive(sb); |
103 | } | 104 | } |
104 | 105 | ||
106 | #if defined(CONFIG_NFS_V4_1) | ||
107 | void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | ||
108 | { | ||
109 | struct nfs_unlinkdata *data = calldata; | ||
110 | struct nfs_server *server = NFS_SERVER(data->dir); | ||
111 | |||
112 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | ||
113 | &data->res.seq_res, 1, task)) | ||
114 | return; | ||
115 | rpc_call_start(task); | ||
116 | } | ||
117 | #endif /* CONFIG_NFS_V4_1 */ | ||
118 | |||
105 | static const struct rpc_call_ops nfs_unlink_ops = { | 119 | static const struct rpc_call_ops nfs_unlink_ops = { |
106 | .rpc_call_done = nfs_async_unlink_done, | 120 | .rpc_call_done = nfs_async_unlink_done, |
107 | .rpc_release = nfs_async_unlink_release, | 121 | .rpc_release = nfs_async_unlink_release, |
122 | #if defined(CONFIG_NFS_V4_1) | ||
123 | .rpc_call_prepare = nfs_unlink_prepare, | ||
124 | #endif /* CONFIG_NFS_V4_1 */ | ||
108 | }; | 125 | }; |
109 | 126 | ||
110 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 127 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
@@ -241,6 +258,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
241 | status = PTR_ERR(data->cred); | 258 | status = PTR_ERR(data->cred); |
242 | goto out_free; | 259 | goto out_free; |
243 | } | 260 | } |
261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
244 | 262 | ||
245 | status = -EBUSY; | 263 | status = -EBUSY; |
246 | spin_lock(&dentry->d_lock); | 264 | spin_lock(&dentry->d_lock); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e560a78995a3..a34fae21fe10 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "delegation.h" | 25 | #include "delegation.h" |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | #include "iostat.h" | 27 | #include "iostat.h" |
28 | #include "nfs4_fs.h" | ||
28 | 29 | ||
29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
30 | 31 | ||
@@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
52 | if (p) { | 53 | if (p) { |
53 | memset(p, 0, sizeof(*p)); | 54 | memset(p, 0, sizeof(*p)); |
54 | INIT_LIST_HEAD(&p->pages); | 55 | INIT_LIST_HEAD(&p->pages); |
56 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
55 | } | 57 | } |
56 | return p; | 58 | return p; |
57 | } | 59 | } |
@@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
71 | memset(p, 0, sizeof(*p)); | 73 | memset(p, 0, sizeof(*p)); |
72 | INIT_LIST_HEAD(&p->pages); | 74 | INIT_LIST_HEAD(&p->pages); |
73 | p->npages = pagecount; | 75 | p->npages = pagecount; |
76 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
74 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 77 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
75 | p->pagevec = p->page_array; | 78 | p->pagevec = p->page_array; |
76 | else { | 79 | else { |
@@ -84,17 +87,15 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
84 | return p; | 87 | return p; |
85 | } | 88 | } |
86 | 89 | ||
87 | static void nfs_writedata_free(struct nfs_write_data *p) | 90 | void nfs_writedata_free(struct nfs_write_data *p) |
88 | { | 91 | { |
89 | if (p && (p->pagevec != &p->page_array[0])) | 92 | if (p && (p->pagevec != &p->page_array[0])) |
90 | kfree(p->pagevec); | 93 | kfree(p->pagevec); |
91 | mempool_free(p, nfs_wdata_mempool); | 94 | mempool_free(p, nfs_wdata_mempool); |
92 | } | 95 | } |
93 | 96 | ||
94 | void nfs_writedata_release(void *data) | 97 | static void nfs_writedata_release(struct nfs_write_data *wdata) |
95 | { | 98 | { |
96 | struct nfs_write_data *wdata = data; | ||
97 | |||
98 | put_nfs_open_context(wdata->args.context); | 99 | put_nfs_open_context(wdata->args.context); |
99 | nfs_writedata_free(wdata); | 100 | nfs_writedata_free(wdata); |
100 | } | 101 | } |
@@ -199,8 +200,10 @@ static int nfs_set_page_writeback(struct page *page) | |||
199 | struct nfs_server *nfss = NFS_SERVER(inode); | 200 | struct nfs_server *nfss = NFS_SERVER(inode); |
200 | 201 | ||
201 | if (atomic_long_inc_return(&nfss->writeback) > | 202 | if (atomic_long_inc_return(&nfss->writeback) > |
202 | NFS_CONGESTION_ON_THRESH) | 203 | NFS_CONGESTION_ON_THRESH) { |
203 | set_bdi_congested(&nfss->backing_dev_info, WRITE); | 204 | set_bdi_congested(&nfss->backing_dev_info, |
205 | BLK_RW_ASYNC); | ||
206 | } | ||
204 | } | 207 | } |
205 | return ret; | 208 | return ret; |
206 | } | 209 | } |
@@ -212,7 +215,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
212 | 215 | ||
213 | end_page_writeback(page); | 216 | end_page_writeback(page); |
214 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 217 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
215 | clear_bdi_congested(&nfss->backing_dev_info, WRITE); | 218 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
216 | } | 219 | } |
217 | 220 | ||
218 | /* | 221 | /* |
@@ -1048,7 +1051,23 @@ out: | |||
1048 | nfs_writedata_release(calldata); | 1051 | nfs_writedata_release(calldata); |
1049 | } | 1052 | } |
1050 | 1053 | ||
1054 | #if defined(CONFIG_NFS_V4_1) | ||
1055 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | ||
1056 | { | ||
1057 | struct nfs_write_data *data = calldata; | ||
1058 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
1059 | |||
1060 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | ||
1061 | &data->res.seq_res, 1, task)) | ||
1062 | return; | ||
1063 | rpc_call_start(task); | ||
1064 | } | ||
1065 | #endif /* CONFIG_NFS_V4_1 */ | ||
1066 | |||
1051 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1067 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1068 | #if defined(CONFIG_NFS_V4_1) | ||
1069 | .rpc_call_prepare = nfs_write_prepare, | ||
1070 | #endif /* CONFIG_NFS_V4_1 */ | ||
1052 | .rpc_call_done = nfs_writeback_done_partial, | 1071 | .rpc_call_done = nfs_writeback_done_partial, |
1053 | .rpc_release = nfs_writeback_release_partial, | 1072 | .rpc_release = nfs_writeback_release_partial, |
1054 | }; | 1073 | }; |
@@ -1111,6 +1130,9 @@ remove_request: | |||
1111 | } | 1130 | } |
1112 | 1131 | ||
1113 | static const struct rpc_call_ops nfs_write_full_ops = { | 1132 | static const struct rpc_call_ops nfs_write_full_ops = { |
1133 | #if defined(CONFIG_NFS_V4_1) | ||
1134 | .rpc_call_prepare = nfs_write_prepare, | ||
1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
1114 | .rpc_call_done = nfs_writeback_done_full, | 1136 | .rpc_call_done = nfs_writeback_done_full, |
1115 | .rpc_release = nfs_writeback_release_full, | 1137 | .rpc_release = nfs_writeback_release_full, |
1116 | }; | 1138 | }; |
@@ -1123,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1123 | { | 1145 | { |
1124 | struct nfs_writeargs *argp = &data->args; | 1146 | struct nfs_writeargs *argp = &data->args; |
1125 | struct nfs_writeres *resp = &data->res; | 1147 | struct nfs_writeres *resp = &data->res; |
1148 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
1126 | int status; | 1149 | int status; |
1127 | 1150 | ||
1128 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1151 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
@@ -1155,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1155 | if (time_before(complain, jiffies)) { | 1178 | if (time_before(complain, jiffies)) { |
1156 | dprintk("NFS: faulty NFS server %s:" | 1179 | dprintk("NFS: faulty NFS server %s:" |
1157 | " (committed = %d) != (stable = %d)\n", | 1180 | " (committed = %d) != (stable = %d)\n", |
1158 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1181 | server->nfs_client->cl_hostname, |
1159 | resp->verf->committed, argp->stable); | 1182 | resp->verf->committed, argp->stable); |
1160 | complain = jiffies + 300 * HZ; | 1183 | complain = jiffies + 300 * HZ; |
1161 | } | 1184 | } |
@@ -1181,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1181 | */ | 1204 | */ |
1182 | argp->stable = NFS_FILE_SYNC; | 1205 | argp->stable = NFS_FILE_SYNC; |
1183 | } | 1206 | } |
1184 | rpc_restart_call(task); | 1207 | nfs4_restart_rpc(task, server->nfs_client); |
1185 | return -EAGAIN; | 1208 | return -EAGAIN; |
1186 | } | 1209 | } |
1187 | if (time_before(complain, jiffies)) { | 1210 | if (time_before(complain, jiffies)) { |
@@ -1193,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1193 | /* Can't do anything about it except throw an error. */ | 1216 | /* Can't do anything about it except throw an error. */ |
1194 | task->tk_status = -EIO; | 1217 | task->tk_status = -EIO; |
1195 | } | 1218 | } |
1219 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
1196 | return 0; | 1220 | return 0; |
1197 | } | 1221 | } |
1198 | 1222 | ||
@@ -1349,6 +1373,9 @@ static void nfs_commit_release(void *calldata) | |||
1349 | } | 1373 | } |
1350 | 1374 | ||
1351 | static const struct rpc_call_ops nfs_commit_ops = { | 1375 | static const struct rpc_call_ops nfs_commit_ops = { |
1376 | #if defined(CONFIG_NFS_V4_1) | ||
1377 | .rpc_call_prepare = nfs_write_prepare, | ||
1378 | #endif /* CONFIG_NFS_V4_1 */ | ||
1352 | .rpc_call_done = nfs_commit_done, | 1379 | .rpc_call_done = nfs_commit_done, |
1353 | .rpc_release = nfs_commit_release, | 1380 | .rpc_release = nfs_commit_release, |
1354 | }; | 1381 | }; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 8b1f8efb4690..b92a27629fb7 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -464,16 +464,11 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) | |||
464 | if (err) | 464 | if (err) |
465 | return err; | 465 | return err; |
466 | /* | 466 | /* |
467 | * Just a quick sanity check; we could also try to check | 467 | * XXX: It would be nice to also check whether this |
468 | * whether this pseudoflavor is supported, but at worst | 468 | * pseudoflavor is supported, so we can discover the |
469 | * an unsupported pseudoflavor on the export would just | 469 | * problem at export time instead of when a client fails |
470 | * be a pseudoflavor that won't match the flavor of any | 470 | * to authenticate. |
471 | * authenticated request. The administrator will | ||
472 | * probably discover the problem when someone fails to | ||
473 | * authenticate. | ||
474 | */ | 471 | */ |
475 | if (f->pseudoflavor < 0) | ||
476 | return -EINVAL; | ||
477 | err = get_int(mesg, &f->flags); | 472 | err = get_int(mesg, &f->flags); |
478 | if (err) | 473 | if (err) |
479 | return err; | 474 | return err; |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 7c9fe838f038..a713c418a922 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -652,8 +652,6 @@ nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp, | |||
652 | * NFSv3 Server procedures. | 652 | * NFSv3 Server procedures. |
653 | * Only the results of non-idempotent operations are cached. | 653 | * Only the results of non-idempotent operations are cached. |
654 | */ | 654 | */ |
655 | #define nfs3svc_decode_voidargs NULL | ||
656 | #define nfs3svc_release_void NULL | ||
657 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle | 655 | #define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle |
658 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat | 656 | #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat |
659 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat | 657 | #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat |
@@ -686,28 +684,219 @@ struct nfsd3_voidargs { int dummy; }; | |||
686 | #define WC (7+pAT) /* WCC attributes */ | 684 | #define WC (7+pAT) /* WCC attributes */ |
687 | 685 | ||
688 | static struct svc_procedure nfsd_procedures3[22] = { | 686 | static struct svc_procedure nfsd_procedures3[22] = { |
689 | PROC(null, void, void, void, RC_NOCACHE, ST), | 687 | [NFS3PROC_NULL] = { |
690 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 688 | .pc_func = (svc_procfunc) nfsd3_proc_null, |
691 | PROC(setattr, sattr, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 689 | .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres, |
692 | PROC(lookup, dirop, dirop, fhandle2, RC_NOCACHE, ST+FH+pAT+pAT), | 690 | .pc_argsize = sizeof(struct nfsd3_voidargs), |
693 | PROC(access, access, access, fhandle, RC_NOCACHE, ST+pAT+1), | 691 | .pc_ressize = sizeof(struct nfsd3_voidres), |
694 | PROC(readlink, readlink, readlink, fhandle, RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4), | 692 | .pc_cachetype = RC_NOCACHE, |
695 | PROC(read, read, read, fhandle, RC_NOCACHE, ST+pAT+4+NFSSVC_MAXBLKSIZE/4), | 693 | .pc_xdrressize = ST, |
696 | PROC(write, write, write, fhandle, RC_REPLBUFF, ST+WC+4), | 694 | }, |
697 | PROC(create, create, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 695 | [NFS3PROC_GETATTR] = { |
698 | PROC(mkdir, mkdir, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 696 | .pc_func = (svc_procfunc) nfsd3_proc_getattr, |
699 | PROC(symlink, symlink, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 697 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, |
700 | PROC(mknod, mknod, create, fhandle2, RC_REPLBUFF, ST+(1+FH+pAT)+WC), | 698 | .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres, |
701 | PROC(remove, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 699 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, |
702 | PROC(rmdir, dirop, wccstat, fhandle, RC_REPLBUFF, ST+WC), | 700 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), |
703 | PROC(rename, rename, rename, fhandle2, RC_REPLBUFF, ST+WC+WC), | 701 | .pc_ressize = sizeof(struct nfsd3_attrstatres), |
704 | PROC(link, link, link, fhandle2, RC_REPLBUFF, ST+pAT+WC), | 702 | .pc_cachetype = RC_NOCACHE, |
705 | PROC(readdir, readdir, readdir, fhandle, RC_NOCACHE, 0), | 703 | .pc_xdrressize = ST+AT, |
706 | PROC(readdirplus,readdirplus, readdir, fhandle, RC_NOCACHE, 0), | 704 | }, |
707 | PROC(fsstat, fhandle, fsstat, void, RC_NOCACHE, ST+pAT+2*6+1), | 705 | [NFS3PROC_SETATTR] = { |
708 | PROC(fsinfo, fhandle, fsinfo, void, RC_NOCACHE, ST+pAT+12), | 706 | .pc_func = (svc_procfunc) nfsd3_proc_setattr, |
709 | PROC(pathconf, fhandle, pathconf, void, RC_NOCACHE, ST+pAT+6), | 707 | .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs, |
710 | PROC(commit, commit, commit, fhandle, RC_NOCACHE, ST+WC+2), | 708 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, |
709 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
710 | .pc_argsize = sizeof(struct nfsd3_sattrargs), | ||
711 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
712 | .pc_cachetype = RC_REPLBUFF, | ||
713 | .pc_xdrressize = ST+WC, | ||
714 | }, | ||
715 | [NFS3PROC_LOOKUP] = { | ||
716 | .pc_func = (svc_procfunc) nfsd3_proc_lookup, | ||
717 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
718 | .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres, | ||
719 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
720 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
721 | .pc_ressize = sizeof(struct nfsd3_diropres), | ||
722 | .pc_cachetype = RC_NOCACHE, | ||
723 | .pc_xdrressize = ST+FH+pAT+pAT, | ||
724 | }, | ||
725 | [NFS3PROC_ACCESS] = { | ||
726 | .pc_func = (svc_procfunc) nfsd3_proc_access, | ||
727 | .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs, | ||
728 | .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres, | ||
729 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
730 | .pc_argsize = sizeof(struct nfsd3_accessargs), | ||
731 | .pc_ressize = sizeof(struct nfsd3_accessres), | ||
732 | .pc_cachetype = RC_NOCACHE, | ||
733 | .pc_xdrressize = ST+pAT+1, | ||
734 | }, | ||
735 | [NFS3PROC_READLINK] = { | ||
736 | .pc_func = (svc_procfunc) nfsd3_proc_readlink, | ||
737 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs, | ||
738 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres, | ||
739 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
740 | .pc_argsize = sizeof(struct nfsd3_readlinkargs), | ||
741 | .pc_ressize = sizeof(struct nfsd3_readlinkres), | ||
742 | .pc_cachetype = RC_NOCACHE, | ||
743 | .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, | ||
744 | }, | ||
745 | [NFS3PROC_READ] = { | ||
746 | .pc_func = (svc_procfunc) nfsd3_proc_read, | ||
747 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs, | ||
748 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readres, | ||
749 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
750 | .pc_argsize = sizeof(struct nfsd3_readargs), | ||
751 | .pc_ressize = sizeof(struct nfsd3_readres), | ||
752 | .pc_cachetype = RC_NOCACHE, | ||
753 | .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4, | ||
754 | }, | ||
755 | [NFS3PROC_WRITE] = { | ||
756 | .pc_func = (svc_procfunc) nfsd3_proc_write, | ||
757 | .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs, | ||
758 | .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres, | ||
759 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
760 | .pc_argsize = sizeof(struct nfsd3_writeargs), | ||
761 | .pc_ressize = sizeof(struct nfsd3_writeres), | ||
762 | .pc_cachetype = RC_REPLBUFF, | ||
763 | .pc_xdrressize = ST+WC+4, | ||
764 | }, | ||
765 | [NFS3PROC_CREATE] = { | ||
766 | .pc_func = (svc_procfunc) nfsd3_proc_create, | ||
767 | .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs, | ||
768 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
769 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
770 | .pc_argsize = sizeof(struct nfsd3_createargs), | ||
771 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
772 | .pc_cachetype = RC_REPLBUFF, | ||
773 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
774 | }, | ||
775 | [NFS3PROC_MKDIR] = { | ||
776 | .pc_func = (svc_procfunc) nfsd3_proc_mkdir, | ||
777 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs, | ||
778 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
779 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
780 | .pc_argsize = sizeof(struct nfsd3_mkdirargs), | ||
781 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
782 | .pc_cachetype = RC_REPLBUFF, | ||
783 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
784 | }, | ||
785 | [NFS3PROC_SYMLINK] = { | ||
786 | .pc_func = (svc_procfunc) nfsd3_proc_symlink, | ||
787 | .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs, | ||
788 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
789 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
790 | .pc_argsize = sizeof(struct nfsd3_symlinkargs), | ||
791 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
792 | .pc_cachetype = RC_REPLBUFF, | ||
793 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
794 | }, | ||
795 | [NFS3PROC_MKNOD] = { | ||
796 | .pc_func = (svc_procfunc) nfsd3_proc_mknod, | ||
797 | .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs, | ||
798 | .pc_encode = (kxdrproc_t) nfs3svc_encode_createres, | ||
799 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
800 | .pc_argsize = sizeof(struct nfsd3_mknodargs), | ||
801 | .pc_ressize = sizeof(struct nfsd3_createres), | ||
802 | .pc_cachetype = RC_REPLBUFF, | ||
803 | .pc_xdrressize = ST+(1+FH+pAT)+WC, | ||
804 | }, | ||
805 | [NFS3PROC_REMOVE] = { | ||
806 | .pc_func = (svc_procfunc) nfsd3_proc_remove, | ||
807 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
808 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
809 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
810 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
811 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
812 | .pc_cachetype = RC_REPLBUFF, | ||
813 | .pc_xdrressize = ST+WC, | ||
814 | }, | ||
815 | [NFS3PROC_RMDIR] = { | ||
816 | .pc_func = (svc_procfunc) nfsd3_proc_rmdir, | ||
817 | .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs, | ||
818 | .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres, | ||
819 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
820 | .pc_argsize = sizeof(struct nfsd3_diropargs), | ||
821 | .pc_ressize = sizeof(struct nfsd3_wccstatres), | ||
822 | .pc_cachetype = RC_REPLBUFF, | ||
823 | .pc_xdrressize = ST+WC, | ||
824 | }, | ||
825 | [NFS3PROC_RENAME] = { | ||
826 | .pc_func = (svc_procfunc) nfsd3_proc_rename, | ||
827 | .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs, | ||
828 | .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres, | ||
829 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
830 | .pc_argsize = sizeof(struct nfsd3_renameargs), | ||
831 | .pc_ressize = sizeof(struct nfsd3_renameres), | ||
832 | .pc_cachetype = RC_REPLBUFF, | ||
833 | .pc_xdrressize = ST+WC+WC, | ||
834 | }, | ||
835 | [NFS3PROC_LINK] = { | ||
836 | .pc_func = (svc_procfunc) nfsd3_proc_link, | ||
837 | .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs, | ||
838 | .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres, | ||
839 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2, | ||
840 | .pc_argsize = sizeof(struct nfsd3_linkargs), | ||
841 | .pc_ressize = sizeof(struct nfsd3_linkres), | ||
842 | .pc_cachetype = RC_REPLBUFF, | ||
843 | .pc_xdrressize = ST+pAT+WC, | ||
844 | }, | ||
845 | [NFS3PROC_READDIR] = { | ||
846 | .pc_func = (svc_procfunc) nfsd3_proc_readdir, | ||
847 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs, | ||
848 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
849 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
850 | .pc_argsize = sizeof(struct nfsd3_readdirargs), | ||
851 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
852 | .pc_cachetype = RC_NOCACHE, | ||
853 | }, | ||
854 | [NFS3PROC_READDIRPLUS] = { | ||
855 | .pc_func = (svc_procfunc) nfsd3_proc_readdirplus, | ||
856 | .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs, | ||
857 | .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres, | ||
858 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
859 | .pc_argsize = sizeof(struct nfsd3_readdirplusargs), | ||
860 | .pc_ressize = sizeof(struct nfsd3_readdirres), | ||
861 | .pc_cachetype = RC_NOCACHE, | ||
862 | }, | ||
863 | [NFS3PROC_FSSTAT] = { | ||
864 | .pc_func = (svc_procfunc) nfsd3_proc_fsstat, | ||
865 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
866 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres, | ||
867 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
868 | .pc_ressize = sizeof(struct nfsd3_fsstatres), | ||
869 | .pc_cachetype = RC_NOCACHE, | ||
870 | .pc_xdrressize = ST+pAT+2*6+1, | ||
871 | }, | ||
872 | [NFS3PROC_FSINFO] = { | ||
873 | .pc_func = (svc_procfunc) nfsd3_proc_fsinfo, | ||
874 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
875 | .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores, | ||
876 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
877 | .pc_ressize = sizeof(struct nfsd3_fsinfores), | ||
878 | .pc_cachetype = RC_NOCACHE, | ||
879 | .pc_xdrressize = ST+pAT+12, | ||
880 | }, | ||
881 | [NFS3PROC_PATHCONF] = { | ||
882 | .pc_func = (svc_procfunc) nfsd3_proc_pathconf, | ||
883 | .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs, | ||
884 | .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres, | ||
885 | .pc_argsize = sizeof(struct nfsd3_fhandleargs), | ||
886 | .pc_ressize = sizeof(struct nfsd3_pathconfres), | ||
887 | .pc_cachetype = RC_NOCACHE, | ||
888 | .pc_xdrressize = ST+pAT+6, | ||
889 | }, | ||
890 | [NFS3PROC_COMMIT] = { | ||
891 | .pc_func = (svc_procfunc) nfsd3_proc_commit, | ||
892 | .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs, | ||
893 | .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres, | ||
894 | .pc_release = (kxdrproc_t) nfs3svc_release_fhandle, | ||
895 | .pc_argsize = sizeof(struct nfsd3_commitargs), | ||
896 | .pc_ressize = sizeof(struct nfsd3_commitres), | ||
897 | .pc_cachetype = RC_NOCACHE, | ||
898 | .pc_xdrressize = ST+WC+2, | ||
899 | }, | ||
711 | }; | 900 | }; |
712 | 901 | ||
713 | struct svc_version nfsd_version3 = { | 902 | struct svc_version nfsd_version3 = { |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 17d0dd997204..01d4ec1c88e0 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -272,6 +272,7 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
272 | 272 | ||
273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 273 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
274 | &fhp->fh_post_attr); | 274 | &fhp->fh_post_attr); |
275 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | ||
275 | if (err) | 276 | if (err) |
276 | fhp->fh_post_saved = 0; | 277 | fhp->fh_post_saved = 0; |
277 | else | 278 | else |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 290289bd44f7..3fd23f7aceca 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -140,8 +140,10 @@ struct nfs4_cb_compound_hdr { | |||
140 | int status; | 140 | int status; |
141 | u32 ident; | 141 | u32 ident; |
142 | u32 nops; | 142 | u32 nops; |
143 | __be32 *nops_p; | ||
144 | u32 minorversion; | ||
143 | u32 taglen; | 145 | u32 taglen; |
144 | char * tag; | 146 | char *tag; |
145 | }; | 147 | }; |
146 | 148 | ||
147 | static struct { | 149 | static struct { |
@@ -201,33 +203,39 @@ nfs_cb_stat_to_errno(int stat) | |||
201 | * XDR encode | 203 | * XDR encode |
202 | */ | 204 | */ |
203 | 205 | ||
204 | static int | 206 | static void |
205 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) | 207 | encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) |
206 | { | 208 | { |
207 | __be32 * p; | 209 | __be32 * p; |
208 | 210 | ||
209 | RESERVE_SPACE(16); | 211 | RESERVE_SPACE(16); |
210 | WRITE32(0); /* tag length is always 0 */ | 212 | WRITE32(0); /* tag length is always 0 */ |
211 | WRITE32(NFS4_MINOR_VERSION); | 213 | WRITE32(hdr->minorversion); |
212 | WRITE32(hdr->ident); | 214 | WRITE32(hdr->ident); |
215 | hdr->nops_p = p; | ||
213 | WRITE32(hdr->nops); | 216 | WRITE32(hdr->nops); |
214 | return 0; | ||
215 | } | 217 | } |
216 | 218 | ||
217 | static int | 219 | static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr) |
218 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) | 220 | { |
221 | *hdr->nops_p = htonl(hdr->nops); | ||
222 | } | ||
223 | |||
224 | static void | ||
225 | encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | ||
226 | struct nfs4_cb_compound_hdr *hdr) | ||
219 | { | 227 | { |
220 | __be32 *p; | 228 | __be32 *p; |
221 | int len = cb_rec->cbr_fh.fh_size; | 229 | int len = dp->dl_fh.fh_size; |
222 | 230 | ||
223 | RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); | 231 | RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); |
224 | WRITE32(OP_CB_RECALL); | 232 | WRITE32(OP_CB_RECALL); |
225 | WRITE32(cb_rec->cbr_stateid.si_generation); | 233 | WRITE32(dp->dl_stateid.si_generation); |
226 | WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t)); | 234 | WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); |
227 | WRITE32(cb_rec->cbr_trunc); | 235 | WRITE32(0); /* truncate optimization not implemented */ |
228 | WRITE32(len); | 236 | WRITE32(len); |
229 | WRITEMEM(&cb_rec->cbr_fh.fh_base, len); | 237 | WRITEMEM(&dp->dl_fh.fh_base, len); |
230 | return 0; | 238 | hdr->nops++; |
231 | } | 239 | } |
232 | 240 | ||
233 | static int | 241 | static int |
@@ -241,17 +249,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | |||
241 | } | 249 | } |
242 | 250 | ||
243 | static int | 251 | static int |
244 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) | 252 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args) |
245 | { | 253 | { |
246 | struct xdr_stream xdr; | 254 | struct xdr_stream xdr; |
247 | struct nfs4_cb_compound_hdr hdr = { | 255 | struct nfs4_cb_compound_hdr hdr = { |
248 | .ident = args->cbr_ident, | 256 | .ident = args->dl_ident, |
249 | .nops = 1, | ||
250 | }; | 257 | }; |
251 | 258 | ||
252 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 259 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
253 | encode_cb_compound_hdr(&xdr, &hdr); | 260 | encode_cb_compound_hdr(&xdr, &hdr); |
254 | return (encode_cb_recall(&xdr, args)); | 261 | encode_cb_recall(&xdr, args, &hdr); |
262 | encode_cb_nops(&hdr); | ||
263 | return 0; | ||
255 | } | 264 | } |
256 | 265 | ||
257 | 266 | ||
@@ -358,18 +367,21 @@ static struct rpc_program cb_program = { | |||
358 | .pipe_dir_name = "/nfsd4_cb", | 367 | .pipe_dir_name = "/nfsd4_cb", |
359 | }; | 368 | }; |
360 | 369 | ||
370 | static int max_cb_time(void) | ||
371 | { | ||
372 | return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ; | ||
373 | } | ||
374 | |||
361 | /* Reference counting, callback cleanup, etc., all look racy as heck. | 375 | /* Reference counting, callback cleanup, etc., all look racy as heck. |
362 | * And why is cb_set an atomic? */ | 376 | * And why is cb_set an atomic? */ |
363 | 377 | ||
364 | static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | 378 | int setup_callback_client(struct nfs4_client *clp) |
365 | { | 379 | { |
366 | struct sockaddr_in addr; | 380 | struct sockaddr_in addr; |
367 | struct nfs4_callback *cb = &clp->cl_callback; | 381 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
368 | struct rpc_timeout timeparms = { | 382 | struct rpc_timeout timeparms = { |
369 | .to_initval = (NFSD_LEASE_TIME/4) * HZ, | 383 | .to_initval = max_cb_time(), |
370 | .to_retries = 5, | 384 | .to_retries = 0, |
371 | .to_maxval = (NFSD_LEASE_TIME/2) * HZ, | ||
372 | .to_exponential = 1, | ||
373 | }; | 385 | }; |
374 | struct rpc_create_args args = { | 386 | struct rpc_create_args args = { |
375 | .protocol = IPPROTO_TCP, | 387 | .protocol = IPPROTO_TCP, |
@@ -386,7 +398,7 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
386 | struct rpc_clnt *client; | 398 | struct rpc_clnt *client; |
387 | 399 | ||
388 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 400 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) |
389 | return ERR_PTR(-EINVAL); | 401 | return -EINVAL; |
390 | 402 | ||
391 | /* Initialize address */ | 403 | /* Initialize address */ |
392 | memset(&addr, 0, sizeof(addr)); | 404 | memset(&addr, 0, sizeof(addr)); |
@@ -396,48 +408,77 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) | |||
396 | 408 | ||
397 | /* Create RPC client */ | 409 | /* Create RPC client */ |
398 | client = rpc_create(&args); | 410 | client = rpc_create(&args); |
399 | if (IS_ERR(client)) | 411 | if (IS_ERR(client)) { |
400 | dprintk("NFSD: couldn't create callback client: %ld\n", | 412 | dprintk("NFSD: couldn't create callback client: %ld\n", |
401 | PTR_ERR(client)); | 413 | PTR_ERR(client)); |
402 | return client; | 414 | return PTR_ERR(client); |
415 | } | ||
416 | cb->cb_client = client; | ||
417 | return 0; | ||
418 | |||
419 | } | ||
420 | |||
421 | static void warn_no_callback_path(struct nfs4_client *clp, int reason) | ||
422 | { | ||
423 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
424 | (int)clp->cl_name.len, clp->cl_name.data, reason); | ||
425 | } | ||
426 | |||
427 | static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) | ||
428 | { | ||
429 | struct nfs4_client *clp = calldata; | ||
430 | |||
431 | if (task->tk_status) | ||
432 | warn_no_callback_path(clp, task->tk_status); | ||
433 | else | ||
434 | atomic_set(&clp->cl_cb_conn.cb_set, 1); | ||
435 | put_nfs4_client(clp); | ||
436 | } | ||
437 | |||
438 | static const struct rpc_call_ops nfsd4_cb_probe_ops = { | ||
439 | .rpc_call_done = nfsd4_cb_probe_done, | ||
440 | }; | ||
403 | 441 | ||
442 | static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb) | ||
443 | { | ||
444 | struct auth_cred acred = { | ||
445 | .machine_cred = 1 | ||
446 | }; | ||
447 | |||
448 | /* | ||
449 | * Note in the gss case this doesn't actually have to wait for a | ||
450 | * gss upcall (or any calls to the client); this just creates a | ||
451 | * non-uptodate cred which the rpc state machine will fill in with | ||
452 | * a refresh_upcall later. | ||
453 | */ | ||
454 | return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred, | ||
455 | RPCAUTH_LOOKUP_NEW); | ||
404 | } | 456 | } |
405 | 457 | ||
406 | static int do_probe_callback(void *data) | 458 | void do_probe_callback(struct nfs4_client *clp) |
407 | { | 459 | { |
408 | struct nfs4_client *clp = data; | 460 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
409 | struct nfs4_callback *cb = &clp->cl_callback; | ||
410 | struct rpc_message msg = { | 461 | struct rpc_message msg = { |
411 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 462 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
412 | .rpc_argp = clp, | 463 | .rpc_argp = clp, |
413 | }; | 464 | }; |
414 | struct rpc_clnt *client; | 465 | struct rpc_cred *cred; |
415 | int status; | 466 | int status; |
416 | 467 | ||
417 | client = setup_callback_client(clp); | 468 | cred = lookup_cb_cred(cb); |
418 | if (IS_ERR(client)) { | 469 | if (IS_ERR(cred)) { |
419 | status = PTR_ERR(client); | 470 | status = PTR_ERR(cred); |
420 | dprintk("NFSD: couldn't create callback client: %d\n", | 471 | goto out; |
421 | status); | 472 | } |
422 | goto out_err; | 473 | cb->cb_cred = cred; |
474 | msg.rpc_cred = cb->cb_cred; | ||
475 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, | ||
476 | &nfsd4_cb_probe_ops, (void *)clp); | ||
477 | out: | ||
478 | if (status) { | ||
479 | warn_no_callback_path(clp, status); | ||
480 | put_nfs4_client(clp); | ||
423 | } | 481 | } |
424 | |||
425 | status = rpc_call_sync(client, &msg, RPC_TASK_SOFT); | ||
426 | |||
427 | if (status) | ||
428 | goto out_release_client; | ||
429 | |||
430 | cb->cb_client = client; | ||
431 | atomic_set(&cb->cb_set, 1); | ||
432 | put_nfs4_client(clp); | ||
433 | return 0; | ||
434 | out_release_client: | ||
435 | rpc_shutdown_client(client); | ||
436 | out_err: | ||
437 | dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", | ||
438 | (int)clp->cl_name.len, clp->cl_name.data, status); | ||
439 | put_nfs4_client(clp); | ||
440 | return 0; | ||
441 | } | 482 | } |
442 | 483 | ||
443 | /* | 484 | /* |
@@ -446,21 +487,65 @@ out_err: | |||
446 | void | 487 | void |
447 | nfsd4_probe_callback(struct nfs4_client *clp) | 488 | nfsd4_probe_callback(struct nfs4_client *clp) |
448 | { | 489 | { |
449 | struct task_struct *t; | 490 | int status; |
450 | 491 | ||
451 | BUG_ON(atomic_read(&clp->cl_callback.cb_set)); | 492 | BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set)); |
493 | |||
494 | status = setup_callback_client(clp); | ||
495 | if (status) { | ||
496 | warn_no_callback_path(clp, status); | ||
497 | return; | ||
498 | } | ||
452 | 499 | ||
453 | /* the task holds a reference to the nfs4_client struct */ | 500 | /* the task holds a reference to the nfs4_client struct */ |
454 | atomic_inc(&clp->cl_count); | 501 | atomic_inc(&clp->cl_count); |
455 | 502 | ||
456 | t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); | 503 | do_probe_callback(clp); |
504 | } | ||
457 | 505 | ||
458 | if (IS_ERR(t)) | 506 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
459 | atomic_dec(&clp->cl_count); | 507 | { |
508 | struct nfs4_delegation *dp = calldata; | ||
509 | struct nfs4_client *clp = dp->dl_client; | ||
460 | 510 | ||
461 | return; | 511 | switch (task->tk_status) { |
512 | case -EIO: | ||
513 | /* Network partition? */ | ||
514 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
515 | warn_no_callback_path(clp, task->tk_status); | ||
516 | case -EBADHANDLE: | ||
517 | case -NFS4ERR_BAD_STATEID: | ||
518 | /* Race: client probably got cb_recall | ||
519 | * before open reply granting delegation */ | ||
520 | break; | ||
521 | default: | ||
522 | /* success, or error we can't handle */ | ||
523 | return; | ||
524 | } | ||
525 | if (dp->dl_retries--) { | ||
526 | rpc_delay(task, 2*HZ); | ||
527 | task->tk_status = 0; | ||
528 | rpc_restart_call(task); | ||
529 | } else { | ||
530 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
531 | warn_no_callback_path(clp, task->tk_status); | ||
532 | } | ||
533 | } | ||
534 | |||
535 | static void nfsd4_cb_recall_release(void *calldata) | ||
536 | { | ||
537 | struct nfs4_delegation *dp = calldata; | ||
538 | struct nfs4_client *clp = dp->dl_client; | ||
539 | |||
540 | nfs4_put_delegation(dp); | ||
541 | put_nfs4_client(clp); | ||
462 | } | 542 | } |
463 | 543 | ||
544 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | ||
545 | .rpc_call_done = nfsd4_cb_recall_done, | ||
546 | .rpc_release = nfsd4_cb_recall_release, | ||
547 | }; | ||
548 | |||
464 | /* | 549 | /* |
465 | * called with dp->dl_count inc'ed. | 550 | * called with dp->dl_count inc'ed. |
466 | */ | 551 | */ |
@@ -468,41 +553,19 @@ void | |||
468 | nfsd4_cb_recall(struct nfs4_delegation *dp) | 553 | nfsd4_cb_recall(struct nfs4_delegation *dp) |
469 | { | 554 | { |
470 | struct nfs4_client *clp = dp->dl_client; | 555 | struct nfs4_client *clp = dp->dl_client; |
471 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 556 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
472 | struct nfs4_cb_recall *cbr = &dp->dl_recall; | ||
473 | struct rpc_message msg = { | 557 | struct rpc_message msg = { |
474 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 558 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
475 | .rpc_argp = cbr, | 559 | .rpc_argp = dp, |
560 | .rpc_cred = clp->cl_cb_conn.cb_cred | ||
476 | }; | 561 | }; |
477 | int retries = 1; | 562 | int status; |
478 | int status = 0; | 563 | |
479 | 564 | dp->dl_retries = 1; | |
480 | cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ | 565 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, |
481 | cbr->cbr_dp = dp; | 566 | &nfsd4_cb_recall_ops, dp); |
482 | 567 | if (status) { | |
483 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | 568 | put_nfs4_client(clp); |
484 | while (retries--) { | 569 | nfs4_put_delegation(dp); |
485 | switch (status) { | ||
486 | case -EIO: | ||
487 | /* Network partition? */ | ||
488 | atomic_set(&clp->cl_callback.cb_set, 0); | ||
489 | case -EBADHANDLE: | ||
490 | case -NFS4ERR_BAD_STATEID: | ||
491 | /* Race: client probably got cb_recall | ||
492 | * before open reply granting delegation */ | ||
493 | break; | ||
494 | default: | ||
495 | goto out_put_cred; | ||
496 | } | ||
497 | ssleep(2); | ||
498 | status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); | ||
499 | } | 570 | } |
500 | out_put_cred: | ||
501 | /* | ||
502 | * Success or failure, now we're either waiting for lease expiration | ||
503 | * or deleg_return. | ||
504 | */ | ||
505 | put_nfs4_client(clp); | ||
506 | nfs4_put_delegation(dp); | ||
507 | return; | ||
508 | } | 571 | } |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b2883e9c6381..7c8801769a3c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -51,6 +51,78 @@ | |||
51 | 51 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 53 | ||
54 | static u32 nfsd_attrmask[] = { | ||
55 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
56 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
57 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
58 | }; | ||
59 | |||
60 | static u32 nfsd41_ex_attrmask[] = { | ||
61 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
62 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
63 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
64 | }; | ||
65 | |||
66 | static __be32 | ||
67 | check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
68 | u32 *bmval, u32 *writable) | ||
69 | { | ||
70 | struct dentry *dentry = cstate->current_fh.fh_dentry; | ||
71 | struct svc_export *exp = cstate->current_fh.fh_export; | ||
72 | |||
73 | /* | ||
74 | * Check about attributes are supported by the NFSv4 server or not. | ||
75 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP. | ||
76 | */ | ||
77 | if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) || | ||
78 | (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) || | ||
79 | (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | ||
80 | return nfserr_attrnotsupp; | ||
81 | |||
82 | /* | ||
83 | * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported | ||
84 | * in current environment or not. | ||
85 | */ | ||
86 | if (bmval[0] & FATTR4_WORD0_ACL) { | ||
87 | if (!IS_POSIXACL(dentry->d_inode)) | ||
88 | return nfserr_attrnotsupp; | ||
89 | } | ||
90 | if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) { | ||
91 | if (exp->ex_fslocs.locations == NULL) | ||
92 | return nfserr_attrnotsupp; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * According to spec, read-only attributes return ERR_INVAL. | ||
97 | */ | ||
98 | if (writable) { | ||
99 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
100 | (bmval[2] & ~writable[2])) | ||
101 | return nfserr_inval; | ||
102 | } | ||
103 | |||
104 | return nfs_ok; | ||
105 | } | ||
106 | |||
107 | static __be32 | ||
108 | nfsd4_check_open_attributes(struct svc_rqst *rqstp, | ||
109 | struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
110 | { | ||
111 | __be32 status = nfs_ok; | ||
112 | |||
113 | if (open->op_create == NFS4_OPEN_CREATE) { | ||
114 | if (open->op_createmode == NFS4_CREATE_UNCHECKED | ||
115 | || open->op_createmode == NFS4_CREATE_GUARDED) | ||
116 | status = check_attr_support(rqstp, cstate, | ||
117 | open->op_bmval, nfsd_attrmask); | ||
118 | else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1) | ||
119 | status = check_attr_support(rqstp, cstate, | ||
120 | open->op_bmval, nfsd41_ex_attrmask); | ||
121 | } | ||
122 | |||
123 | return status; | ||
124 | } | ||
125 | |||
54 | static inline void | 126 | static inline void |
55 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 127 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
56 | { | 128 | { |
@@ -225,6 +297,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
225 | if (status) | 297 | if (status) |
226 | goto out; | 298 | goto out; |
227 | 299 | ||
300 | status = nfsd4_check_open_attributes(rqstp, cstate, open); | ||
301 | if (status) | ||
302 | goto out; | ||
303 | |||
228 | /* Openowner is now set, so sequence id will get bumped. Now we need | 304 | /* Openowner is now set, so sequence id will get bumped. Now we need |
229 | * these checks before we do any creates: */ | 305 | * these checks before we do any creates: */ |
230 | status = nfserr_grace; | 306 | status = nfserr_grace; |
@@ -395,6 +471,11 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
395 | if (status) | 471 | if (status) |
396 | return status; | 472 | return status; |
397 | 473 | ||
474 | status = check_attr_support(rqstp, cstate, create->cr_bmval, | ||
475 | nfsd_attrmask); | ||
476 | if (status) | ||
477 | return status; | ||
478 | |||
398 | switch (create->cr_type) { | 479 | switch (create->cr_type) { |
399 | case NF4LNK: | 480 | case NF4LNK: |
400 | /* ugh! we have to null-terminate the linktext, or | 481 | /* ugh! we have to null-terminate the linktext, or |
@@ -689,6 +770,12 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
689 | if (status) | 770 | if (status) |
690 | return status; | 771 | return status; |
691 | status = nfs_ok; | 772 | status = nfs_ok; |
773 | |||
774 | status = check_attr_support(rqstp, cstate, setattr->sa_bmval, | ||
775 | nfsd_attrmask); | ||
776 | if (status) | ||
777 | goto out; | ||
778 | |||
692 | if (setattr->sa_acl != NULL) | 779 | if (setattr->sa_acl != NULL) |
693 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, | 780 | status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, |
694 | setattr->sa_acl); | 781 | setattr->sa_acl); |
@@ -763,10 +850,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
763 | if (status) | 850 | if (status) |
764 | return status; | 851 | return status; |
765 | 852 | ||
766 | if ((verify->ve_bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) | 853 | status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL); |
767 | || (verify->ve_bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) | 854 | if (status) |
768 | || (verify->ve_bmval[2] & ~nfsd_suppattrs2(cstate->minorversion))) | 855 | return status; |
769 | return nfserr_attrnotsupp; | 856 | |
770 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) | 857 | if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) |
771 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) | 858 | || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) |
772 | return nfserr_inval; | 859 | return nfserr_inval; |
@@ -1226,24 +1313,9 @@ static const char *nfsd4_op_name(unsigned opnum) | |||
1226 | return "unknown_operation"; | 1313 | return "unknown_operation"; |
1227 | } | 1314 | } |
1228 | 1315 | ||
1229 | #define nfs4svc_decode_voidargs NULL | ||
1230 | #define nfs4svc_release_void NULL | ||
1231 | #define nfsd4_voidres nfsd4_voidargs | 1316 | #define nfsd4_voidres nfsd4_voidargs |
1232 | #define nfs4svc_release_compound NULL | ||
1233 | struct nfsd4_voidargs { int dummy; }; | 1317 | struct nfsd4_voidargs { int dummy; }; |
1234 | 1318 | ||
1235 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
1236 | { (svc_procfunc) nfsd4_proc_##name, \ | ||
1237 | (kxdrproc_t) nfs4svc_decode_##argt##args, \ | ||
1238 | (kxdrproc_t) nfs4svc_encode_##rest##res, \ | ||
1239 | (kxdrproc_t) nfs4svc_release_##relt, \ | ||
1240 | sizeof(struct nfsd4_##argt##args), \ | ||
1241 | sizeof(struct nfsd4_##rest##res), \ | ||
1242 | 0, \ | ||
1243 | cache, \ | ||
1244 | respsize, \ | ||
1245 | } | ||
1246 | |||
1247 | /* | 1319 | /* |
1248 | * TODO: At the present time, the NFSv4 server does not do XID caching | 1320 | * TODO: At the present time, the NFSv4 server does not do XID caching |
1249 | * of requests. Implementing XID caching would not be a serious problem, | 1321 | * of requests. Implementing XID caching would not be a serious problem, |
@@ -1255,8 +1327,23 @@ struct nfsd4_voidargs { int dummy; }; | |||
1255 | * better XID's. | 1327 | * better XID's. |
1256 | */ | 1328 | */ |
1257 | static struct svc_procedure nfsd_procedures4[2] = { | 1329 | static struct svc_procedure nfsd_procedures4[2] = { |
1258 | PROC(null, void, void, void, RC_NOCACHE, 1), | 1330 | [NFSPROC4_NULL] = { |
1259 | PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4) | 1331 | .pc_func = (svc_procfunc) nfsd4_proc_null, |
1332 | .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres, | ||
1333 | .pc_argsize = sizeof(struct nfsd4_voidargs), | ||
1334 | .pc_ressize = sizeof(struct nfsd4_voidres), | ||
1335 | .pc_cachetype = RC_NOCACHE, | ||
1336 | .pc_xdrressize = 1, | ||
1337 | }, | ||
1338 | [NFSPROC4_COMPOUND] = { | ||
1339 | .pc_func = (svc_procfunc) nfsd4_proc_compound, | ||
1340 | .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs, | ||
1341 | .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres, | ||
1342 | .pc_argsize = sizeof(struct nfsd4_compoundargs), | ||
1343 | .pc_ressize = sizeof(struct nfsd4_compoundres), | ||
1344 | .pc_cachetype = RC_NOCACHE, | ||
1345 | .pc_xdrressize = NFSD_BUFSIZE/4, | ||
1346 | }, | ||
1260 | }; | 1347 | }; |
1261 | 1348 | ||
1262 | struct svc_version nfsd_version4 = { | 1349 | struct svc_version nfsd_version4 = { |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3b711f5147a7..980a216a48c8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -182,7 +182,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
182 | { | 182 | { |
183 | struct nfs4_delegation *dp; | 183 | struct nfs4_delegation *dp; |
184 | struct nfs4_file *fp = stp->st_file; | 184 | struct nfs4_file *fp = stp->st_file; |
185 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 185 | struct nfs4_cb_conn *cb = &stp->st_stateowner->so_client->cl_cb_conn; |
186 | 186 | ||
187 | dprintk("NFSD alloc_init_deleg\n"); | 187 | dprintk("NFSD alloc_init_deleg\n"); |
188 | if (fp->fi_had_conflict) | 188 | if (fp->fi_had_conflict) |
@@ -203,10 +203,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
203 | get_file(stp->st_vfs_file); | 203 | get_file(stp->st_vfs_file); |
204 | dp->dl_vfs_file = stp->st_vfs_file; | 204 | dp->dl_vfs_file = stp->st_vfs_file; |
205 | dp->dl_type = type; | 205 | dp->dl_type = type; |
206 | dp->dl_recall.cbr_dp = NULL; | 206 | dp->dl_ident = cb->cb_ident; |
207 | dp->dl_recall.cbr_ident = cb->cb_ident; | 207 | dp->dl_stateid.si_boot = get_seconds(); |
208 | dp->dl_recall.cbr_trunc = 0; | ||
209 | dp->dl_stateid.si_boot = boot_time; | ||
210 | dp->dl_stateid.si_stateownerid = current_delegid++; | 208 | dp->dl_stateid.si_stateownerid = current_delegid++; |
211 | dp->dl_stateid.si_fileid = 0; | 209 | dp->dl_stateid.si_fileid = 0; |
212 | dp->dl_stateid.si_generation = 0; | 210 | dp->dl_stateid.si_generation = 0; |
@@ -427,6 +425,11 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
427 | { | 425 | { |
428 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | 426 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; |
429 | 427 | ||
428 | if (fchan->maxreqs < 1) | ||
429 | return nfserr_inval; | ||
430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
432 | |||
430 | spin_lock(&nfsd_serv->sv_lock); | 433 | spin_lock(&nfsd_serv->sv_lock); |
431 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | 434 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) |
432 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | 435 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; |
@@ -446,8 +449,8 @@ static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | |||
446 | * fchan holds the client values on input, and the server values on output | 449 | * fchan holds the client values on input, and the server values on output |
447 | */ | 450 | */ |
448 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | 451 | static int init_forechannel_attrs(struct svc_rqst *rqstp, |
449 | struct nfsd4_session *session, | 452 | struct nfsd4_channel_attrs *session_fchan, |
450 | struct nfsd4_channel_attrs *fchan) | 453 | struct nfsd4_channel_attrs *fchan) |
451 | { | 454 | { |
452 | int status = 0; | 455 | int status = 0; |
453 | __u32 maxcount = svc_max_payload(rqstp); | 456 | __u32 maxcount = svc_max_payload(rqstp); |
@@ -457,21 +460,21 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
457 | /* Use the client's max request and max response size if possible */ | 460 | /* Use the client's max request and max response size if possible */ |
458 | if (fchan->maxreq_sz > maxcount) | 461 | if (fchan->maxreq_sz > maxcount) |
459 | fchan->maxreq_sz = maxcount; | 462 | fchan->maxreq_sz = maxcount; |
460 | session->se_fmaxreq_sz = fchan->maxreq_sz; | 463 | session_fchan->maxreq_sz = fchan->maxreq_sz; |
461 | 464 | ||
462 | if (fchan->maxresp_sz > maxcount) | 465 | if (fchan->maxresp_sz > maxcount) |
463 | fchan->maxresp_sz = maxcount; | 466 | fchan->maxresp_sz = maxcount; |
464 | session->se_fmaxresp_sz = fchan->maxresp_sz; | 467 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
465 | 468 | ||
466 | /* Set the max response cached size our default which is | 469 | /* Set the max response cached size our default which is |
467 | * a multiple of PAGE_SIZE and small */ | 470 | * a multiple of PAGE_SIZE and small */ |
468 | session->se_fmaxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | 471 | session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; |
469 | fchan->maxresp_cached = session->se_fmaxresp_cached; | 472 | fchan->maxresp_cached = session_fchan->maxresp_cached; |
470 | 473 | ||
471 | /* Use the client's maxops if possible */ | 474 | /* Use the client's maxops if possible */ |
472 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 475 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
473 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 476 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
474 | session->se_fmaxops = fchan->maxops; | 477 | session_fchan->maxops = fchan->maxops; |
475 | 478 | ||
476 | /* try to use the client requested number of slots */ | 479 | /* try to use the client requested number of slots */ |
477 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | 480 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) |
@@ -483,7 +486,7 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
483 | */ | 486 | */ |
484 | status = set_forechannel_maxreqs(fchan); | 487 | status = set_forechannel_maxreqs(fchan); |
485 | 488 | ||
486 | session->se_fnumslots = fchan->maxreqs; | 489 | session_fchan->maxreqs = fchan->maxreqs; |
487 | return status; | 490 | return status; |
488 | } | 491 | } |
489 | 492 | ||
@@ -497,12 +500,14 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
497 | memset(&tmp, 0, sizeof(tmp)); | 500 | memset(&tmp, 0, sizeof(tmp)); |
498 | 501 | ||
499 | /* FIXME: For now, we just accept the client back channel attributes. */ | 502 | /* FIXME: For now, we just accept the client back channel attributes. */ |
500 | status = init_forechannel_attrs(rqstp, &tmp, &cses->fore_channel); | 503 | tmp.se_bchannel = cses->back_channel; |
504 | status = init_forechannel_attrs(rqstp, &tmp.se_fchannel, | ||
505 | &cses->fore_channel); | ||
501 | if (status) | 506 | if (status) |
502 | goto out; | 507 | goto out; |
503 | 508 | ||
504 | /* allocate struct nfsd4_session and slot table in one piece */ | 509 | /* allocate struct nfsd4_session and slot table in one piece */ |
505 | slotsize = tmp.se_fnumslots * sizeof(struct nfsd4_slot); | 510 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot); |
506 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 511 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
507 | if (!new) | 512 | if (!new) |
508 | goto out; | 513 | goto out; |
@@ -576,7 +581,7 @@ free_session(struct kref *kref) | |||
576 | int i; | 581 | int i; |
577 | 582 | ||
578 | ses = container_of(kref, struct nfsd4_session, se_ref); | 583 | ses = container_of(kref, struct nfsd4_session, se_ref); |
579 | for (i = 0; i < ses->se_fnumslots; i++) { | 584 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { |
580 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | 585 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; |
581 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | 586 | nfsd4_release_respages(e->ce_respages, e->ce_resused); |
582 | } | 587 | } |
@@ -632,16 +637,20 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
632 | static void | 637 | static void |
633 | shutdown_callback_client(struct nfs4_client *clp) | 638 | shutdown_callback_client(struct nfs4_client *clp) |
634 | { | 639 | { |
635 | struct rpc_clnt *clnt = clp->cl_callback.cb_client; | 640 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
636 | 641 | ||
637 | if (clnt) { | 642 | if (clnt) { |
638 | /* | 643 | /* |
639 | * Callback threads take a reference on the client, so there | 644 | * Callback threads take a reference on the client, so there |
640 | * should be no outstanding callbacks at this point. | 645 | * should be no outstanding callbacks at this point. |
641 | */ | 646 | */ |
642 | clp->cl_callback.cb_client = NULL; | 647 | clp->cl_cb_conn.cb_client = NULL; |
643 | rpc_shutdown_client(clnt); | 648 | rpc_shutdown_client(clnt); |
644 | } | 649 | } |
650 | if (clp->cl_cb_conn.cb_cred) { | ||
651 | put_rpccred(clp->cl_cb_conn.cb_cred); | ||
652 | clp->cl_cb_conn.cb_cred = NULL; | ||
653 | } | ||
645 | } | 654 | } |
646 | 655 | ||
647 | static inline void | 656 | static inline void |
@@ -714,7 +723,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | |||
714 | return NULL; | 723 | return NULL; |
715 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | 724 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); |
716 | atomic_set(&clp->cl_count, 1); | 725 | atomic_set(&clp->cl_count, 1); |
717 | atomic_set(&clp->cl_callback.cb_set, 0); | 726 | atomic_set(&clp->cl_cb_conn.cb_set, 0); |
718 | INIT_LIST_HEAD(&clp->cl_idhash); | 727 | INIT_LIST_HEAD(&clp->cl_idhash); |
719 | INIT_LIST_HEAD(&clp->cl_strhash); | 728 | INIT_LIST_HEAD(&clp->cl_strhash); |
720 | INIT_LIST_HEAD(&clp->cl_openowners); | 729 | INIT_LIST_HEAD(&clp->cl_openowners); |
@@ -966,7 +975,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne | |||
966 | static void | 975 | static void |
967 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 976 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) |
968 | { | 977 | { |
969 | struct nfs4_callback *cb = &clp->cl_callback; | 978 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
970 | 979 | ||
971 | /* Currently, we only support tcp for the callback channel */ | 980 | /* Currently, we only support tcp for the callback channel */ |
972 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) | 981 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) |
@@ -975,6 +984,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
975 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, | 984 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, |
976 | &cb->cb_addr, &cb->cb_port))) | 985 | &cb->cb_addr, &cb->cb_port))) |
977 | goto out_err; | 986 | goto out_err; |
987 | cb->cb_minorversion = 0; | ||
978 | cb->cb_prog = se->se_callback_prog; | 988 | cb->cb_prog = se->se_callback_prog; |
979 | cb->cb_ident = se->se_callback_ident; | 989 | cb->cb_ident = se->se_callback_ident; |
980 | return; | 990 | return; |
@@ -1128,7 +1138,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | |||
1128 | * is sent (lease renewal). | 1138 | * is sent (lease renewal). |
1129 | */ | 1139 | */ |
1130 | if (seq && nfsd4_not_cached(resp)) { | 1140 | if (seq && nfsd4_not_cached(resp)) { |
1131 | seq->maxslots = resp->cstate.session->se_fnumslots; | 1141 | seq->maxslots = resp->cstate.session->se_fchannel.maxreqs; |
1132 | return nfs_ok; | 1142 | return nfs_ok; |
1133 | } | 1143 | } |
1134 | 1144 | ||
@@ -1238,12 +1248,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1238 | expire_client(conf); | 1248 | expire_client(conf); |
1239 | goto out_new; | 1249 | goto out_new; |
1240 | } | 1250 | } |
1241 | if (ip_addr != conf->cl_addr && | ||
1242 | !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) { | ||
1243 | /* Client collision. 18.35.4 case 3 */ | ||
1244 | status = nfserr_clid_inuse; | ||
1245 | goto out; | ||
1246 | } | ||
1247 | /* | 1251 | /* |
1248 | * Set bit when the owner id and verifier map to an already | 1252 | * Set bit when the owner id and verifier map to an already |
1249 | * confirmed client id (18.35.3). | 1253 | * confirmed client id (18.35.3). |
@@ -1257,12 +1261,12 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1257 | copy_verf(conf, &verf); | 1261 | copy_verf(conf, &verf); |
1258 | new = conf; | 1262 | new = conf; |
1259 | goto out_copy; | 1263 | goto out_copy; |
1260 | } else { | 1264 | } |
1261 | /* 18.35.4 case 7 */ | 1265 | |
1262 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | 1266 | /* 18.35.4 case 7 */ |
1263 | status = nfserr_noent; | 1267 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
1264 | goto out; | 1268 | status = nfserr_noent; |
1265 | } | 1269 | goto out; |
1266 | } | 1270 | } |
1267 | 1271 | ||
1268 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | 1272 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); |
@@ -1471,7 +1475,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1471 | goto out; | 1475 | goto out; |
1472 | 1476 | ||
1473 | status = nfserr_badslot; | 1477 | status = nfserr_badslot; |
1474 | if (seq->slotid >= session->se_fnumslots) | 1478 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1475 | goto out; | 1479 | goto out; |
1476 | 1480 | ||
1477 | slot = &session->se_slots[seq->slotid]; | 1481 | slot = &session->se_slots[seq->slotid]; |
@@ -1686,9 +1690,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1686 | else { | 1690 | else { |
1687 | /* XXX: We just turn off callbacks until we can handle | 1691 | /* XXX: We just turn off callbacks until we can handle |
1688 | * change request correctly. */ | 1692 | * change request correctly. */ |
1689 | atomic_set(&conf->cl_callback.cb_set, 0); | 1693 | atomic_set(&conf->cl_cb_conn.cb_set, 0); |
1690 | gen_confirm(conf); | ||
1691 | nfsd4_remove_clid_dir(unconf); | ||
1692 | expire_client(unconf); | 1694 | expire_client(unconf); |
1693 | status = nfs_ok; | 1695 | status = nfs_ok; |
1694 | 1696 | ||
@@ -1882,7 +1884,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1882 | stp->st_stateowner = sop; | 1884 | stp->st_stateowner = sop; |
1883 | get_nfs4_file(fp); | 1885 | get_nfs4_file(fp); |
1884 | stp->st_file = fp; | 1886 | stp->st_file = fp; |
1885 | stp->st_stateid.si_boot = boot_time; | 1887 | stp->st_stateid.si_boot = get_seconds(); |
1886 | stp->st_stateid.si_stateownerid = sop->so_id; | 1888 | stp->st_stateid.si_stateownerid = sop->so_id; |
1887 | stp->st_stateid.si_fileid = fp->fi_id; | 1889 | stp->st_stateid.si_fileid = fp->fi_id; |
1888 | stp->st_stateid.si_generation = 0; | 1890 | stp->st_stateid.si_generation = 0; |
@@ -2059,19 +2061,6 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access) | |||
2059 | } | 2061 | } |
2060 | 2062 | ||
2061 | /* | 2063 | /* |
2062 | * Recall a delegation | ||
2063 | */ | ||
2064 | static int | ||
2065 | do_recall(void *__dp) | ||
2066 | { | ||
2067 | struct nfs4_delegation *dp = __dp; | ||
2068 | |||
2069 | dp->dl_file->fi_had_conflict = true; | ||
2070 | nfsd4_cb_recall(dp); | ||
2071 | return 0; | ||
2072 | } | ||
2073 | |||
2074 | /* | ||
2075 | * Spawn a thread to perform a recall on the delegation represented | 2064 | * Spawn a thread to perform a recall on the delegation represented |
2076 | * by the lease (file_lock) | 2065 | * by the lease (file_lock) |
2077 | * | 2066 | * |
@@ -2082,8 +2071,7 @@ do_recall(void *__dp) | |||
2082 | static | 2071 | static |
2083 | void nfsd_break_deleg_cb(struct file_lock *fl) | 2072 | void nfsd_break_deleg_cb(struct file_lock *fl) |
2084 | { | 2073 | { |
2085 | struct nfs4_delegation *dp= (struct nfs4_delegation *)fl->fl_owner; | 2074 | struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; |
2086 | struct task_struct *t; | ||
2087 | 2075 | ||
2088 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); | 2076 | dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl); |
2089 | if (!dp) | 2077 | if (!dp) |
@@ -2111,16 +2099,8 @@ void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2111 | */ | 2099 | */ |
2112 | fl->fl_break_time = 0; | 2100 | fl->fl_break_time = 0; |
2113 | 2101 | ||
2114 | t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall"); | 2102 | dp->dl_file->fi_had_conflict = true; |
2115 | if (IS_ERR(t)) { | 2103 | nfsd4_cb_recall(dp); |
2116 | struct nfs4_client *clp = dp->dl_client; | ||
2117 | |||
2118 | printk(KERN_INFO "NFSD: Callback thread failed for " | ||
2119 | "for client (clientid %08x/%08x)\n", | ||
2120 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
2121 | put_nfs4_client(dp->dl_client); | ||
2122 | nfs4_put_delegation(dp); | ||
2123 | } | ||
2124 | } | 2104 | } |
2125 | 2105 | ||
2126 | /* | 2106 | /* |
@@ -2422,7 +2402,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
2422 | { | 2402 | { |
2423 | struct nfs4_delegation *dp; | 2403 | struct nfs4_delegation *dp; |
2424 | struct nfs4_stateowner *sop = stp->st_stateowner; | 2404 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2425 | struct nfs4_callback *cb = &sop->so_client->cl_callback; | 2405 | struct nfs4_cb_conn *cb = &sop->so_client->cl_cb_conn; |
2426 | struct file_lock fl, *flp = &fl; | 2406 | struct file_lock fl, *flp = &fl; |
2427 | int status, flag = 0; | 2407 | int status, flag = 0; |
2428 | 2408 | ||
@@ -2614,7 +2594,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2614 | renew_client(clp); | 2594 | renew_client(clp); |
2615 | status = nfserr_cb_path_down; | 2595 | status = nfserr_cb_path_down; |
2616 | if (!list_empty(&clp->cl_delegations) | 2596 | if (!list_empty(&clp->cl_delegations) |
2617 | && !atomic_read(&clp->cl_callback.cb_set)) | 2597 | && !atomic_read(&clp->cl_cb_conn.cb_set)) |
2618 | goto out; | 2598 | goto out; |
2619 | status = nfs_ok; | 2599 | status = nfs_ok; |
2620 | out: | 2600 | out: |
@@ -2738,12 +2718,42 @@ nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | |||
2738 | static int | 2718 | static int |
2739 | STALE_STATEID(stateid_t *stateid) | 2719 | STALE_STATEID(stateid_t *stateid) |
2740 | { | 2720 | { |
2741 | if (stateid->si_boot == boot_time) | 2721 | if (time_after((unsigned long)boot_time, |
2742 | return 0; | 2722 | (unsigned long)stateid->si_boot)) { |
2743 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", | 2723 | dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", |
2744 | stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, | 2724 | stateid->si_boot, stateid->si_stateownerid, |
2745 | stateid->si_generation); | 2725 | stateid->si_fileid, stateid->si_generation); |
2746 | return 1; | 2726 | return 1; |
2727 | } | ||
2728 | return 0; | ||
2729 | } | ||
2730 | |||
2731 | static int | ||
2732 | EXPIRED_STATEID(stateid_t *stateid) | ||
2733 | { | ||
2734 | if (time_before((unsigned long)boot_time, | ||
2735 | ((unsigned long)stateid->si_boot)) && | ||
2736 | time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) { | ||
2737 | dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n", | ||
2738 | stateid->si_boot, stateid->si_stateownerid, | ||
2739 | stateid->si_fileid, stateid->si_generation); | ||
2740 | return 1; | ||
2741 | } | ||
2742 | return 0; | ||
2743 | } | ||
2744 | |||
2745 | static __be32 | ||
2746 | stateid_error_map(stateid_t *stateid) | ||
2747 | { | ||
2748 | if (STALE_STATEID(stateid)) | ||
2749 | return nfserr_stale_stateid; | ||
2750 | if (EXPIRED_STATEID(stateid)) | ||
2751 | return nfserr_expired; | ||
2752 | |||
2753 | dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n", | ||
2754 | stateid->si_boot, stateid->si_stateownerid, | ||
2755 | stateid->si_fileid, stateid->si_generation); | ||
2756 | return nfserr_bad_stateid; | ||
2747 | } | 2757 | } |
2748 | 2758 | ||
2749 | static inline int | 2759 | static inline int |
@@ -2867,8 +2877,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2867 | status = nfserr_bad_stateid; | 2877 | status = nfserr_bad_stateid; |
2868 | if (is_delegation_stateid(stateid)) { | 2878 | if (is_delegation_stateid(stateid)) { |
2869 | dp = find_delegation_stateid(ino, stateid); | 2879 | dp = find_delegation_stateid(ino, stateid); |
2870 | if (!dp) | 2880 | if (!dp) { |
2881 | status = stateid_error_map(stateid); | ||
2871 | goto out; | 2882 | goto out; |
2883 | } | ||
2872 | status = check_stateid_generation(stateid, &dp->dl_stateid, | 2884 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2873 | flags); | 2885 | flags); |
2874 | if (status) | 2886 | if (status) |
@@ -2881,8 +2893,10 @@ nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, | |||
2881 | *filpp = dp->dl_vfs_file; | 2893 | *filpp = dp->dl_vfs_file; |
2882 | } else { /* open or lock stateid */ | 2894 | } else { /* open or lock stateid */ |
2883 | stp = find_stateid(stateid, flags); | 2895 | stp = find_stateid(stateid, flags); |
2884 | if (!stp) | 2896 | if (!stp) { |
2897 | status = stateid_error_map(stateid); | ||
2885 | goto out; | 2898 | goto out; |
2899 | } | ||
2886 | if (nfs4_check_fh(current_fh, stp)) | 2900 | if (nfs4_check_fh(current_fh, stp)) |
2887 | goto out; | 2901 | goto out; |
2888 | if (!stp->st_stateowner->so_confirmed) | 2902 | if (!stp->st_stateowner->so_confirmed) |
@@ -2956,7 +2970,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | |||
2956 | */ | 2970 | */ |
2957 | sop = search_close_lru(stateid->si_stateownerid, flags); | 2971 | sop = search_close_lru(stateid->si_stateownerid, flags); |
2958 | if (sop == NULL) | 2972 | if (sop == NULL) |
2959 | return nfserr_bad_stateid; | 2973 | return stateid_error_map(stateid); |
2960 | *sopp = sop; | 2974 | *sopp = sop; |
2961 | goto check_replay; | 2975 | goto check_replay; |
2962 | } | 2976 | } |
@@ -3227,8 +3241,10 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3227 | if (!is_delegation_stateid(stateid)) | 3241 | if (!is_delegation_stateid(stateid)) |
3228 | goto out; | 3242 | goto out; |
3229 | dp = find_delegation_stateid(inode, stateid); | 3243 | dp = find_delegation_stateid(inode, stateid); |
3230 | if (!dp) | 3244 | if (!dp) { |
3245 | status = stateid_error_map(stateid); | ||
3231 | goto out; | 3246 | goto out; |
3247 | } | ||
3232 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | 3248 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3233 | if (status) | 3249 | if (status) |
3234 | goto out; | 3250 | goto out; |
@@ -3455,7 +3471,7 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc | |||
3455 | stp->st_stateowner = sop; | 3471 | stp->st_stateowner = sop; |
3456 | get_nfs4_file(fp); | 3472 | get_nfs4_file(fp); |
3457 | stp->st_file = fp; | 3473 | stp->st_file = fp; |
3458 | stp->st_stateid.si_boot = boot_time; | 3474 | stp->st_stateid.si_boot = get_seconds(); |
3459 | stp->st_stateid.si_stateownerid = sop->so_id; | 3475 | stp->st_stateid.si_stateownerid = sop->so_id; |
3460 | stp->st_stateid.si_fileid = fp->fi_id; | 3476 | stp->st_stateid.si_fileid = fp->fi_id; |
3461 | stp->st_stateid.si_generation = 0; | 3477 | stp->st_stateid.si_generation = 0; |
@@ -3987,6 +4003,7 @@ nfs4_state_init(void) | |||
3987 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 4003 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
3988 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | 4004 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
3989 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | 4005 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
4006 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3990 | } | 4007 | } |
3991 | for (i = 0; i < SESSION_HASH_SIZE; i++) | 4008 | for (i = 0; i < SESSION_HASH_SIZE; i++) |
3992 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | 4009 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); |
@@ -4009,8 +4026,6 @@ nfs4_state_init(void) | |||
4009 | INIT_LIST_HEAD(&close_lru); | 4026 | INIT_LIST_HEAD(&close_lru); |
4010 | INIT_LIST_HEAD(&client_lru); | 4027 | INIT_LIST_HEAD(&client_lru); |
4011 | INIT_LIST_HEAD(&del_recall_lru); | 4028 | INIT_LIST_HEAD(&del_recall_lru); |
4012 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
4013 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
4014 | reclaim_str_hashtbl_size = 0; | 4029 | reclaim_str_hashtbl_size = 0; |
4015 | return 0; | 4030 | return 0; |
4016 | } | 4031 | } |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b73549d293be..2dcc7feaa6ff 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -83,16 +83,6 @@ check_filename(char *str, int len, __be32 err) | |||
83 | return 0; | 83 | return 0; |
84 | } | 84 | } |
85 | 85 | ||
86 | /* | ||
87 | * START OF "GENERIC" DECODE ROUTINES. | ||
88 | * These may look a little ugly since they are imported from a "generic" | ||
89 | * set of XDR encode/decode routines which are intended to be shared by | ||
90 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
91 | * | ||
92 | * If the pain of reading these is too great, it should be a straightforward | ||
93 | * task to translate them into Linux-specific versions which are more | ||
94 | * consistent with the style used in NFSv2/v3... | ||
95 | */ | ||
96 | #define DECODE_HEAD \ | 86 | #define DECODE_HEAD \ |
97 | __be32 *p; \ | 87 | __be32 *p; \ |
98 | __be32 status | 88 | __be32 status |
@@ -254,20 +244,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) | |||
254 | DECODE_TAIL; | 244 | DECODE_TAIL; |
255 | } | 245 | } |
256 | 246 | ||
257 | static u32 nfsd_attrmask[] = { | ||
258 | NFSD_WRITEABLE_ATTRS_WORD0, | ||
259 | NFSD_WRITEABLE_ATTRS_WORD1, | ||
260 | NFSD_WRITEABLE_ATTRS_WORD2 | ||
261 | }; | ||
262 | |||
263 | static u32 nfsd41_ex_attrmask[] = { | ||
264 | NFSD_SUPPATTR_EXCLCREAT_WORD0, | ||
265 | NFSD_SUPPATTR_EXCLCREAT_WORD1, | ||
266 | NFSD_SUPPATTR_EXCLCREAT_WORD2 | ||
267 | }; | ||
268 | |||
269 | static __be32 | 247 | static __be32 |
270 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | 248 | nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, |
271 | struct iattr *iattr, struct nfs4_acl **acl) | 249 | struct iattr *iattr, struct nfs4_acl **acl) |
272 | { | 250 | { |
273 | int expected_len, len = 0; | 251 | int expected_len, len = 0; |
@@ -280,18 +258,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
280 | if ((status = nfsd4_decode_bitmap(argp, bmval))) | 258 | if ((status = nfsd4_decode_bitmap(argp, bmval))) |
281 | return status; | 259 | return status; |
282 | 260 | ||
283 | /* | ||
284 | * According to spec, unsupported attributes return ERR_ATTRNOTSUPP; | ||
285 | * read-only attributes return ERR_INVAL. | ||
286 | */ | ||
287 | if ((bmval[0] & ~nfsd_suppattrs0(argp->minorversion)) || | ||
288 | (bmval[1] & ~nfsd_suppattrs1(argp->minorversion)) || | ||
289 | (bmval[2] & ~nfsd_suppattrs2(argp->minorversion))) | ||
290 | return nfserr_attrnotsupp; | ||
291 | if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) || | ||
292 | (bmval[2] & ~writable[2])) | ||
293 | return nfserr_inval; | ||
294 | |||
295 | READ_BUF(4); | 261 | READ_BUF(4); |
296 | READ32(expected_len); | 262 | READ32(expected_len); |
297 | 263 | ||
@@ -424,8 +390,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, u32 *writable, | |||
424 | goto xdr_error; | 390 | goto xdr_error; |
425 | } | 391 | } |
426 | } | 392 | } |
427 | BUG_ON(bmval[2]); /* no such writeable attr supported yet */ | 393 | if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 |
428 | if (len != expected_len) | 394 | || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 |
395 | || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) | ||
396 | READ_BUF(expected_len - len); | ||
397 | else if (len != expected_len) | ||
429 | goto xdr_error; | 398 | goto xdr_error; |
430 | 399 | ||
431 | DECODE_TAIL; | 400 | DECODE_TAIL; |
@@ -518,8 +487,8 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create | |||
518 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) | 487 | if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval))) |
519 | return status; | 488 | return status; |
520 | 489 | ||
521 | status = nfsd4_decode_fattr(argp, create->cr_bmval, nfsd_attrmask, | 490 | status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, |
522 | &create->cr_iattr, &create->cr_acl); | 491 | &create->cr_acl); |
523 | if (status) | 492 | if (status) |
524 | goto out; | 493 | goto out; |
525 | 494 | ||
@@ -682,7 +651,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
682 | case NFS4_CREATE_UNCHECKED: | 651 | case NFS4_CREATE_UNCHECKED: |
683 | case NFS4_CREATE_GUARDED: | 652 | case NFS4_CREATE_GUARDED: |
684 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 653 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
685 | nfsd_attrmask, &open->op_iattr, &open->op_acl); | 654 | &open->op_iattr, &open->op_acl); |
686 | if (status) | 655 | if (status) |
687 | goto out; | 656 | goto out; |
688 | break; | 657 | break; |
@@ -696,8 +665,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) | |||
696 | READ_BUF(8); | 665 | READ_BUF(8); |
697 | COPYMEM(open->op_verf.data, 8); | 666 | COPYMEM(open->op_verf.data, 8); |
698 | status = nfsd4_decode_fattr(argp, open->op_bmval, | 667 | status = nfsd4_decode_fattr(argp, open->op_bmval, |
699 | nfsd41_ex_attrmask, &open->op_iattr, | 668 | &open->op_iattr, &open->op_acl); |
700 | &open->op_acl); | ||
701 | if (status) | 669 | if (status) |
702 | goto out; | 670 | goto out; |
703 | break; | 671 | break; |
@@ -893,8 +861,8 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta | |||
893 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); | 861 | status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); |
894 | if (status) | 862 | if (status) |
895 | return status; | 863 | return status; |
896 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, nfsd_attrmask, | 864 | return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, |
897 | &setattr->sa_iattr, &setattr->sa_acl); | 865 | &setattr->sa_acl); |
898 | } | 866 | } |
899 | 867 | ||
900 | static __be32 | 868 | static __be32 |
@@ -1328,64 +1296,64 @@ static nfsd4_dec nfsd4_dec_ops[] = { | |||
1328 | }; | 1296 | }; |
1329 | 1297 | ||
1330 | static nfsd4_dec nfsd41_dec_ops[] = { | 1298 | static nfsd4_dec nfsd41_dec_ops[] = { |
1331 | [OP_ACCESS] (nfsd4_dec)nfsd4_decode_access, | 1299 | [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, |
1332 | [OP_CLOSE] (nfsd4_dec)nfsd4_decode_close, | 1300 | [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, |
1333 | [OP_COMMIT] (nfsd4_dec)nfsd4_decode_commit, | 1301 | [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, |
1334 | [OP_CREATE] (nfsd4_dec)nfsd4_decode_create, | 1302 | [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, |
1335 | [OP_DELEGPURGE] (nfsd4_dec)nfsd4_decode_notsupp, | 1303 | [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, |
1336 | [OP_DELEGRETURN] (nfsd4_dec)nfsd4_decode_delegreturn, | 1304 | [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, |
1337 | [OP_GETATTR] (nfsd4_dec)nfsd4_decode_getattr, | 1305 | [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, |
1338 | [OP_GETFH] (nfsd4_dec)nfsd4_decode_noop, | 1306 | [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, |
1339 | [OP_LINK] (nfsd4_dec)nfsd4_decode_link, | 1307 | [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, |
1340 | [OP_LOCK] (nfsd4_dec)nfsd4_decode_lock, | 1308 | [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, |
1341 | [OP_LOCKT] (nfsd4_dec)nfsd4_decode_lockt, | 1309 | [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, |
1342 | [OP_LOCKU] (nfsd4_dec)nfsd4_decode_locku, | 1310 | [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, |
1343 | [OP_LOOKUP] (nfsd4_dec)nfsd4_decode_lookup, | 1311 | [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, |
1344 | [OP_LOOKUPP] (nfsd4_dec)nfsd4_decode_noop, | 1312 | [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, |
1345 | [OP_NVERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1313 | [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1346 | [OP_OPEN] (nfsd4_dec)nfsd4_decode_open, | 1314 | [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, |
1347 | [OP_OPENATTR] (nfsd4_dec)nfsd4_decode_notsupp, | 1315 | [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, |
1348 | [OP_OPEN_CONFIRM] (nfsd4_dec)nfsd4_decode_notsupp, | 1316 | [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, |
1349 | [OP_OPEN_DOWNGRADE] (nfsd4_dec)nfsd4_decode_open_downgrade, | 1317 | [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, |
1350 | [OP_PUTFH] (nfsd4_dec)nfsd4_decode_putfh, | 1318 | [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, |
1351 | [OP_PUTPUBFH] (nfsd4_dec)nfsd4_decode_notsupp, | 1319 | [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, |
1352 | [OP_PUTROOTFH] (nfsd4_dec)nfsd4_decode_noop, | 1320 | [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, |
1353 | [OP_READ] (nfsd4_dec)nfsd4_decode_read, | 1321 | [OP_READ] = (nfsd4_dec)nfsd4_decode_read, |
1354 | [OP_READDIR] (nfsd4_dec)nfsd4_decode_readdir, | 1322 | [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, |
1355 | [OP_READLINK] (nfsd4_dec)nfsd4_decode_noop, | 1323 | [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, |
1356 | [OP_REMOVE] (nfsd4_dec)nfsd4_decode_remove, | 1324 | [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, |
1357 | [OP_RENAME] (nfsd4_dec)nfsd4_decode_rename, | 1325 | [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, |
1358 | [OP_RENEW] (nfsd4_dec)nfsd4_decode_notsupp, | 1326 | [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, |
1359 | [OP_RESTOREFH] (nfsd4_dec)nfsd4_decode_noop, | 1327 | [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, |
1360 | [OP_SAVEFH] (nfsd4_dec)nfsd4_decode_noop, | 1328 | [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, |
1361 | [OP_SECINFO] (nfsd4_dec)nfsd4_decode_secinfo, | 1329 | [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, |
1362 | [OP_SETATTR] (nfsd4_dec)nfsd4_decode_setattr, | 1330 | [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, |
1363 | [OP_SETCLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1331 | [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1364 | [OP_SETCLIENTID_CONFIRM](nfsd4_dec)nfsd4_decode_notsupp, | 1332 | [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, |
1365 | [OP_VERIFY] (nfsd4_dec)nfsd4_decode_verify, | 1333 | [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, |
1366 | [OP_WRITE] (nfsd4_dec)nfsd4_decode_write, | 1334 | [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, |
1367 | [OP_RELEASE_LOCKOWNER] (nfsd4_dec)nfsd4_decode_notsupp, | 1335 | [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, |
1368 | 1336 | ||
1369 | /* new operations for NFSv4.1 */ | 1337 | /* new operations for NFSv4.1 */ |
1370 | [OP_BACKCHANNEL_CTL] (nfsd4_dec)nfsd4_decode_notsupp, | 1338 | [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_notsupp, |
1371 | [OP_BIND_CONN_TO_SESSION](nfsd4_dec)nfsd4_decode_notsupp, | 1339 | [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_notsupp, |
1372 | [OP_EXCHANGE_ID] (nfsd4_dec)nfsd4_decode_exchange_id, | 1340 | [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, |
1373 | [OP_CREATE_SESSION] (nfsd4_dec)nfsd4_decode_create_session, | 1341 | [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, |
1374 | [OP_DESTROY_SESSION] (nfsd4_dec)nfsd4_decode_destroy_session, | 1342 | [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, |
1375 | [OP_FREE_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1343 | [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1376 | [OP_GET_DIR_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1344 | [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1377 | [OP_GETDEVICEINFO] (nfsd4_dec)nfsd4_decode_notsupp, | 1345 | [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, |
1378 | [OP_GETDEVICELIST] (nfsd4_dec)nfsd4_decode_notsupp, | 1346 | [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, |
1379 | [OP_LAYOUTCOMMIT] (nfsd4_dec)nfsd4_decode_notsupp, | 1347 | [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, |
1380 | [OP_LAYOUTGET] (nfsd4_dec)nfsd4_decode_notsupp, | 1348 | [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, |
1381 | [OP_LAYOUTRETURN] (nfsd4_dec)nfsd4_decode_notsupp, | 1349 | [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, |
1382 | [OP_SECINFO_NO_NAME] (nfsd4_dec)nfsd4_decode_notsupp, | 1350 | [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_notsupp, |
1383 | [OP_SEQUENCE] (nfsd4_dec)nfsd4_decode_sequence, | 1351 | [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, |
1384 | [OP_SET_SSV] (nfsd4_dec)nfsd4_decode_notsupp, | 1352 | [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, |
1385 | [OP_TEST_STATEID] (nfsd4_dec)nfsd4_decode_notsupp, | 1353 | [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1386 | [OP_WANT_DELEGATION] (nfsd4_dec)nfsd4_decode_notsupp, | 1354 | [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, |
1387 | [OP_DESTROY_CLIENTID] (nfsd4_dec)nfsd4_decode_notsupp, | 1355 | [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, |
1388 | [OP_RECLAIM_COMPLETE] (nfsd4_dec)nfsd4_decode_notsupp, | 1356 | [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_notsupp, |
1389 | }; | 1357 | }; |
1390 | 1358 | ||
1391 | struct nfsd4_minorversion_ops { | 1359 | struct nfsd4_minorversion_ops { |
@@ -1489,21 +1457,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1489 | 1457 | ||
1490 | DECODE_TAIL; | 1458 | DECODE_TAIL; |
1491 | } | 1459 | } |
1492 | /* | ||
1493 | * END OF "GENERIC" DECODE ROUTINES. | ||
1494 | */ | ||
1495 | |||
1496 | /* | ||
1497 | * START OF "GENERIC" ENCODE ROUTINES. | ||
1498 | * These may look a little ugly since they are imported from a "generic" | ||
1499 | * set of XDR encode/decode routines which are intended to be shared by | ||
1500 | * all of our NFSv4 implementations (OpenBSD, MacOS X...). | ||
1501 | * | ||
1502 | * If the pain of reading these is too great, it should be a straightforward | ||
1503 | * task to translate them into Linux-specific versions which are more | ||
1504 | * consistent with the style used in NFSv2/v3... | ||
1505 | */ | ||
1506 | #define ENCODE_HEAD __be32 *p | ||
1507 | 1460 | ||
1508 | #define WRITE32(n) *p++ = htonl(n) | 1461 | #define WRITE32(n) *p++ = htonl(n) |
1509 | #define WRITE64(n) do { \ | 1462 | #define WRITE64(n) do { \ |
@@ -1515,13 +1468,41 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1515 | memcpy(p, ptr, nbytes); \ | 1468 | memcpy(p, ptr, nbytes); \ |
1516 | p += XDR_QUADLEN(nbytes); \ | 1469 | p += XDR_QUADLEN(nbytes); \ |
1517 | }} while (0) | 1470 | }} while (0) |
1518 | #define WRITECINFO(c) do { \ | 1471 | |
1519 | *p++ = htonl(c.atomic); \ | 1472 | static void write32(__be32 **p, u32 n) |
1520 | *p++ = htonl(c.before_ctime_sec); \ | 1473 | { |
1521 | *p++ = htonl(c.before_ctime_nsec); \ | 1474 | *(*p)++ = n; |
1522 | *p++ = htonl(c.after_ctime_sec); \ | 1475 | } |
1523 | *p++ = htonl(c.after_ctime_nsec); \ | 1476 | |
1524 | } while (0) | 1477 | static void write64(__be32 **p, u64 n) |
1478 | { | ||
1479 | write32(p, (u32)(n >> 32)); | ||
1480 | write32(p, (u32)n); | ||
1481 | } | ||
1482 | |||
1483 | static void write_change(__be32 **p, struct kstat *stat, struct inode *inode) | ||
1484 | { | ||
1485 | if (IS_I_VERSION(inode)) { | ||
1486 | write64(p, inode->i_version); | ||
1487 | } else { | ||
1488 | write32(p, stat->ctime.tv_sec); | ||
1489 | write32(p, stat->ctime.tv_nsec); | ||
1490 | } | ||
1491 | } | ||
1492 | |||
1493 | static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) | ||
1494 | { | ||
1495 | write32(p, c->atomic); | ||
1496 | if (c->change_supported) { | ||
1497 | write64(p, c->before_change); | ||
1498 | write64(p, c->after_change); | ||
1499 | } else { | ||
1500 | write32(p, c->before_ctime_sec); | ||
1501 | write32(p, c->before_ctime_nsec); | ||
1502 | write32(p, c->after_ctime_sec); | ||
1503 | write32(p, c->after_ctime_nsec); | ||
1504 | } | ||
1505 | } | ||
1525 | 1506 | ||
1526 | #define RESERVE_SPACE(nbytes) do { \ | 1507 | #define RESERVE_SPACE(nbytes) do { \ |
1527 | p = resp->p; \ | 1508 | p = resp->p; \ |
@@ -1874,16 +1855,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1874 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); | 1855 | WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME); |
1875 | } | 1856 | } |
1876 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1857 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
1877 | /* | ||
1878 | * Note: This _must_ be consistent with the scheme for writing | ||
1879 | * change_info, so any changes made here must be reflected there | ||
1880 | * as well. (See xdr4.h:set_change_info() and the WRITECINFO() | ||
1881 | * macro above.) | ||
1882 | */ | ||
1883 | if ((buflen -= 8) < 0) | 1858 | if ((buflen -= 8) < 0) |
1884 | goto out_resource; | 1859 | goto out_resource; |
1885 | WRITE32(stat.ctime.tv_sec); | 1860 | write_change(&p, &stat, dentry->d_inode); |
1886 | WRITE32(stat.ctime.tv_nsec); | ||
1887 | } | 1861 | } |
1888 | if (bmval0 & FATTR4_WORD0_SIZE) { | 1862 | if (bmval0 & FATTR4_WORD0_SIZE) { |
1889 | if ((buflen -= 8) < 0) | 1863 | if ((buflen -= 8) < 0) |
@@ -2348,7 +2322,7 @@ fail: | |||
2348 | static void | 2322 | static void |
2349 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | 2323 | nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) |
2350 | { | 2324 | { |
2351 | ENCODE_HEAD; | 2325 | __be32 *p; |
2352 | 2326 | ||
2353 | RESERVE_SPACE(sizeof(stateid_t)); | 2327 | RESERVE_SPACE(sizeof(stateid_t)); |
2354 | WRITE32(sid->si_generation); | 2328 | WRITE32(sid->si_generation); |
@@ -2359,7 +2333,7 @@ nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid) | |||
2359 | static __be32 | 2333 | static __be32 |
2360 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) | 2334 | nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) |
2361 | { | 2335 | { |
2362 | ENCODE_HEAD; | 2336 | __be32 *p; |
2363 | 2337 | ||
2364 | if (!nfserr) { | 2338 | if (!nfserr) { |
2365 | RESERVE_SPACE(8); | 2339 | RESERVE_SPACE(8); |
@@ -2386,7 +2360,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c | |||
2386 | static __be32 | 2360 | static __be32 |
2387 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) | 2361 | nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) |
2388 | { | 2362 | { |
2389 | ENCODE_HEAD; | 2363 | __be32 *p; |
2390 | 2364 | ||
2391 | if (!nfserr) { | 2365 | if (!nfserr) { |
2392 | RESERVE_SPACE(8); | 2366 | RESERVE_SPACE(8); |
@@ -2399,11 +2373,11 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2399 | static __be32 | 2373 | static __be32 |
2400 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) | 2374 | nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) |
2401 | { | 2375 | { |
2402 | ENCODE_HEAD; | 2376 | __be32 *p; |
2403 | 2377 | ||
2404 | if (!nfserr) { | 2378 | if (!nfserr) { |
2405 | RESERVE_SPACE(32); | 2379 | RESERVE_SPACE(32); |
2406 | WRITECINFO(create->cr_cinfo); | 2380 | write_cinfo(&p, &create->cr_cinfo); |
2407 | WRITE32(2); | 2381 | WRITE32(2); |
2408 | WRITE32(create->cr_bmval[0]); | 2382 | WRITE32(create->cr_bmval[0]); |
2409 | WRITE32(create->cr_bmval[1]); | 2383 | WRITE32(create->cr_bmval[1]); |
@@ -2435,7 +2409,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2435 | { | 2409 | { |
2436 | struct svc_fh *fhp = *fhpp; | 2410 | struct svc_fh *fhp = *fhpp; |
2437 | unsigned int len; | 2411 | unsigned int len; |
2438 | ENCODE_HEAD; | 2412 | __be32 *p; |
2439 | 2413 | ||
2440 | if (!nfserr) { | 2414 | if (!nfserr) { |
2441 | len = fhp->fh_handle.fh_size; | 2415 | len = fhp->fh_handle.fh_size; |
@@ -2454,7 +2428,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh | |||
2454 | static void | 2428 | static void |
2455 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) | 2429 | nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld) |
2456 | { | 2430 | { |
2457 | ENCODE_HEAD; | 2431 | __be32 *p; |
2458 | 2432 | ||
2459 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); | 2433 | RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0)); |
2460 | WRITE64(ld->ld_start); | 2434 | WRITE64(ld->ld_start); |
@@ -2510,11 +2484,11 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l | |||
2510 | static __be32 | 2484 | static __be32 |
2511 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) | 2485 | nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) |
2512 | { | 2486 | { |
2513 | ENCODE_HEAD; | 2487 | __be32 *p; |
2514 | 2488 | ||
2515 | if (!nfserr) { | 2489 | if (!nfserr) { |
2516 | RESERVE_SPACE(20); | 2490 | RESERVE_SPACE(20); |
2517 | WRITECINFO(link->li_cinfo); | 2491 | write_cinfo(&p, &link->li_cinfo); |
2518 | ADJUST_ARGS(); | 2492 | ADJUST_ARGS(); |
2519 | } | 2493 | } |
2520 | return nfserr; | 2494 | return nfserr; |
@@ -2524,7 +2498,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li | |||
2524 | static __be32 | 2498 | static __be32 |
2525 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) | 2499 | nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) |
2526 | { | 2500 | { |
2527 | ENCODE_HEAD; | 2501 | __be32 *p; |
2528 | ENCODE_SEQID_OP_HEAD; | 2502 | ENCODE_SEQID_OP_HEAD; |
2529 | 2503 | ||
2530 | if (nfserr) | 2504 | if (nfserr) |
@@ -2532,7 +2506,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op | |||
2532 | 2506 | ||
2533 | nfsd4_encode_stateid(resp, &open->op_stateid); | 2507 | nfsd4_encode_stateid(resp, &open->op_stateid); |
2534 | RESERVE_SPACE(40); | 2508 | RESERVE_SPACE(40); |
2535 | WRITECINFO(open->op_cinfo); | 2509 | write_cinfo(&p, &open->op_cinfo); |
2536 | WRITE32(open->op_rflags); | 2510 | WRITE32(open->op_rflags); |
2537 | WRITE32(2); | 2511 | WRITE32(2); |
2538 | WRITE32(open->op_bmval[0]); | 2512 | WRITE32(open->op_bmval[0]); |
@@ -2619,7 +2593,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2619 | int v, pn; | 2593 | int v, pn; |
2620 | unsigned long maxcount; | 2594 | unsigned long maxcount; |
2621 | long len; | 2595 | long len; |
2622 | ENCODE_HEAD; | 2596 | __be32 *p; |
2623 | 2597 | ||
2624 | if (nfserr) | 2598 | if (nfserr) |
2625 | return nfserr; | 2599 | return nfserr; |
@@ -2681,7 +2655,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd | |||
2681 | { | 2655 | { |
2682 | int maxcount; | 2656 | int maxcount; |
2683 | char *page; | 2657 | char *page; |
2684 | ENCODE_HEAD; | 2658 | __be32 *p; |
2685 | 2659 | ||
2686 | if (nfserr) | 2660 | if (nfserr) |
2687 | return nfserr; | 2661 | return nfserr; |
@@ -2730,7 +2704,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2730 | int maxcount; | 2704 | int maxcount; |
2731 | loff_t offset; | 2705 | loff_t offset; |
2732 | __be32 *page, *savep, *tailbase; | 2706 | __be32 *page, *savep, *tailbase; |
2733 | ENCODE_HEAD; | 2707 | __be32 *p; |
2734 | 2708 | ||
2735 | if (nfserr) | 2709 | if (nfserr) |
2736 | return nfserr; | 2710 | return nfserr; |
@@ -2806,11 +2780,11 @@ err_no_verf: | |||
2806 | static __be32 | 2780 | static __be32 |
2807 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) | 2781 | nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) |
2808 | { | 2782 | { |
2809 | ENCODE_HEAD; | 2783 | __be32 *p; |
2810 | 2784 | ||
2811 | if (!nfserr) { | 2785 | if (!nfserr) { |
2812 | RESERVE_SPACE(20); | 2786 | RESERVE_SPACE(20); |
2813 | WRITECINFO(remove->rm_cinfo); | 2787 | write_cinfo(&p, &remove->rm_cinfo); |
2814 | ADJUST_ARGS(); | 2788 | ADJUST_ARGS(); |
2815 | } | 2789 | } |
2816 | return nfserr; | 2790 | return nfserr; |
@@ -2819,12 +2793,12 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2819 | static __be32 | 2793 | static __be32 |
2820 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) | 2794 | nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) |
2821 | { | 2795 | { |
2822 | ENCODE_HEAD; | 2796 | __be32 *p; |
2823 | 2797 | ||
2824 | if (!nfserr) { | 2798 | if (!nfserr) { |
2825 | RESERVE_SPACE(40); | 2799 | RESERVE_SPACE(40); |
2826 | WRITECINFO(rename->rn_sinfo); | 2800 | write_cinfo(&p, &rename->rn_sinfo); |
2827 | WRITECINFO(rename->rn_tinfo); | 2801 | write_cinfo(&p, &rename->rn_tinfo); |
2828 | ADJUST_ARGS(); | 2802 | ADJUST_ARGS(); |
2829 | } | 2803 | } |
2830 | return nfserr; | 2804 | return nfserr; |
@@ -2839,7 +2813,7 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, | |||
2839 | u32 nflavs; | 2813 | u32 nflavs; |
2840 | struct exp_flavor_info *flavs; | 2814 | struct exp_flavor_info *flavs; |
2841 | struct exp_flavor_info def_flavs[2]; | 2815 | struct exp_flavor_info def_flavs[2]; |
2842 | ENCODE_HEAD; | 2816 | __be32 *p; |
2843 | 2817 | ||
2844 | if (nfserr) | 2818 | if (nfserr) |
2845 | goto out; | 2819 | goto out; |
@@ -2904,7 +2878,7 @@ out: | |||
2904 | static __be32 | 2878 | static __be32 |
2905 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) | 2879 | nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) |
2906 | { | 2880 | { |
2907 | ENCODE_HEAD; | 2881 | __be32 *p; |
2908 | 2882 | ||
2909 | RESERVE_SPACE(12); | 2883 | RESERVE_SPACE(12); |
2910 | if (nfserr) { | 2884 | if (nfserr) { |
@@ -2924,7 +2898,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 | |||
2924 | static __be32 | 2898 | static __be32 |
2925 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) | 2899 | nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) |
2926 | { | 2900 | { |
2927 | ENCODE_HEAD; | 2901 | __be32 *p; |
2928 | 2902 | ||
2929 | if (!nfserr) { | 2903 | if (!nfserr) { |
2930 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); | 2904 | RESERVE_SPACE(8 + sizeof(nfs4_verifier)); |
@@ -2944,7 +2918,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n | |||
2944 | static __be32 | 2918 | static __be32 |
2945 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) | 2919 | nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) |
2946 | { | 2920 | { |
2947 | ENCODE_HEAD; | 2921 | __be32 *p; |
2948 | 2922 | ||
2949 | if (!nfserr) { | 2923 | if (!nfserr) { |
2950 | RESERVE_SPACE(16); | 2924 | RESERVE_SPACE(16); |
@@ -2960,7 +2934,7 @@ static __be32 | |||
2960 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, | 2934 | nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, int nfserr, |
2961 | struct nfsd4_exchange_id *exid) | 2935 | struct nfsd4_exchange_id *exid) |
2962 | { | 2936 | { |
2963 | ENCODE_HEAD; | 2937 | __be32 *p; |
2964 | char *major_id; | 2938 | char *major_id; |
2965 | char *server_scope; | 2939 | char *server_scope; |
2966 | int major_id_sz; | 2940 | int major_id_sz; |
@@ -3015,7 +2989,7 @@ static __be32 | |||
3015 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, | 2989 | nfsd4_encode_create_session(struct nfsd4_compoundres *resp, int nfserr, |
3016 | struct nfsd4_create_session *sess) | 2990 | struct nfsd4_create_session *sess) |
3017 | { | 2991 | { |
3018 | ENCODE_HEAD; | 2992 | __be32 *p; |
3019 | 2993 | ||
3020 | if (nfserr) | 2994 | if (nfserr) |
3021 | return nfserr; | 2995 | return nfserr; |
@@ -3071,7 +3045,7 @@ __be32 | |||
3071 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | 3045 | nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, |
3072 | struct nfsd4_sequence *seq) | 3046 | struct nfsd4_sequence *seq) |
3073 | { | 3047 | { |
3074 | ENCODE_HEAD; | 3048 | __be32 *p; |
3075 | 3049 | ||
3076 | if (nfserr) | 3050 | if (nfserr) |
3077 | return nfserr; | 3051 | return nfserr; |
@@ -3209,7 +3183,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3209 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, | 3183 | dprintk("%s length %u, xb->page_len %u tlen %u pad %u\n", __func__, |
3210 | length, xb->page_len, tlen, pad); | 3184 | length, xb->page_len, tlen, pad); |
3211 | 3185 | ||
3212 | if (length <= session->se_fmaxresp_cached) | 3186 | if (length <= session->se_fchannel.maxresp_cached) |
3213 | return status; | 3187 | return status; |
3214 | else | 3188 | else |
3215 | return nfserr_rep_too_big_to_cache; | 3189 | return nfserr_rep_too_big_to_cache; |
@@ -3219,7 +3193,7 @@ void | |||
3219 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3193 | nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
3220 | { | 3194 | { |
3221 | __be32 *statp; | 3195 | __be32 *statp; |
3222 | ENCODE_HEAD; | 3196 | __be32 *p; |
3223 | 3197 | ||
3224 | RESERVE_SPACE(8); | 3198 | RESERVE_SPACE(8); |
3225 | WRITE32(op->opnum); | 3199 | WRITE32(op->opnum); |
@@ -3253,7 +3227,7 @@ status: | |||
3253 | void | 3227 | void |
3254 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | 3228 | nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) |
3255 | { | 3229 | { |
3256 | ENCODE_HEAD; | 3230 | __be32 *p; |
3257 | struct nfs4_replay *rp = op->replay; | 3231 | struct nfs4_replay *rp = op->replay; |
3258 | 3232 | ||
3259 | BUG_ON(!rp); | 3233 | BUG_ON(!rp); |
@@ -3268,10 +3242,6 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
3268 | ADJUST_ARGS(); | 3242 | ADJUST_ARGS(); |
3269 | } | 3243 | } |
3270 | 3244 | ||
3271 | /* | ||
3272 | * END OF "GENERIC" ENCODE ROUTINES. | ||
3273 | */ | ||
3274 | |||
3275 | int | 3245 | int |
3276 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) | 3246 | nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) |
3277 | { | 3247 | { |
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 5bfc2ac60d54..4638635c5d87 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c | |||
@@ -29,15 +29,24 @@ | |||
29 | */ | 29 | */ |
30 | #define CACHESIZE 1024 | 30 | #define CACHESIZE 1024 |
31 | #define HASHSIZE 64 | 31 | #define HASHSIZE 64 |
32 | #define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1)) | ||
33 | 32 | ||
34 | static struct hlist_head * hash_list; | 33 | static struct hlist_head * cache_hash; |
35 | static struct list_head lru_head; | 34 | static struct list_head lru_head; |
36 | static int cache_disabled = 1; | 35 | static int cache_disabled = 1; |
37 | 36 | ||
37 | /* | ||
38 | * Calculate the hash index from an XID. | ||
39 | */ | ||
40 | static inline u32 request_hash(u32 xid) | ||
41 | { | ||
42 | u32 h = xid; | ||
43 | h ^= (xid >> 24); | ||
44 | return h & (HASHSIZE-1); | ||
45 | } | ||
46 | |||
38 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); | 47 | static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); |
39 | 48 | ||
40 | /* | 49 | /* |
41 | * locking for the reply cache: | 50 | * locking for the reply cache: |
42 | * A cache entry is "single use" if c_state == RC_INPROG | 51 | * A cache entry is "single use" if c_state == RC_INPROG |
43 | * Otherwise, it when accessing _prev or _next, the lock must be held. | 52 | * Otherwise, it when accessing _prev or _next, the lock must be held. |
@@ -62,8 +71,8 @@ int nfsd_reply_cache_init(void) | |||
62 | i--; | 71 | i--; |
63 | } | 72 | } |
64 | 73 | ||
65 | hash_list = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); | 74 | cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); |
66 | if (!hash_list) | 75 | if (!cache_hash) |
67 | goto out_nomem; | 76 | goto out_nomem; |
68 | 77 | ||
69 | cache_disabled = 0; | 78 | cache_disabled = 0; |
@@ -88,8 +97,8 @@ void nfsd_reply_cache_shutdown(void) | |||
88 | 97 | ||
89 | cache_disabled = 1; | 98 | cache_disabled = 1; |
90 | 99 | ||
91 | kfree (hash_list); | 100 | kfree (cache_hash); |
92 | hash_list = NULL; | 101 | cache_hash = NULL; |
93 | } | 102 | } |
94 | 103 | ||
95 | /* | 104 | /* |
@@ -108,7 +117,7 @@ static void | |||
108 | hash_refile(struct svc_cacherep *rp) | 117 | hash_refile(struct svc_cacherep *rp) |
109 | { | 118 | { |
110 | hlist_del_init(&rp->c_hash); | 119 | hlist_del_init(&rp->c_hash); |
111 | hlist_add_head(&rp->c_hash, hash_list + REQHASH(rp->c_xid)); | 120 | hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid)); |
112 | } | 121 | } |
113 | 122 | ||
114 | /* | 123 | /* |
@@ -138,7 +147,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
138 | spin_lock(&cache_lock); | 147 | spin_lock(&cache_lock); |
139 | rtn = RC_DOIT; | 148 | rtn = RC_DOIT; |
140 | 149 | ||
141 | rh = &hash_list[REQHASH(xid)]; | 150 | rh = &cache_hash[request_hash(xid)]; |
142 | hlist_for_each_entry(rp, hn, rh, c_hash) { | 151 | hlist_for_each_entry(rp, hn, rh, c_hash) { |
143 | if (rp->c_state != RC_UNUSED && | 152 | if (rp->c_state != RC_UNUSED && |
144 | xid == rp->c_xid && proc == rp->c_proc && | 153 | xid == rp->c_xid && proc == rp->c_proc && |
@@ -165,8 +174,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) | |||
165 | } | 174 | } |
166 | } | 175 | } |
167 | 176 | ||
168 | /* This should not happen */ | 177 | /* All entries on the LRU are in-progress. This should not happen */ |
169 | if (rp == NULL) { | 178 | if (&rp->c_lru == &lru_head) { |
170 | static int complaints; | 179 | static int complaints; |
171 | 180 | ||
172 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); | 181 | printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); |
@@ -264,7 +273,7 @@ nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) | |||
264 | 273 | ||
265 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); | 274 | len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); |
266 | len >>= 2; | 275 | len >>= 2; |
267 | 276 | ||
268 | /* Don't cache excessive amounts of data and XDR failures */ | 277 | /* Don't cache excessive amounts of data and XDR failures */ |
269 | if (!statp || len > (256 >> 2)) { | 278 | if (!statp || len > (256 >> 2)) { |
270 | rp->c_state = RC_UNUSED; | 279 | rp->c_state = RC_UNUSED; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index af16849d243a..6d0847562d87 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/inet.h> | 26 | #include <linux/inet.h> |
27 | #include <linux/string.h> | 27 | #include <linux/string.h> |
28 | #include <linux/smp_lock.h> | ||
29 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
30 | 29 | ||
31 | #include <linux/nfs.h> | 30 | #include <linux/nfs.h> |
@@ -207,10 +206,14 @@ static struct file_operations pool_stats_operations = { | |||
207 | static ssize_t write_svc(struct file *file, char *buf, size_t size) | 206 | static ssize_t write_svc(struct file *file, char *buf, size_t size) |
208 | { | 207 | { |
209 | struct nfsctl_svc *data; | 208 | struct nfsctl_svc *data; |
209 | int err; | ||
210 | if (size < sizeof(*data)) | 210 | if (size < sizeof(*data)) |
211 | return -EINVAL; | 211 | return -EINVAL; |
212 | data = (struct nfsctl_svc*) buf; | 212 | data = (struct nfsctl_svc*) buf; |
213 | return nfsd_svc(data->svc_port, data->svc_nthreads); | 213 | err = nfsd_svc(data->svc_port, data->svc_nthreads); |
214 | if (err < 0) | ||
215 | return err; | ||
216 | return 0; | ||
214 | } | 217 | } |
215 | 218 | ||
216 | /** | 219 | /** |
@@ -692,11 +695,12 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size) | |||
692 | if (newthreads < 0) | 695 | if (newthreads < 0) |
693 | return -EINVAL; | 696 | return -EINVAL; |
694 | rv = nfsd_svc(NFS_PORT, newthreads); | 697 | rv = nfsd_svc(NFS_PORT, newthreads); |
695 | if (rv) | 698 | if (rv < 0) |
696 | return rv; | 699 | return rv; |
697 | } | 700 | } else |
698 | sprintf(buf, "%d\n", nfsd_nrthreads()); | 701 | rv = nfsd_nrthreads(); |
699 | return strlen(buf); | 702 | |
703 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", rv); | ||
700 | } | 704 | } |
701 | 705 | ||
702 | /** | 706 | /** |
@@ -793,7 +797,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
793 | { | 797 | { |
794 | char *mesg = buf; | 798 | char *mesg = buf; |
795 | char *vers, *minorp, sign; | 799 | char *vers, *minorp, sign; |
796 | int len, num; | 800 | int len, num, remaining; |
797 | unsigned minor; | 801 | unsigned minor; |
798 | ssize_t tlen = 0; | 802 | ssize_t tlen = 0; |
799 | char *sep; | 803 | char *sep; |
@@ -840,32 +844,50 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | |||
840 | } | 844 | } |
841 | next: | 845 | next: |
842 | vers += len + 1; | 846 | vers += len + 1; |
843 | tlen += len; | ||
844 | } while ((len = qword_get(&mesg, vers, size)) > 0); | 847 | } while ((len = qword_get(&mesg, vers, size)) > 0); |
845 | /* If all get turned off, turn them back on, as | 848 | /* If all get turned off, turn them back on, as |
846 | * having no versions is BAD | 849 | * having no versions is BAD |
847 | */ | 850 | */ |
848 | nfsd_reset_versions(); | 851 | nfsd_reset_versions(); |
849 | } | 852 | } |
853 | |||
850 | /* Now write current state into reply buffer */ | 854 | /* Now write current state into reply buffer */ |
851 | len = 0; | 855 | len = 0; |
852 | sep = ""; | 856 | sep = ""; |
857 | remaining = SIMPLE_TRANSACTION_LIMIT; | ||
853 | for (num=2 ; num <= 4 ; num++) | 858 | for (num=2 ; num <= 4 ; num++) |
854 | if (nfsd_vers(num, NFSD_AVAIL)) { | 859 | if (nfsd_vers(num, NFSD_AVAIL)) { |
855 | len += sprintf(buf+len, "%s%c%d", sep, | 860 | len = snprintf(buf, remaining, "%s%c%d", sep, |
856 | nfsd_vers(num, NFSD_TEST)?'+':'-', | 861 | nfsd_vers(num, NFSD_TEST)?'+':'-', |
857 | num); | 862 | num); |
858 | sep = " "; | 863 | sep = " "; |
864 | |||
865 | if (len > remaining) | ||
866 | break; | ||
867 | remaining -= len; | ||
868 | buf += len; | ||
869 | tlen += len; | ||
859 | } | 870 | } |
860 | if (nfsd_vers(4, NFSD_AVAIL)) | 871 | if (nfsd_vers(4, NFSD_AVAIL)) |
861 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; minor++) | 872 | for (minor = 1; minor <= NFSD_SUPPORTED_MINOR_VERSION; |
862 | len += sprintf(buf+len, " %c4.%u", | 873 | minor++) { |
874 | len = snprintf(buf, remaining, " %c4.%u", | ||
863 | (nfsd_vers(4, NFSD_TEST) && | 875 | (nfsd_vers(4, NFSD_TEST) && |
864 | nfsd_minorversion(minor, NFSD_TEST)) ? | 876 | nfsd_minorversion(minor, NFSD_TEST)) ? |
865 | '+' : '-', | 877 | '+' : '-', |
866 | minor); | 878 | minor); |
867 | len += sprintf(buf+len, "\n"); | 879 | |
868 | return len; | 880 | if (len > remaining) |
881 | break; | ||
882 | remaining -= len; | ||
883 | buf += len; | ||
884 | tlen += len; | ||
885 | } | ||
886 | |||
887 | len = snprintf(buf, remaining, "\n"); | ||
888 | if (len > remaining) | ||
889 | return -EINVAL; | ||
890 | return tlen + len; | ||
869 | } | 891 | } |
870 | 892 | ||
871 | /** | 893 | /** |
@@ -910,104 +932,143 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size) | |||
910 | return rv; | 932 | return rv; |
911 | } | 933 | } |
912 | 934 | ||
913 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | 935 | /* |
936 | * Zero-length write. Return a list of NFSD's current listener | ||
937 | * transports. | ||
938 | */ | ||
939 | static ssize_t __write_ports_names(char *buf) | ||
914 | { | 940 | { |
915 | if (size == 0) { | 941 | if (nfsd_serv == NULL) |
916 | int len = 0; | 942 | return 0; |
943 | return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT); | ||
944 | } | ||
917 | 945 | ||
918 | if (nfsd_serv) | 946 | /* |
919 | len = svc_xprt_names(nfsd_serv, buf, 0); | 947 | * A single 'fd' number was written, in which case it must be for |
920 | return len; | 948 | * a socket of a supported family/protocol, and we use it as an |
921 | } | 949 | * nfsd listener. |
922 | /* Either a single 'fd' number is written, in which | 950 | */ |
923 | * case it must be for a socket of a supported family/protocol, | 951 | static ssize_t __write_ports_addfd(char *buf) |
924 | * and we use it as an nfsd socket, or | 952 | { |
925 | * A '-' followed by the 'name' of a socket in which case | 953 | char *mesg = buf; |
926 | * we close the socket. | 954 | int fd, err; |
927 | */ | 955 | |
928 | if (isdigit(buf[0])) { | 956 | err = get_int(&mesg, &fd); |
929 | char *mesg = buf; | 957 | if (err != 0 || fd < 0) |
930 | int fd; | 958 | return -EINVAL; |
931 | int err; | 959 | |
932 | err = get_int(&mesg, &fd); | 960 | err = nfsd_create_serv(); |
933 | if (err) | 961 | if (err != 0) |
934 | return -EINVAL; | 962 | return err; |
935 | if (fd < 0) | 963 | |
936 | return -EINVAL; | 964 | err = lockd_up(); |
937 | err = nfsd_create_serv(); | 965 | if (err != 0) |
938 | if (!err) { | 966 | goto out; |
939 | err = svc_addsock(nfsd_serv, fd, buf); | 967 | |
940 | if (err >= 0) { | 968 | err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); |
941 | err = lockd_up(); | 969 | if (err < 0) |
942 | if (err < 0) | 970 | lockd_down(); |
943 | svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf); | 971 | |
944 | } | 972 | out: |
945 | /* Decrease the count, but don't shutdown the | 973 | /* Decrease the count, but don't shut down the service */ |
946 | * the service | 974 | nfsd_serv->sv_nrthreads--; |
947 | */ | 975 | return err; |
948 | nfsd_serv->sv_nrthreads--; | 976 | } |
949 | } | 977 | |
950 | return err < 0 ? err : 0; | 978 | /* |
951 | } | 979 | * A '-' followed by the 'name' of a socket means we close the socket. |
952 | if (buf[0] == '-' && isdigit(buf[1])) { | 980 | */ |
953 | char *toclose = kstrdup(buf+1, GFP_KERNEL); | 981 | static ssize_t __write_ports_delfd(char *buf) |
954 | int len = 0; | 982 | { |
955 | if (!toclose) | 983 | char *toclose; |
956 | return -ENOMEM; | 984 | int len = 0; |
957 | if (nfsd_serv) | 985 | |
958 | len = svc_sock_names(buf, nfsd_serv, toclose); | 986 | toclose = kstrdup(buf + 1, GFP_KERNEL); |
959 | if (len >= 0) | 987 | if (toclose == NULL) |
960 | lockd_down(); | 988 | return -ENOMEM; |
961 | kfree(toclose); | 989 | |
962 | return len; | 990 | if (nfsd_serv != NULL) |
963 | } | 991 | len = svc_sock_names(nfsd_serv, buf, |
964 | /* | 992 | SIMPLE_TRANSACTION_LIMIT, toclose); |
965 | * Add a transport listener by writing it's transport name | 993 | if (len >= 0) |
966 | */ | 994 | lockd_down(); |
967 | if (isalpha(buf[0])) { | 995 | |
968 | int err; | 996 | kfree(toclose); |
969 | char transport[16]; | 997 | return len; |
970 | int port; | 998 | } |
971 | if (sscanf(buf, "%15s %4d", transport, &port) == 2) { | 999 | |
972 | if (port < 1 || port > 65535) | 1000 | /* |
973 | return -EINVAL; | 1001 | * A transport listener is added by writing it's transport name and |
974 | err = nfsd_create_serv(); | 1002 | * a port number. |
975 | if (!err) { | 1003 | */ |
976 | err = svc_create_xprt(nfsd_serv, | 1004 | static ssize_t __write_ports_addxprt(char *buf) |
977 | transport, PF_INET, port, | 1005 | { |
978 | SVC_SOCK_ANONYMOUS); | 1006 | char transport[16]; |
979 | if (err == -ENOENT) | 1007 | int port, err; |
980 | /* Give a reasonable perror msg for | 1008 | |
981 | * bad transport string */ | 1009 | if (sscanf(buf, "%15s %4u", transport, &port) != 2) |
982 | err = -EPROTONOSUPPORT; | 1010 | return -EINVAL; |
983 | } | 1011 | |
984 | return err < 0 ? err : 0; | 1012 | if (port < 1 || port > USHORT_MAX) |
985 | } | 1013 | return -EINVAL; |
986 | } | 1014 | |
987 | /* | 1015 | err = nfsd_create_serv(); |
988 | * Remove a transport by writing it's transport name and port number | 1016 | if (err != 0) |
989 | */ | 1017 | return err; |
990 | if (buf[0] == '-' && isalpha(buf[1])) { | 1018 | |
991 | struct svc_xprt *xprt; | 1019 | err = svc_create_xprt(nfsd_serv, transport, |
992 | int err = -EINVAL; | 1020 | PF_INET, port, SVC_SOCK_ANONYMOUS); |
993 | char transport[16]; | 1021 | if (err < 0) { |
994 | int port; | 1022 | /* Give a reasonable perror msg for bad transport string */ |
995 | if (sscanf(&buf[1], "%15s %4d", transport, &port) == 2) { | 1023 | if (err == -ENOENT) |
996 | if (port < 1 || port > 65535) | 1024 | err = -EPROTONOSUPPORT; |
997 | return -EINVAL; | 1025 | return err; |
998 | if (nfsd_serv) { | ||
999 | xprt = svc_find_xprt(nfsd_serv, transport, | ||
1000 | AF_UNSPEC, port); | ||
1001 | if (xprt) { | ||
1002 | svc_close_xprt(xprt); | ||
1003 | svc_xprt_put(xprt); | ||
1004 | err = 0; | ||
1005 | } else | ||
1006 | err = -ENOTCONN; | ||
1007 | } | ||
1008 | return err < 0 ? err : 0; | ||
1009 | } | ||
1010 | } | 1026 | } |
1027 | return 0; | ||
1028 | } | ||
1029 | |||
1030 | /* | ||
1031 | * A transport listener is removed by writing a "-", it's transport | ||
1032 | * name, and it's port number. | ||
1033 | */ | ||
1034 | static ssize_t __write_ports_delxprt(char *buf) | ||
1035 | { | ||
1036 | struct svc_xprt *xprt; | ||
1037 | char transport[16]; | ||
1038 | int port; | ||
1039 | |||
1040 | if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) | ||
1041 | return -EINVAL; | ||
1042 | |||
1043 | if (port < 1 || port > USHORT_MAX || nfsd_serv == NULL) | ||
1044 | return -EINVAL; | ||
1045 | |||
1046 | xprt = svc_find_xprt(nfsd_serv, transport, AF_UNSPEC, port); | ||
1047 | if (xprt == NULL) | ||
1048 | return -ENOTCONN; | ||
1049 | |||
1050 | svc_close_xprt(xprt); | ||
1051 | svc_xprt_put(xprt); | ||
1052 | return 0; | ||
1053 | } | ||
1054 | |||
1055 | static ssize_t __write_ports(struct file *file, char *buf, size_t size) | ||
1056 | { | ||
1057 | if (size == 0) | ||
1058 | return __write_ports_names(buf); | ||
1059 | |||
1060 | if (isdigit(buf[0])) | ||
1061 | return __write_ports_addfd(buf); | ||
1062 | |||
1063 | if (buf[0] == '-' && isdigit(buf[1])) | ||
1064 | return __write_ports_delfd(buf); | ||
1065 | |||
1066 | if (isalpha(buf[0])) | ||
1067 | return __write_ports_addxprt(buf); | ||
1068 | |||
1069 | if (buf[0] == '-' && isalpha(buf[1])) | ||
1070 | return __write_ports_delxprt(buf); | ||
1071 | |||
1011 | return -EINVAL; | 1072 | return -EINVAL; |
1012 | } | 1073 | } |
1013 | 1074 | ||
@@ -1030,7 +1091,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size) | |||
1030 | * buf: C string containing an unsigned | 1091 | * buf: C string containing an unsigned |
1031 | * integer value representing a bound | 1092 | * integer value representing a bound |
1032 | * but unconnected socket that is to be | 1093 | * but unconnected socket that is to be |
1033 | * used as an NFSD listener | 1094 | * used as an NFSD listener; listen(3) |
1095 | * must be called for a SOCK_STREAM | ||
1096 | * socket, otherwise it is ignored | ||
1034 | * size: non-zero length of C string in @buf | 1097 | * size: non-zero length of C string in @buf |
1035 | * Output: | 1098 | * Output: |
1036 | * On success: NFS service is started; | 1099 | * On success: NFS service is started; |
@@ -1138,7 +1201,9 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size) | |||
1138 | nfsd_max_blksize = bsize; | 1201 | nfsd_max_blksize = bsize; |
1139 | mutex_unlock(&nfsd_mutex); | 1202 | mutex_unlock(&nfsd_mutex); |
1140 | } | 1203 | } |
1141 | return sprintf(buf, "%d\n", nfsd_max_blksize); | 1204 | |
1205 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n", | ||
1206 | nfsd_max_blksize); | ||
1142 | } | 1207 | } |
1143 | 1208 | ||
1144 | #ifdef CONFIG_NFSD_V4 | 1209 | #ifdef CONFIG_NFSD_V4 |
@@ -1162,8 +1227,9 @@ static ssize_t __write_leasetime(struct file *file, char *buf, size_t size) | |||
1162 | return -EINVAL; | 1227 | return -EINVAL; |
1163 | nfs4_reset_lease(lease); | 1228 | nfs4_reset_lease(lease); |
1164 | } | 1229 | } |
1165 | sprintf(buf, "%ld\n", nfs4_lease_time()); | 1230 | |
1166 | return strlen(buf); | 1231 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%ld\n", |
1232 | nfs4_lease_time()); | ||
1167 | } | 1233 | } |
1168 | 1234 | ||
1169 | /** | 1235 | /** |
@@ -1219,8 +1285,9 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size) | |||
1219 | 1285 | ||
1220 | status = nfs4_reset_recoverydir(recdir); | 1286 | status = nfs4_reset_recoverydir(recdir); |
1221 | } | 1287 | } |
1222 | sprintf(buf, "%s\n", nfs4_recoverydir()); | 1288 | |
1223 | return strlen(buf); | 1289 | return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n", |
1290 | nfs4_recoverydir()); | ||
1224 | } | 1291 | } |
1225 | 1292 | ||
1226 | /** | 1293 | /** |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 9f1ca17293d3..8847f3fbfc1e 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -27,9 +27,6 @@ | |||
27 | #define NFSDDBG_FACILITY NFSDDBG_FH | 27 | #define NFSDDBG_FACILITY NFSDDBG_FH |
28 | 28 | ||
29 | 29 | ||
30 | static int nfsd_nr_verified; | ||
31 | static int nfsd_nr_put; | ||
32 | |||
33 | /* | 30 | /* |
34 | * our acceptability function. | 31 | * our acceptability function. |
35 | * if NOSUBTREECHECK, accept anything | 32 | * if NOSUBTREECHECK, accept anything |
@@ -251,7 +248,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
251 | 248 | ||
252 | fhp->fh_dentry = dentry; | 249 | fhp->fh_dentry = dentry; |
253 | fhp->fh_export = exp; | 250 | fhp->fh_export = exp; |
254 | nfsd_nr_verified++; | ||
255 | return 0; | 251 | return 0; |
256 | out: | 252 | out: |
257 | exp_put(exp); | 253 | exp_put(exp); |
@@ -552,7 +548,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
552 | return nfserr_opnotsupp; | 548 | return nfserr_opnotsupp; |
553 | } | 549 | } |
554 | 550 | ||
555 | nfsd_nr_verified++; | ||
556 | return 0; | 551 | return 0; |
557 | } | 552 | } |
558 | 553 | ||
@@ -609,7 +604,6 @@ fh_put(struct svc_fh *fhp) | |||
609 | fhp->fh_pre_saved = 0; | 604 | fhp->fh_pre_saved = 0; |
610 | fhp->fh_post_saved = 0; | 605 | fhp->fh_post_saved = 0; |
611 | #endif | 606 | #endif |
612 | nfsd_nr_put++; | ||
613 | } | 607 | } |
614 | if (exp) { | 608 | if (exp) { |
615 | cache_put(&exp->h, &svc_export_cache); | 609 | cache_put(&exp->h, &svc_export_cache); |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index e298e260b5f1..0eb9c820b7a6 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -533,45 +533,179 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, | |||
533 | * NFSv2 Server procedures. | 533 | * NFSv2 Server procedures. |
534 | * Only the results of non-idempotent operations are cached. | 534 | * Only the results of non-idempotent operations are cached. |
535 | */ | 535 | */ |
536 | #define nfsd_proc_none NULL | ||
537 | #define nfssvc_release_none NULL | ||
538 | struct nfsd_void { int dummy; }; | 536 | struct nfsd_void { int dummy; }; |
539 | 537 | ||
540 | #define PROC(name, argt, rest, relt, cache, respsize) \ | ||
541 | { (svc_procfunc) nfsd_proc_##name, \ | ||
542 | (kxdrproc_t) nfssvc_decode_##argt, \ | ||
543 | (kxdrproc_t) nfssvc_encode_##rest, \ | ||
544 | (kxdrproc_t) nfssvc_release_##relt, \ | ||
545 | sizeof(struct nfsd_##argt), \ | ||
546 | sizeof(struct nfsd_##rest), \ | ||
547 | 0, \ | ||
548 | cache, \ | ||
549 | respsize, \ | ||
550 | } | ||
551 | |||
552 | #define ST 1 /* status */ | 538 | #define ST 1 /* status */ |
553 | #define FH 8 /* filehandle */ | 539 | #define FH 8 /* filehandle */ |
554 | #define AT 18 /* attributes */ | 540 | #define AT 18 /* attributes */ |
555 | 541 | ||
556 | static struct svc_procedure nfsd_procedures2[18] = { | 542 | static struct svc_procedure nfsd_procedures2[18] = { |
557 | PROC(null, void, void, none, RC_NOCACHE, ST), | 543 | [NFSPROC_NULL] = { |
558 | PROC(getattr, fhandle, attrstat, fhandle, RC_NOCACHE, ST+AT), | 544 | .pc_func = (svc_procfunc) nfsd_proc_null, |
559 | PROC(setattr, sattrargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 545 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, |
560 | PROC(none, void, void, none, RC_NOCACHE, ST), | 546 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, |
561 | PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT), | 547 | .pc_argsize = sizeof(struct nfsd_void), |
562 | PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4), | 548 | .pc_ressize = sizeof(struct nfsd_void), |
563 | PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4), | 549 | .pc_cachetype = RC_NOCACHE, |
564 | PROC(none, void, void, none, RC_NOCACHE, ST), | 550 | .pc_xdrressize = ST, |
565 | PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT), | 551 | }, |
566 | PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 552 | [NFSPROC_GETATTR] = { |
567 | PROC(remove, diropargs, void, none, RC_REPLSTAT, ST), | 553 | .pc_func = (svc_procfunc) nfsd_proc_getattr, |
568 | PROC(rename, renameargs, void, none, RC_REPLSTAT, ST), | 554 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, |
569 | PROC(link, linkargs, void, none, RC_REPLSTAT, ST), | 555 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, |
570 | PROC(symlink, symlinkargs, void, none, RC_REPLSTAT, ST), | 556 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, |
571 | PROC(mkdir, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT), | 557 | .pc_argsize = sizeof(struct nfsd_fhandle), |
572 | PROC(rmdir, diropargs, void, none, RC_REPLSTAT, ST), | 558 | .pc_ressize = sizeof(struct nfsd_attrstat), |
573 | PROC(readdir, readdirargs, readdirres, none, RC_NOCACHE, 0), | 559 | .pc_cachetype = RC_NOCACHE, |
574 | PROC(statfs, fhandle, statfsres, none, RC_NOCACHE, ST+5), | 560 | .pc_xdrressize = ST+AT, |
561 | }, | ||
562 | [NFSPROC_SETATTR] = { | ||
563 | .pc_func = (svc_procfunc) nfsd_proc_setattr, | ||
564 | .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs, | ||
565 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
566 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
567 | .pc_argsize = sizeof(struct nfsd_sattrargs), | ||
568 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
569 | .pc_cachetype = RC_REPLBUFF, | ||
570 | .pc_xdrressize = ST+AT, | ||
571 | }, | ||
572 | [NFSPROC_ROOT] = { | ||
573 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
574 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
575 | .pc_argsize = sizeof(struct nfsd_void), | ||
576 | .pc_ressize = sizeof(struct nfsd_void), | ||
577 | .pc_cachetype = RC_NOCACHE, | ||
578 | .pc_xdrressize = ST, | ||
579 | }, | ||
580 | [NFSPROC_LOOKUP] = { | ||
581 | .pc_func = (svc_procfunc) nfsd_proc_lookup, | ||
582 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
583 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
584 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
585 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
586 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
587 | .pc_cachetype = RC_NOCACHE, | ||
588 | .pc_xdrressize = ST+FH+AT, | ||
589 | }, | ||
590 | [NFSPROC_READLINK] = { | ||
591 | .pc_func = (svc_procfunc) nfsd_proc_readlink, | ||
592 | .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs, | ||
593 | .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres, | ||
594 | .pc_argsize = sizeof(struct nfsd_readlinkargs), | ||
595 | .pc_ressize = sizeof(struct nfsd_readlinkres), | ||
596 | .pc_cachetype = RC_NOCACHE, | ||
597 | .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, | ||
598 | }, | ||
599 | [NFSPROC_READ] = { | ||
600 | .pc_func = (svc_procfunc) nfsd_proc_read, | ||
601 | .pc_decode = (kxdrproc_t) nfssvc_decode_readargs, | ||
602 | .pc_encode = (kxdrproc_t) nfssvc_encode_readres, | ||
603 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
604 | .pc_argsize = sizeof(struct nfsd_readargs), | ||
605 | .pc_ressize = sizeof(struct nfsd_readres), | ||
606 | .pc_cachetype = RC_NOCACHE, | ||
607 | .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, | ||
608 | }, | ||
609 | [NFSPROC_WRITECACHE] = { | ||
610 | .pc_decode = (kxdrproc_t) nfssvc_decode_void, | ||
611 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
612 | .pc_argsize = sizeof(struct nfsd_void), | ||
613 | .pc_ressize = sizeof(struct nfsd_void), | ||
614 | .pc_cachetype = RC_NOCACHE, | ||
615 | .pc_xdrressize = ST, | ||
616 | }, | ||
617 | [NFSPROC_WRITE] = { | ||
618 | .pc_func = (svc_procfunc) nfsd_proc_write, | ||
619 | .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs, | ||
620 | .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, | ||
621 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
622 | .pc_argsize = sizeof(struct nfsd_writeargs), | ||
623 | .pc_ressize = sizeof(struct nfsd_attrstat), | ||
624 | .pc_cachetype = RC_REPLBUFF, | ||
625 | .pc_xdrressize = ST+AT, | ||
626 | }, | ||
627 | [NFSPROC_CREATE] = { | ||
628 | .pc_func = (svc_procfunc) nfsd_proc_create, | ||
629 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
630 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
631 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
632 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
633 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
634 | .pc_cachetype = RC_REPLBUFF, | ||
635 | .pc_xdrressize = ST+FH+AT, | ||
636 | }, | ||
637 | [NFSPROC_REMOVE] = { | ||
638 | .pc_func = (svc_procfunc) nfsd_proc_remove, | ||
639 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
640 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
641 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
642 | .pc_ressize = sizeof(struct nfsd_void), | ||
643 | .pc_cachetype = RC_REPLSTAT, | ||
644 | .pc_xdrressize = ST, | ||
645 | }, | ||
646 | [NFSPROC_RENAME] = { | ||
647 | .pc_func = (svc_procfunc) nfsd_proc_rename, | ||
648 | .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs, | ||
649 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
650 | .pc_argsize = sizeof(struct nfsd_renameargs), | ||
651 | .pc_ressize = sizeof(struct nfsd_void), | ||
652 | .pc_cachetype = RC_REPLSTAT, | ||
653 | .pc_xdrressize = ST, | ||
654 | }, | ||
655 | [NFSPROC_LINK] = { | ||
656 | .pc_func = (svc_procfunc) nfsd_proc_link, | ||
657 | .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs, | ||
658 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
659 | .pc_argsize = sizeof(struct nfsd_linkargs), | ||
660 | .pc_ressize = sizeof(struct nfsd_void), | ||
661 | .pc_cachetype = RC_REPLSTAT, | ||
662 | .pc_xdrressize = ST, | ||
663 | }, | ||
664 | [NFSPROC_SYMLINK] = { | ||
665 | .pc_func = (svc_procfunc) nfsd_proc_symlink, | ||
666 | .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs, | ||
667 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
668 | .pc_argsize = sizeof(struct nfsd_symlinkargs), | ||
669 | .pc_ressize = sizeof(struct nfsd_void), | ||
670 | .pc_cachetype = RC_REPLSTAT, | ||
671 | .pc_xdrressize = ST, | ||
672 | }, | ||
673 | [NFSPROC_MKDIR] = { | ||
674 | .pc_func = (svc_procfunc) nfsd_proc_mkdir, | ||
675 | .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, | ||
676 | .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, | ||
677 | .pc_release = (kxdrproc_t) nfssvc_release_fhandle, | ||
678 | .pc_argsize = sizeof(struct nfsd_createargs), | ||
679 | .pc_ressize = sizeof(struct nfsd_diropres), | ||
680 | .pc_cachetype = RC_REPLBUFF, | ||
681 | .pc_xdrressize = ST+FH+AT, | ||
682 | }, | ||
683 | [NFSPROC_RMDIR] = { | ||
684 | .pc_func = (svc_procfunc) nfsd_proc_rmdir, | ||
685 | .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, | ||
686 | .pc_encode = (kxdrproc_t) nfssvc_encode_void, | ||
687 | .pc_argsize = sizeof(struct nfsd_diropargs), | ||
688 | .pc_ressize = sizeof(struct nfsd_void), | ||
689 | .pc_cachetype = RC_REPLSTAT, | ||
690 | .pc_xdrressize = ST, | ||
691 | }, | ||
692 | [NFSPROC_READDIR] = { | ||
693 | .pc_func = (svc_procfunc) nfsd_proc_readdir, | ||
694 | .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs, | ||
695 | .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres, | ||
696 | .pc_argsize = sizeof(struct nfsd_readdirargs), | ||
697 | .pc_ressize = sizeof(struct nfsd_readdirres), | ||
698 | .pc_cachetype = RC_NOCACHE, | ||
699 | }, | ||
700 | [NFSPROC_STATFS] = { | ||
701 | .pc_func = (svc_procfunc) nfsd_proc_statfs, | ||
702 | .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, | ||
703 | .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres, | ||
704 | .pc_argsize = sizeof(struct nfsd_fhandle), | ||
705 | .pc_ressize = sizeof(struct nfsd_statfsres), | ||
706 | .pc_cachetype = RC_NOCACHE, | ||
707 | .pc_xdrressize = ST+5, | ||
708 | }, | ||
575 | }; | 709 | }; |
576 | 710 | ||
577 | 711 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index cbba4a935786..492c79b7800b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/unistd.h> | 18 | #include <linux/unistd.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
21 | #include <linux/smp_lock.h> | ||
22 | #include <linux/freezer.h> | 21 | #include <linux/freezer.h> |
23 | #include <linux/fs_struct.h> | 22 | #include <linux/fs_struct.h> |
24 | #include <linux/kthread.h> | 23 | #include <linux/kthread.h> |
@@ -390,12 +389,14 @@ nfsd_svc(unsigned short port, int nrservs) | |||
390 | 389 | ||
391 | mutex_lock(&nfsd_mutex); | 390 | mutex_lock(&nfsd_mutex); |
392 | dprintk("nfsd: creating service\n"); | 391 | dprintk("nfsd: creating service\n"); |
393 | error = -EINVAL; | ||
394 | if (nrservs <= 0) | 392 | if (nrservs <= 0) |
395 | nrservs = 0; | 393 | nrservs = 0; |
396 | if (nrservs > NFSD_MAXSERVS) | 394 | if (nrservs > NFSD_MAXSERVS) |
397 | nrservs = NFSD_MAXSERVS; | 395 | nrservs = NFSD_MAXSERVS; |
398 | 396 | error = 0; | |
397 | if (nrservs == 0 && nfsd_serv == NULL) | ||
398 | goto out; | ||
399 | |||
399 | /* Readahead param cache - will no-op if it already exists */ | 400 | /* Readahead param cache - will no-op if it already exists */ |
400 | error = nfsd_racache_init(2*nrservs); | 401 | error = nfsd_racache_init(2*nrservs); |
401 | if (error<0) | 402 | if (error<0) |
@@ -413,6 +414,12 @@ nfsd_svc(unsigned short port, int nrservs) | |||
413 | goto failure; | 414 | goto failure; |
414 | 415 | ||
415 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); | 416 | error = svc_set_num_threads(nfsd_serv, NULL, nrservs); |
417 | if (error == 0) | ||
418 | /* We are holding a reference to nfsd_serv which | ||
419 | * we don't want to count in the return value, | ||
420 | * so subtract 1 | ||
421 | */ | ||
422 | error = nfsd_serv->sv_nrthreads - 1; | ||
416 | failure: | 423 | failure: |
417 | svc_destroy(nfsd_serv); /* Release server */ | 424 | svc_destroy(nfsd_serv); /* Release server */ |
418 | out: | 425 | out: |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 99f835753596..23341c1063bc 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -678,7 +678,6 @@ __be32 | |||
678 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | 678 | nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, |
679 | int access, struct file **filp) | 679 | int access, struct file **filp) |
680 | { | 680 | { |
681 | const struct cred *cred = current_cred(); | ||
682 | struct dentry *dentry; | 681 | struct dentry *dentry; |
683 | struct inode *inode; | 682 | struct inode *inode; |
684 | int flags = O_RDONLY|O_LARGEFILE; | 683 | int flags = O_RDONLY|O_LARGEFILE; |
@@ -733,7 +732,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
733 | vfs_dq_init(inode); | 732 | vfs_dq_init(inode); |
734 | } | 733 | } |
735 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), | 734 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), |
736 | flags, cred); | 735 | flags, current_cred()); |
737 | if (IS_ERR(*filp)) | 736 | if (IS_ERR(*filp)) |
738 | host_err = PTR_ERR(*filp); | 737 | host_err = PTR_ERR(*filp); |
739 | else | 738 | else |
@@ -966,6 +965,43 @@ static void kill_suid(struct dentry *dentry) | |||
966 | mutex_unlock(&dentry->d_inode->i_mutex); | 965 | mutex_unlock(&dentry->d_inode->i_mutex); |
967 | } | 966 | } |
968 | 967 | ||
968 | /* | ||
969 | * Gathered writes: If another process is currently writing to the file, | ||
970 | * there's a high chance this is another nfsd (triggered by a bulk write | ||
971 | * from a client's biod). Rather than syncing the file with each write | ||
972 | * request, we sleep for 10 msec. | ||
973 | * | ||
974 | * I don't know if this roughly approximates C. Juszak's idea of | ||
975 | * gathered writes, but it's a nice and simple solution (IMHO), and it | ||
976 | * seems to work:-) | ||
977 | * | ||
978 | * Note: we do this only in the NFSv2 case, since v3 and higher have a | ||
979 | * better tool (separate unstable writes and commits) for solving this | ||
980 | * problem. | ||
981 | */ | ||
982 | static int wait_for_concurrent_writes(struct file *file) | ||
983 | { | ||
984 | struct inode *inode = file->f_path.dentry->d_inode; | ||
985 | static ino_t last_ino; | ||
986 | static dev_t last_dev; | ||
987 | int err = 0; | ||
988 | |||
989 | if (atomic_read(&inode->i_writecount) > 1 | ||
990 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
991 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
992 | msleep(10); | ||
993 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
994 | } | ||
995 | |||
996 | if (inode->i_state & I_DIRTY) { | ||
997 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
998 | err = nfsd_sync(file); | ||
999 | } | ||
1000 | last_ino = inode->i_ino; | ||
1001 | last_dev = inode->i_sb->s_dev; | ||
1002 | return err; | ||
1003 | } | ||
1004 | |||
969 | static __be32 | 1005 | static __be32 |
970 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1006 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
971 | loff_t offset, struct kvec *vec, int vlen, | 1007 | loff_t offset, struct kvec *vec, int vlen, |
@@ -978,6 +1014,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
978 | __be32 err = 0; | 1014 | __be32 err = 0; |
979 | int host_err; | 1015 | int host_err; |
980 | int stable = *stablep; | 1016 | int stable = *stablep; |
1017 | int use_wgather; | ||
981 | 1018 | ||
982 | #ifdef MSNFS | 1019 | #ifdef MSNFS |
983 | err = nfserr_perm; | 1020 | err = nfserr_perm; |
@@ -996,9 +1033,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
996 | * - the sync export option has been set, or | 1033 | * - the sync export option has been set, or |
997 | * - the client requested O_SYNC behavior (NFSv3 feature). | 1034 | * - the client requested O_SYNC behavior (NFSv3 feature). |
998 | * - The file system doesn't support fsync(). | 1035 | * - The file system doesn't support fsync(). |
999 | * When gathered writes have been configured for this volume, | 1036 | * When NFSv2 gathered writes have been configured for this volume, |
1000 | * flushing the data to disk is handled separately below. | 1037 | * flushing the data to disk is handled separately below. |
1001 | */ | 1038 | */ |
1039 | use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); | ||
1002 | 1040 | ||
1003 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ | 1041 | if (!file->f_op->fsync) {/* COMMIT3 cannot work */ |
1004 | stable = 2; | 1042 | stable = 2; |
@@ -1007,7 +1045,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1007 | 1045 | ||
1008 | if (!EX_ISSYNC(exp)) | 1046 | if (!EX_ISSYNC(exp)) |
1009 | stable = 0; | 1047 | stable = 0; |
1010 | if (stable && !EX_WGATHER(exp)) { | 1048 | if (stable && !use_wgather) { |
1011 | spin_lock(&file->f_lock); | 1049 | spin_lock(&file->f_lock); |
1012 | file->f_flags |= O_SYNC; | 1050 | file->f_flags |= O_SYNC; |
1013 | spin_unlock(&file->f_lock); | 1051 | spin_unlock(&file->f_lock); |
@@ -1017,52 +1055,20 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1017 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1055 | oldfs = get_fs(); set_fs(KERNEL_DS); |
1018 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); | 1056 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); |
1019 | set_fs(oldfs); | 1057 | set_fs(oldfs); |
1020 | if (host_err >= 0) { | 1058 | if (host_err < 0) |
1021 | *cnt = host_err; | 1059 | goto out_nfserr; |
1022 | nfsdstats.io_write += host_err; | 1060 | *cnt = host_err; |
1023 | fsnotify_modify(file->f_path.dentry); | 1061 | nfsdstats.io_write += host_err; |
1024 | } | 1062 | fsnotify_modify(file->f_path.dentry); |
1025 | 1063 | ||
1026 | /* clear setuid/setgid flag after write */ | 1064 | /* clear setuid/setgid flag after write */ |
1027 | if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID))) | 1065 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
1028 | kill_suid(dentry); | 1066 | kill_suid(dentry); |
1029 | 1067 | ||
1030 | if (host_err >= 0 && stable) { | 1068 | if (stable && use_wgather) |
1031 | static ino_t last_ino; | 1069 | host_err = wait_for_concurrent_writes(file); |
1032 | static dev_t last_dev; | ||
1033 | |||
1034 | /* | ||
1035 | * Gathered writes: If another process is currently | ||
1036 | * writing to the file, there's a high chance | ||
1037 | * this is another nfsd (triggered by a bulk write | ||
1038 | * from a client's biod). Rather than syncing the | ||
1039 | * file with each write request, we sleep for 10 msec. | ||
1040 | * | ||
1041 | * I don't know if this roughly approximates | ||
1042 | * C. Juszak's idea of gathered writes, but it's a | ||
1043 | * nice and simple solution (IMHO), and it seems to | ||
1044 | * work:-) | ||
1045 | */ | ||
1046 | if (EX_WGATHER(exp)) { | ||
1047 | if (atomic_read(&inode->i_writecount) > 1 | ||
1048 | || (last_ino == inode->i_ino && last_dev == inode->i_sb->s_dev)) { | ||
1049 | dprintk("nfsd: write defer %d\n", task_pid_nr(current)); | ||
1050 | msleep(10); | ||
1051 | dprintk("nfsd: write resume %d\n", task_pid_nr(current)); | ||
1052 | } | ||
1053 | |||
1054 | if (inode->i_state & I_DIRTY) { | ||
1055 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | ||
1056 | host_err=nfsd_sync(file); | ||
1057 | } | ||
1058 | #if 0 | ||
1059 | wake_up(&inode->i_wait); | ||
1060 | #endif | ||
1061 | } | ||
1062 | last_ino = inode->i_ino; | ||
1063 | last_dev = inode->i_sb->s_dev; | ||
1064 | } | ||
1065 | 1070 | ||
1071 | out_nfserr: | ||
1066 | dprintk("nfsd: write complete host_err=%d\n", host_err); | 1072 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
1067 | if (host_err >= 0) | 1073 | if (host_err >= 0) |
1068 | err = 0; | 1074 | err = 0; |
diff --git a/fs/nilfs2/Kconfig b/fs/nilfs2/Kconfig new file mode 100644 index 000000000000..72da095d4009 --- /dev/null +++ b/fs/nilfs2/Kconfig | |||
@@ -0,0 +1,25 @@ | |||
1 | config NILFS2_FS | ||
2 | tristate "NILFS2 file system support (EXPERIMENTAL)" | ||
3 | depends on BLOCK && EXPERIMENTAL | ||
4 | select CRC32 | ||
5 | help | ||
6 | NILFS2 is a log-structured file system (LFS) supporting continuous | ||
7 | snapshotting. In addition to versioning capability of the entire | ||
8 | file system, users can even restore files mistakenly overwritten or | ||
9 | destroyed just a few seconds ago. Since this file system can keep | ||
10 | consistency like conventional LFS, it achieves quick recovery after | ||
11 | system crashes. | ||
12 | |||
13 | NILFS2 creates a number of checkpoints every few seconds or per | ||
14 | synchronous write basis (unless there is no change). Users can | ||
15 | select significant versions among continuously created checkpoints, | ||
16 | and can change them into snapshots which will be preserved for long | ||
17 | periods until they are changed back to checkpoints. Each | ||
18 | snapshot is mountable as a read-only file system concurrently with | ||
19 | its writable mount, and this feature is convenient for online backup. | ||
20 | |||
21 | Some features including atime, extended attributes, and POSIX ACLs, | ||
22 | are not supported yet. | ||
23 | |||
24 | To compile this file system support as a module, choose M here: the | ||
25 | module will be called nilfs2. If unsure, say N. | ||
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 064279e33bbb..99d58a028b94 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c | |||
@@ -31,21 +31,26 @@ | |||
31 | #include "dat.h" | 31 | #include "dat.h" |
32 | #include "alloc.h" | 32 | #include "alloc.h" |
33 | 33 | ||
34 | struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) | ||
35 | { | ||
36 | return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); | ||
37 | } | ||
38 | |||
34 | int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, | 39 | int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, |
35 | __u64 *ptrp) | 40 | __u64 *ptrp) |
36 | { | 41 | { |
37 | __u64 ptr; | 42 | sector_t blocknr; |
38 | int ret; | 43 | int ret; |
39 | 44 | ||
40 | down_read(&bmap->b_sem); | 45 | down_read(&bmap->b_sem); |
41 | ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); | 46 | ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); |
42 | if (ret < 0) | 47 | if (ret < 0) |
43 | goto out; | 48 | goto out; |
44 | if (bmap->b_pops->bpop_translate != NULL) { | 49 | if (NILFS_BMAP_USE_VBN(bmap)) { |
45 | ret = bmap->b_pops->bpop_translate(bmap, *ptrp, &ptr); | 50 | ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), *ptrp, |
46 | if (ret < 0) | 51 | &blocknr); |
47 | goto out; | 52 | if (!ret) |
48 | *ptrp = ptr; | 53 | *ptrp = blocknr; |
49 | } | 54 | } |
50 | 55 | ||
51 | out: | 56 | out: |
@@ -53,6 +58,16 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, | |||
53 | return ret; | 58 | return ret; |
54 | } | 59 | } |
55 | 60 | ||
61 | int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp, | ||
62 | unsigned maxblocks) | ||
63 | { | ||
64 | int ret; | ||
65 | |||
66 | down_read(&bmap->b_sem); | ||
67 | ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks); | ||
68 | up_read(&bmap->b_sem); | ||
69 | return ret; | ||
70 | } | ||
56 | 71 | ||
57 | /** | 72 | /** |
58 | * nilfs_bmap_lookup - find a record | 73 | * nilfs_bmap_lookup - find a record |
@@ -101,8 +116,7 @@ static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | |||
101 | if (n < 0) | 116 | if (n < 0) |
102 | return n; | 117 | return n; |
103 | ret = nilfs_btree_convert_and_insert( | 118 | ret = nilfs_btree_convert_and_insert( |
104 | bmap, key, ptr, keys, ptrs, n, | 119 | bmap, key, ptr, keys, ptrs, n); |
105 | NILFS_BMAP_LARGE_LOW, NILFS_BMAP_LARGE_HIGH); | ||
106 | if (ret == 0) | 120 | if (ret == 0) |
107 | bmap->b_u.u_flags |= NILFS_BMAP_LARGE; | 121 | bmap->b_u.u_flags |= NILFS_BMAP_LARGE; |
108 | 122 | ||
@@ -158,8 +172,7 @@ static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) | |||
158 | if (n < 0) | 172 | if (n < 0) |
159 | return n; | 173 | return n; |
160 | ret = nilfs_direct_delete_and_convert( | 174 | ret = nilfs_direct_delete_and_convert( |
161 | bmap, key, keys, ptrs, n, | 175 | bmap, key, keys, ptrs, n); |
162 | NILFS_BMAP_SMALL_LOW, NILFS_BMAP_SMALL_HIGH); | ||
163 | if (ret == 0) | 176 | if (ret == 0) |
164 | bmap->b_u.u_flags &= ~NILFS_BMAP_LARGE; | 177 | bmap->b_u.u_flags &= ~NILFS_BMAP_LARGE; |
165 | 178 | ||
@@ -417,38 +430,6 @@ void nilfs_bmap_sub_blocks(const struct nilfs_bmap *bmap, int n) | |||
417 | mark_inode_dirty(bmap->b_inode); | 430 | mark_inode_dirty(bmap->b_inode); |
418 | } | 431 | } |
419 | 432 | ||
420 | int nilfs_bmap_get_block(const struct nilfs_bmap *bmap, __u64 ptr, | ||
421 | struct buffer_head **bhp) | ||
422 | { | ||
423 | return nilfs_btnode_get(&NILFS_BMAP_I(bmap)->i_btnode_cache, | ||
424 | ptr, 0, bhp, 0); | ||
425 | } | ||
426 | |||
427 | void nilfs_bmap_put_block(const struct nilfs_bmap *bmap, | ||
428 | struct buffer_head *bh) | ||
429 | { | ||
430 | brelse(bh); | ||
431 | } | ||
432 | |||
433 | int nilfs_bmap_get_new_block(const struct nilfs_bmap *bmap, __u64 ptr, | ||
434 | struct buffer_head **bhp) | ||
435 | { | ||
436 | int ret; | ||
437 | |||
438 | ret = nilfs_btnode_get(&NILFS_BMAP_I(bmap)->i_btnode_cache, | ||
439 | ptr, 0, bhp, 1); | ||
440 | if (ret < 0) | ||
441 | return ret; | ||
442 | set_buffer_nilfs_volatile(*bhp); | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | void nilfs_bmap_delete_block(const struct nilfs_bmap *bmap, | ||
447 | struct buffer_head *bh) | ||
448 | { | ||
449 | nilfs_btnode_delete(bh); | ||
450 | } | ||
451 | |||
452 | __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *bmap, | 433 | __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *bmap, |
453 | const struct buffer_head *bh) | 434 | const struct buffer_head *bh) |
454 | { | 435 | { |
@@ -476,11 +457,6 @@ __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *bmap, __u64 key) | |||
476 | return NILFS_BMAP_INVALID_PTR; | 457 | return NILFS_BMAP_INVALID_PTR; |
477 | } | 458 | } |
478 | 459 | ||
479 | static struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) | ||
480 | { | ||
481 | return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); | ||
482 | } | ||
483 | |||
484 | #define NILFS_BMAP_GROUP_DIV 8 | 460 | #define NILFS_BMAP_GROUP_DIV 8 |
485 | __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) | 461 | __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) |
486 | { | 462 | { |
@@ -493,64 +469,51 @@ __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap) | |||
493 | (entries_per_group / NILFS_BMAP_GROUP_DIV); | 469 | (entries_per_group / NILFS_BMAP_GROUP_DIV); |
494 | } | 470 | } |
495 | 471 | ||
496 | static int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, | 472 | int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *bmap, |
497 | union nilfs_bmap_ptr_req *req) | 473 | union nilfs_bmap_ptr_req *req) |
498 | { | 474 | { |
499 | return nilfs_dat_prepare_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 475 | return nilfs_dat_prepare_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); |
500 | } | 476 | } |
501 | 477 | ||
502 | static void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, | 478 | void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *bmap, |
503 | union nilfs_bmap_ptr_req *req) | 479 | union nilfs_bmap_ptr_req *req) |
504 | { | 480 | { |
505 | nilfs_dat_commit_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 481 | nilfs_dat_commit_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); |
506 | } | 482 | } |
507 | 483 | ||
508 | static void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, | 484 | void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *bmap, |
509 | union nilfs_bmap_ptr_req *req) | 485 | union nilfs_bmap_ptr_req *req) |
510 | { | 486 | { |
511 | nilfs_dat_abort_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 487 | nilfs_dat_abort_alloc(nilfs_bmap_get_dat(bmap), &req->bpr_req); |
512 | } | 488 | } |
513 | 489 | ||
514 | static int nilfs_bmap_prepare_start_v(struct nilfs_bmap *bmap, | 490 | int nilfs_bmap_start_v(struct nilfs_bmap *bmap, union nilfs_bmap_ptr_req *req, |
515 | union nilfs_bmap_ptr_req *req) | 491 | sector_t blocknr) |
516 | { | 492 | { |
517 | return nilfs_dat_prepare_start(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 493 | struct inode *dat = nilfs_bmap_get_dat(bmap); |
518 | } | 494 | int ret; |
519 | |||
520 | static void nilfs_bmap_commit_start_v(struct nilfs_bmap *bmap, | ||
521 | union nilfs_bmap_ptr_req *req, | ||
522 | sector_t blocknr) | ||
523 | { | ||
524 | nilfs_dat_commit_start(nilfs_bmap_get_dat(bmap), &req->bpr_req, | ||
525 | blocknr); | ||
526 | } | ||
527 | 495 | ||
528 | static void nilfs_bmap_abort_start_v(struct nilfs_bmap *bmap, | 496 | ret = nilfs_dat_prepare_start(dat, &req->bpr_req); |
529 | union nilfs_bmap_ptr_req *req) | 497 | if (likely(!ret)) |
530 | { | 498 | nilfs_dat_commit_start(dat, &req->bpr_req, blocknr); |
531 | nilfs_dat_abort_start(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 499 | return ret; |
532 | } | 500 | } |
533 | 501 | ||
534 | static int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, | 502 | int nilfs_bmap_prepare_end_v(struct nilfs_bmap *bmap, |
535 | union nilfs_bmap_ptr_req *req) | 503 | union nilfs_bmap_ptr_req *req) |
536 | { | 504 | { |
537 | return nilfs_dat_prepare_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 505 | return nilfs_dat_prepare_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); |
538 | } | 506 | } |
539 | 507 | ||
540 | static void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, | 508 | void nilfs_bmap_commit_end_v(struct nilfs_bmap *bmap, |
541 | union nilfs_bmap_ptr_req *req) | 509 | union nilfs_bmap_ptr_req *req) |
542 | { | ||
543 | nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, 0); | ||
544 | } | ||
545 | |||
546 | static void nilfs_bmap_commit_end_vmdt(struct nilfs_bmap *bmap, | ||
547 | union nilfs_bmap_ptr_req *req) | ||
548 | { | 510 | { |
549 | nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, 1); | 511 | nilfs_dat_commit_end(nilfs_bmap_get_dat(bmap), &req->bpr_req, |
512 | bmap->b_ptr_type == NILFS_BMAP_PTR_VS); | ||
550 | } | 513 | } |
551 | 514 | ||
552 | static void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, | 515 | void nilfs_bmap_abort_end_v(struct nilfs_bmap *bmap, |
553 | union nilfs_bmap_ptr_req *req) | 516 | union nilfs_bmap_ptr_req *req) |
554 | { | 517 | { |
555 | nilfs_dat_abort_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); | 518 | nilfs_dat_abort_end(nilfs_bmap_get_dat(bmap), &req->bpr_req); |
556 | } | 519 | } |
@@ -566,129 +529,46 @@ int nilfs_bmap_mark_dirty(const struct nilfs_bmap *bmap, __u64 vblocknr) | |||
566 | return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), vblocknr); | 529 | return nilfs_dat_mark_dirty(nilfs_bmap_get_dat(bmap), vblocknr); |
567 | } | 530 | } |
568 | 531 | ||
569 | int nilfs_bmap_prepare_update(struct nilfs_bmap *bmap, | 532 | int nilfs_bmap_prepare_update_v(struct nilfs_bmap *bmap, |
570 | union nilfs_bmap_ptr_req *oldreq, | 533 | union nilfs_bmap_ptr_req *oldreq, |
571 | union nilfs_bmap_ptr_req *newreq) | 534 | union nilfs_bmap_ptr_req *newreq) |
572 | { | 535 | { |
536 | struct inode *dat = nilfs_bmap_get_dat(bmap); | ||
573 | int ret; | 537 | int ret; |
574 | 538 | ||
575 | ret = bmap->b_pops->bpop_prepare_end_ptr(bmap, oldreq); | 539 | ret = nilfs_dat_prepare_end(dat, &oldreq->bpr_req); |
576 | if (ret < 0) | 540 | if (ret < 0) |
577 | return ret; | 541 | return ret; |
578 | ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, newreq); | 542 | ret = nilfs_dat_prepare_alloc(dat, &newreq->bpr_req); |
579 | if (ret < 0) | 543 | if (ret < 0) |
580 | bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); | 544 | nilfs_dat_abort_end(dat, &oldreq->bpr_req); |
581 | 545 | ||
582 | return ret; | 546 | return ret; |
583 | } | 547 | } |
584 | 548 | ||
585 | void nilfs_bmap_commit_update(struct nilfs_bmap *bmap, | 549 | void nilfs_bmap_commit_update_v(struct nilfs_bmap *bmap, |
586 | union nilfs_bmap_ptr_req *oldreq, | 550 | union nilfs_bmap_ptr_req *oldreq, |
587 | union nilfs_bmap_ptr_req *newreq) | 551 | union nilfs_bmap_ptr_req *newreq) |
588 | { | 552 | { |
589 | bmap->b_pops->bpop_commit_end_ptr(bmap, oldreq); | 553 | struct inode *dat = nilfs_bmap_get_dat(bmap); |
590 | bmap->b_pops->bpop_commit_alloc_ptr(bmap, newreq); | ||
591 | } | ||
592 | 554 | ||
593 | void nilfs_bmap_abort_update(struct nilfs_bmap *bmap, | 555 | nilfs_dat_commit_end(dat, &oldreq->bpr_req, |
594 | union nilfs_bmap_ptr_req *oldreq, | 556 | bmap->b_ptr_type == NILFS_BMAP_PTR_VS); |
595 | union nilfs_bmap_ptr_req *newreq) | 557 | nilfs_dat_commit_alloc(dat, &newreq->bpr_req); |
596 | { | ||
597 | bmap->b_pops->bpop_abort_end_ptr(bmap, oldreq); | ||
598 | bmap->b_pops->bpop_abort_alloc_ptr(bmap, newreq); | ||
599 | } | 558 | } |
600 | 559 | ||
601 | static int nilfs_bmap_translate_v(const struct nilfs_bmap *bmap, __u64 ptr, | 560 | void nilfs_bmap_abort_update_v(struct nilfs_bmap *bmap, |
602 | __u64 *ptrp) | 561 | union nilfs_bmap_ptr_req *oldreq, |
562 | union nilfs_bmap_ptr_req *newreq) | ||
603 | { | 563 | { |
604 | sector_t blocknr; | 564 | struct inode *dat = nilfs_bmap_get_dat(bmap); |
605 | int ret; | ||
606 | |||
607 | ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), ptr, &blocknr); | ||
608 | if (ret < 0) | ||
609 | return ret; | ||
610 | if (ptrp != NULL) | ||
611 | *ptrp = blocknr; | ||
612 | return 0; | ||
613 | } | ||
614 | 565 | ||
615 | static int nilfs_bmap_prepare_alloc_p(struct nilfs_bmap *bmap, | 566 | nilfs_dat_abort_end(dat, &oldreq->bpr_req); |
616 | union nilfs_bmap_ptr_req *req) | 567 | nilfs_dat_abort_alloc(dat, &newreq->bpr_req); |
617 | { | ||
618 | /* ignore target ptr */ | ||
619 | req->bpr_ptr = bmap->b_last_allocated_ptr++; | ||
620 | return 0; | ||
621 | } | 568 | } |
622 | 569 | ||
623 | static void nilfs_bmap_commit_alloc_p(struct nilfs_bmap *bmap, | ||
624 | union nilfs_bmap_ptr_req *req) | ||
625 | { | ||
626 | /* do nothing */ | ||
627 | } | ||
628 | |||
629 | static void nilfs_bmap_abort_alloc_p(struct nilfs_bmap *bmap, | ||
630 | union nilfs_bmap_ptr_req *req) | ||
631 | { | ||
632 | bmap->b_last_allocated_ptr--; | ||
633 | } | ||
634 | |||
635 | static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_v = { | ||
636 | .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, | ||
637 | .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, | ||
638 | .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, | ||
639 | .bpop_prepare_start_ptr = nilfs_bmap_prepare_start_v, | ||
640 | .bpop_commit_start_ptr = nilfs_bmap_commit_start_v, | ||
641 | .bpop_abort_start_ptr = nilfs_bmap_abort_start_v, | ||
642 | .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, | ||
643 | .bpop_commit_end_ptr = nilfs_bmap_commit_end_v, | ||
644 | .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, | ||
645 | |||
646 | .bpop_translate = nilfs_bmap_translate_v, | ||
647 | }; | ||
648 | |||
649 | static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_vmdt = { | ||
650 | .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_v, | ||
651 | .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_v, | ||
652 | .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_v, | ||
653 | .bpop_prepare_start_ptr = nilfs_bmap_prepare_start_v, | ||
654 | .bpop_commit_start_ptr = nilfs_bmap_commit_start_v, | ||
655 | .bpop_abort_start_ptr = nilfs_bmap_abort_start_v, | ||
656 | .bpop_prepare_end_ptr = nilfs_bmap_prepare_end_v, | ||
657 | .bpop_commit_end_ptr = nilfs_bmap_commit_end_vmdt, | ||
658 | .bpop_abort_end_ptr = nilfs_bmap_abort_end_v, | ||
659 | |||
660 | .bpop_translate = nilfs_bmap_translate_v, | ||
661 | }; | ||
662 | |||
663 | static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_p = { | ||
664 | .bpop_prepare_alloc_ptr = nilfs_bmap_prepare_alloc_p, | ||
665 | .bpop_commit_alloc_ptr = nilfs_bmap_commit_alloc_p, | ||
666 | .bpop_abort_alloc_ptr = nilfs_bmap_abort_alloc_p, | ||
667 | .bpop_prepare_start_ptr = NULL, | ||
668 | .bpop_commit_start_ptr = NULL, | ||
669 | .bpop_abort_start_ptr = NULL, | ||
670 | .bpop_prepare_end_ptr = NULL, | ||
671 | .bpop_commit_end_ptr = NULL, | ||
672 | .bpop_abort_end_ptr = NULL, | ||
673 | |||
674 | .bpop_translate = NULL, | ||
675 | }; | ||
676 | |||
677 | static const struct nilfs_bmap_ptr_operations nilfs_bmap_ptr_ops_gc = { | ||
678 | .bpop_prepare_alloc_ptr = NULL, | ||
679 | .bpop_commit_alloc_ptr = NULL, | ||
680 | .bpop_abort_alloc_ptr = NULL, | ||
681 | .bpop_prepare_start_ptr = NULL, | ||
682 | .bpop_commit_start_ptr = NULL, | ||
683 | .bpop_abort_start_ptr = NULL, | ||
684 | .bpop_prepare_end_ptr = NULL, | ||
685 | .bpop_commit_end_ptr = NULL, | ||
686 | .bpop_abort_end_ptr = NULL, | ||
687 | |||
688 | .bpop_translate = NULL, | ||
689 | }; | ||
690 | |||
691 | static struct lock_class_key nilfs_bmap_dat_lock_key; | 570 | static struct lock_class_key nilfs_bmap_dat_lock_key; |
571 | static struct lock_class_key nilfs_bmap_mdt_lock_key; | ||
692 | 572 | ||
693 | /** | 573 | /** |
694 | * nilfs_bmap_read - read a bmap from an inode | 574 | * nilfs_bmap_read - read a bmap from an inode |
@@ -714,31 +594,30 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode) | |||
714 | bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; | 594 | bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; |
715 | switch (bmap->b_inode->i_ino) { | 595 | switch (bmap->b_inode->i_ino) { |
716 | case NILFS_DAT_INO: | 596 | case NILFS_DAT_INO: |
717 | bmap->b_pops = &nilfs_bmap_ptr_ops_p; | 597 | bmap->b_ptr_type = NILFS_BMAP_PTR_P; |
718 | bmap->b_last_allocated_key = 0; /* XXX: use macro */ | 598 | bmap->b_last_allocated_key = 0; |
719 | bmap->b_last_allocated_ptr = NILFS_BMAP_NEW_PTR_INIT; | 599 | bmap->b_last_allocated_ptr = NILFS_BMAP_NEW_PTR_INIT; |
720 | lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); | 600 | lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); |
721 | break; | 601 | break; |
722 | case NILFS_CPFILE_INO: | 602 | case NILFS_CPFILE_INO: |
723 | case NILFS_SUFILE_INO: | 603 | case NILFS_SUFILE_INO: |
724 | bmap->b_pops = &nilfs_bmap_ptr_ops_vmdt; | 604 | bmap->b_ptr_type = NILFS_BMAP_PTR_VS; |
725 | bmap->b_last_allocated_key = 0; /* XXX: use macro */ | 605 | bmap->b_last_allocated_key = 0; |
726 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; | 606 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; |
607 | lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key); | ||
727 | break; | 608 | break; |
609 | case NILFS_IFILE_INO: | ||
610 | lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key); | ||
611 | /* Fall through */ | ||
728 | default: | 612 | default: |
729 | bmap->b_pops = &nilfs_bmap_ptr_ops_v; | 613 | bmap->b_ptr_type = NILFS_BMAP_PTR_VM; |
730 | bmap->b_last_allocated_key = 0; /* XXX: use macro */ | 614 | bmap->b_last_allocated_key = 0; |
731 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; | 615 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; |
732 | break; | 616 | break; |
733 | } | 617 | } |
734 | 618 | ||
735 | return (bmap->b_u.u_flags & NILFS_BMAP_LARGE) ? | 619 | return (bmap->b_u.u_flags & NILFS_BMAP_LARGE) ? |
736 | nilfs_btree_init(bmap, | 620 | nilfs_btree_init(bmap) : nilfs_direct_init(bmap); |
737 | NILFS_BMAP_LARGE_LOW, | ||
738 | NILFS_BMAP_LARGE_HIGH) : | ||
739 | nilfs_direct_init(bmap, | ||
740 | NILFS_BMAP_SMALL_LOW, | ||
741 | NILFS_BMAP_SMALL_HIGH); | ||
742 | } | 621 | } |
743 | 622 | ||
744 | /** | 623 | /** |
@@ -764,7 +643,7 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) | |||
764 | memset(&bmap->b_u, 0, NILFS_BMAP_SIZE); | 643 | memset(&bmap->b_u, 0, NILFS_BMAP_SIZE); |
765 | init_rwsem(&bmap->b_sem); | 644 | init_rwsem(&bmap->b_sem); |
766 | bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; | 645 | bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; |
767 | bmap->b_pops = &nilfs_bmap_ptr_ops_gc; | 646 | bmap->b_ptr_type = NILFS_BMAP_PTR_U; |
768 | bmap->b_last_allocated_key = 0; | 647 | bmap->b_last_allocated_key = 0; |
769 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; | 648 | bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR; |
770 | bmap->b_state = 0; | 649 | bmap->b_state = 0; |
diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 4f2708abb1ba..b2890cdcef12 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h | |||
@@ -64,6 +64,8 @@ struct nilfs_bmap_stats { | |||
64 | */ | 64 | */ |
65 | struct nilfs_bmap_operations { | 65 | struct nilfs_bmap_operations { |
66 | int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *); | 66 | int (*bop_lookup)(const struct nilfs_bmap *, __u64, int, __u64 *); |
67 | int (*bop_lookup_contig)(const struct nilfs_bmap *, __u64, __u64 *, | ||
68 | unsigned); | ||
67 | int (*bop_insert)(struct nilfs_bmap *, __u64, __u64); | 69 | int (*bop_insert)(struct nilfs_bmap *, __u64, __u64); |
68 | int (*bop_delete)(struct nilfs_bmap *, __u64); | 70 | int (*bop_delete)(struct nilfs_bmap *, __u64); |
69 | void (*bop_clear)(struct nilfs_bmap *); | 71 | void (*bop_clear)(struct nilfs_bmap *); |
@@ -86,34 +88,6 @@ struct nilfs_bmap_operations { | |||
86 | }; | 88 | }; |
87 | 89 | ||
88 | 90 | ||
89 | /** | ||
90 | * struct nilfs_bmap_ptr_operations - bmap ptr operation table | ||
91 | */ | ||
92 | struct nilfs_bmap_ptr_operations { | ||
93 | int (*bpop_prepare_alloc_ptr)(struct nilfs_bmap *, | ||
94 | union nilfs_bmap_ptr_req *); | ||
95 | void (*bpop_commit_alloc_ptr)(struct nilfs_bmap *, | ||
96 | union nilfs_bmap_ptr_req *); | ||
97 | void (*bpop_abort_alloc_ptr)(struct nilfs_bmap *, | ||
98 | union nilfs_bmap_ptr_req *); | ||
99 | int (*bpop_prepare_start_ptr)(struct nilfs_bmap *, | ||
100 | union nilfs_bmap_ptr_req *); | ||
101 | void (*bpop_commit_start_ptr)(struct nilfs_bmap *, | ||
102 | union nilfs_bmap_ptr_req *, | ||
103 | sector_t); | ||
104 | void (*bpop_abort_start_ptr)(struct nilfs_bmap *, | ||
105 | union nilfs_bmap_ptr_req *); | ||
106 | int (*bpop_prepare_end_ptr)(struct nilfs_bmap *, | ||
107 | union nilfs_bmap_ptr_req *); | ||
108 | void (*bpop_commit_end_ptr)(struct nilfs_bmap *, | ||
109 | union nilfs_bmap_ptr_req *); | ||
110 | void (*bpop_abort_end_ptr)(struct nilfs_bmap *, | ||
111 | union nilfs_bmap_ptr_req *); | ||
112 | |||
113 | int (*bpop_translate)(const struct nilfs_bmap *, __u64, __u64 *); | ||
114 | }; | ||
115 | |||
116 | |||
117 | #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(__le64)) | 91 | #define NILFS_BMAP_SIZE (NILFS_INODE_BMAP_SIZE * sizeof(__le64)) |
118 | #define NILFS_BMAP_KEY_BIT (sizeof(unsigned long) * 8 /* CHAR_BIT */) | 92 | #define NILFS_BMAP_KEY_BIT (sizeof(unsigned long) * 8 /* CHAR_BIT */) |
119 | #define NILFS_BMAP_NEW_PTR_INIT \ | 93 | #define NILFS_BMAP_NEW_PTR_INIT \ |
@@ -131,11 +105,9 @@ static inline int nilfs_bmap_is_new_ptr(unsigned long ptr) | |||
131 | * @b_sem: semaphore | 105 | * @b_sem: semaphore |
132 | * @b_inode: owner of bmap | 106 | * @b_inode: owner of bmap |
133 | * @b_ops: bmap operation table | 107 | * @b_ops: bmap operation table |
134 | * @b_pops: bmap ptr operation table | ||
135 | * @b_low: low watermark of conversion | ||
136 | * @b_high: high watermark of conversion | ||
137 | * @b_last_allocated_key: last allocated key for data block | 108 | * @b_last_allocated_key: last allocated key for data block |
138 | * @b_last_allocated_ptr: last allocated ptr for data block | 109 | * @b_last_allocated_ptr: last allocated ptr for data block |
110 | * @b_ptr_type: pointer type | ||
139 | * @b_state: state | 111 | * @b_state: state |
140 | */ | 112 | */ |
141 | struct nilfs_bmap { | 113 | struct nilfs_bmap { |
@@ -146,14 +118,22 @@ struct nilfs_bmap { | |||
146 | struct rw_semaphore b_sem; | 118 | struct rw_semaphore b_sem; |
147 | struct inode *b_inode; | 119 | struct inode *b_inode; |
148 | const struct nilfs_bmap_operations *b_ops; | 120 | const struct nilfs_bmap_operations *b_ops; |
149 | const struct nilfs_bmap_ptr_operations *b_pops; | ||
150 | __u64 b_low; | ||
151 | __u64 b_high; | ||
152 | __u64 b_last_allocated_key; | 121 | __u64 b_last_allocated_key; |
153 | __u64 b_last_allocated_ptr; | 122 | __u64 b_last_allocated_ptr; |
123 | int b_ptr_type; | ||
154 | int b_state; | 124 | int b_state; |
155 | }; | 125 | }; |
156 | 126 | ||
127 | /* pointer type */ | ||
128 | #define NILFS_BMAP_PTR_P 0 /* physical block number (i.e. LBN) */ | ||
129 | #define NILFS_BMAP_PTR_VS 1 /* virtual block number (single | ||
130 | version) */ | ||
131 | #define NILFS_BMAP_PTR_VM 2 /* virtual block number (has multiple | ||
132 | versions) */ | ||
133 | #define NILFS_BMAP_PTR_U (-1) /* never perform pointer operations */ | ||
134 | |||
135 | #define NILFS_BMAP_USE_VBN(bmap) ((bmap)->b_ptr_type > 0) | ||
136 | |||
157 | /* state */ | 137 | /* state */ |
158 | #define NILFS_BMAP_DIRTY 0x00000001 | 138 | #define NILFS_BMAP_DIRTY 0x00000001 |
159 | 139 | ||
@@ -162,6 +142,7 @@ int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); | |||
162 | int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); | 142 | int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); |
163 | void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); | 143 | void nilfs_bmap_write(struct nilfs_bmap *, struct nilfs_inode *); |
164 | int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *); | 144 | int nilfs_bmap_lookup(struct nilfs_bmap *, unsigned long, unsigned long *); |
145 | int nilfs_bmap_lookup_contig(struct nilfs_bmap *, __u64, __u64 *, unsigned); | ||
165 | int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); | 146 | int nilfs_bmap_insert(struct nilfs_bmap *, unsigned long, unsigned long); |
166 | int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); | 147 | int nilfs_bmap_delete(struct nilfs_bmap *, unsigned long); |
167 | int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); | 148 | int nilfs_bmap_last_key(struct nilfs_bmap *, unsigned long *); |
@@ -182,7 +163,67 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); | |||
182 | /* | 163 | /* |
183 | * Internal use only | 164 | * Internal use only |
184 | */ | 165 | */ |
166 | struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *); | ||
167 | int nilfs_bmap_prepare_alloc_v(struct nilfs_bmap *, | ||
168 | union nilfs_bmap_ptr_req *); | ||
169 | void nilfs_bmap_commit_alloc_v(struct nilfs_bmap *, | ||
170 | union nilfs_bmap_ptr_req *); | ||
171 | void nilfs_bmap_abort_alloc_v(struct nilfs_bmap *, | ||
172 | union nilfs_bmap_ptr_req *); | ||
185 | 173 | ||
174 | static inline int nilfs_bmap_prepare_alloc_ptr(struct nilfs_bmap *bmap, | ||
175 | union nilfs_bmap_ptr_req *req) | ||
176 | { | ||
177 | if (NILFS_BMAP_USE_VBN(bmap)) | ||
178 | return nilfs_bmap_prepare_alloc_v(bmap, req); | ||
179 | /* ignore target ptr */ | ||
180 | req->bpr_ptr = bmap->b_last_allocated_ptr++; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static inline void nilfs_bmap_commit_alloc_ptr(struct nilfs_bmap *bmap, | ||
185 | union nilfs_bmap_ptr_req *req) | ||
186 | { | ||
187 | if (NILFS_BMAP_USE_VBN(bmap)) | ||
188 | nilfs_bmap_commit_alloc_v(bmap, req); | ||
189 | } | ||
190 | |||
191 | static inline void nilfs_bmap_abort_alloc_ptr(struct nilfs_bmap *bmap, | ||
192 | union nilfs_bmap_ptr_req *req) | ||
193 | { | ||
194 | if (NILFS_BMAP_USE_VBN(bmap)) | ||
195 | nilfs_bmap_abort_alloc_v(bmap, req); | ||
196 | else | ||
197 | bmap->b_last_allocated_ptr--; | ||
198 | } | ||
199 | |||
200 | int nilfs_bmap_prepare_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); | ||
201 | void nilfs_bmap_commit_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); | ||
202 | void nilfs_bmap_abort_end_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *); | ||
203 | |||
204 | static inline int nilfs_bmap_prepare_end_ptr(struct nilfs_bmap *bmap, | ||
205 | union nilfs_bmap_ptr_req *req) | ||
206 | { | ||
207 | return NILFS_BMAP_USE_VBN(bmap) ? | ||
208 | nilfs_bmap_prepare_end_v(bmap, req) : 0; | ||
209 | } | ||
210 | |||
211 | static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap, | ||
212 | union nilfs_bmap_ptr_req *req) | ||
213 | { | ||
214 | if (NILFS_BMAP_USE_VBN(bmap)) | ||
215 | nilfs_bmap_commit_end_v(bmap, req); | ||
216 | } | ||
217 | |||
218 | static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap, | ||
219 | union nilfs_bmap_ptr_req *req) | ||
220 | { | ||
221 | if (NILFS_BMAP_USE_VBN(bmap)) | ||
222 | nilfs_bmap_abort_end_v(bmap, req); | ||
223 | } | ||
224 | |||
225 | int nilfs_bmap_start_v(struct nilfs_bmap *, union nilfs_bmap_ptr_req *, | ||
226 | sector_t); | ||
186 | int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t); | 227 | int nilfs_bmap_move_v(const struct nilfs_bmap *, __u64, sector_t); |
187 | int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64); | 228 | int nilfs_bmap_mark_dirty(const struct nilfs_bmap *, __u64); |
188 | 229 | ||
@@ -193,28 +234,20 @@ __u64 nilfs_bmap_data_get_key(const struct nilfs_bmap *, | |||
193 | __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); | 234 | __u64 nilfs_bmap_find_target_seq(const struct nilfs_bmap *, __u64); |
194 | __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); | 235 | __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *); |
195 | 236 | ||
196 | int nilfs_bmap_prepare_update(struct nilfs_bmap *, | 237 | int nilfs_bmap_prepare_update_v(struct nilfs_bmap *, |
197 | union nilfs_bmap_ptr_req *, | 238 | union nilfs_bmap_ptr_req *, |
198 | union nilfs_bmap_ptr_req *); | 239 | union nilfs_bmap_ptr_req *); |
199 | void nilfs_bmap_commit_update(struct nilfs_bmap *, | 240 | void nilfs_bmap_commit_update_v(struct nilfs_bmap *, |
200 | union nilfs_bmap_ptr_req *, | 241 | union nilfs_bmap_ptr_req *, |
201 | union nilfs_bmap_ptr_req *); | 242 | union nilfs_bmap_ptr_req *); |
202 | void nilfs_bmap_abort_update(struct nilfs_bmap *, | 243 | void nilfs_bmap_abort_update_v(struct nilfs_bmap *, |
203 | union nilfs_bmap_ptr_req *, | 244 | union nilfs_bmap_ptr_req *, |
204 | union nilfs_bmap_ptr_req *); | 245 | union nilfs_bmap_ptr_req *); |
205 | 246 | ||
206 | void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); | 247 | void nilfs_bmap_add_blocks(const struct nilfs_bmap *, int); |
207 | void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); | 248 | void nilfs_bmap_sub_blocks(const struct nilfs_bmap *, int); |
208 | 249 | ||
209 | 250 | ||
210 | int nilfs_bmap_get_block(const struct nilfs_bmap *, __u64, | ||
211 | struct buffer_head **); | ||
212 | void nilfs_bmap_put_block(const struct nilfs_bmap *, struct buffer_head *); | ||
213 | int nilfs_bmap_get_new_block(const struct nilfs_bmap *, __u64, | ||
214 | struct buffer_head **); | ||
215 | void nilfs_bmap_delete_block(const struct nilfs_bmap *, struct buffer_head *); | ||
216 | |||
217 | |||
218 | /* Assume that bmap semaphore is locked. */ | 251 | /* Assume that bmap semaphore is locked. */ |
219 | static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap) | 252 | static inline int nilfs_bmap_dirty(const struct nilfs_bmap *bmap) |
220 | { | 253 | { |
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 4cc07b2c30e0..7e0b61be212e 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c | |||
@@ -46,15 +46,18 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc) | |||
46 | INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); | 46 | INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); |
47 | } | 47 | } |
48 | 48 | ||
49 | static struct address_space_operations def_btnode_aops; | 49 | static struct address_space_operations def_btnode_aops = { |
50 | .sync_page = block_sync_page, | ||
51 | }; | ||
50 | 52 | ||
51 | void nilfs_btnode_cache_init(struct address_space *btnc) | 53 | void nilfs_btnode_cache_init(struct address_space *btnc, |
54 | struct backing_dev_info *bdi) | ||
52 | { | 55 | { |
53 | btnc->host = NULL; /* can safely set to host inode ? */ | 56 | btnc->host = NULL; /* can safely set to host inode ? */ |
54 | btnc->flags = 0; | 57 | btnc->flags = 0; |
55 | mapping_set_gfp_mask(btnc, GFP_NOFS); | 58 | mapping_set_gfp_mask(btnc, GFP_NOFS); |
56 | btnc->assoc_mapping = NULL; | 59 | btnc->assoc_mapping = NULL; |
57 | btnc->backing_dev_info = &default_backing_dev_info; | 60 | btnc->backing_dev_info = bdi; |
58 | btnc->a_ops = &def_btnode_aops; | 61 | btnc->a_ops = &def_btnode_aops; |
59 | } | 62 | } |
60 | 63 | ||
diff --git a/fs/nilfs2/btnode.h b/fs/nilfs2/btnode.h index 35faa86444a7..3e2275172ed6 100644 --- a/fs/nilfs2/btnode.h +++ b/fs/nilfs2/btnode.h | |||
@@ -38,7 +38,7 @@ struct nilfs_btnode_chkey_ctxt { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | void nilfs_btnode_cache_init_once(struct address_space *); | 40 | void nilfs_btnode_cache_init_once(struct address_space *); |
41 | void nilfs_btnode_cache_init(struct address_space *); | 41 | void nilfs_btnode_cache_init(struct address_space *, struct backing_dev_info *); |
42 | void nilfs_btnode_cache_clear(struct address_space *); | 42 | void nilfs_btnode_cache_clear(struct address_space *); |
43 | int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, | 43 | int nilfs_btnode_submit_block(struct address_space *, __u64, sector_t, |
44 | struct buffer_head **, int); | 44 | struct buffer_head **, int); |
diff --git a/fs/nilfs2/btree.c b/fs/nilfs2/btree.c index 6b37a2767293..aa412724b64e 100644 --- a/fs/nilfs2/btree.c +++ b/fs/nilfs2/btree.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "btnode.h" | 29 | #include "btnode.h" |
30 | #include "btree.h" | 30 | #include "btree.h" |
31 | #include "alloc.h" | 31 | #include "alloc.h" |
32 | #include "dat.h" | ||
32 | 33 | ||
33 | /** | 34 | /** |
34 | * struct nilfs_btree_path - A path on which B-tree operations are executed | 35 | * struct nilfs_btree_path - A path on which B-tree operations are executed |
@@ -109,8 +110,7 @@ static void nilfs_btree_clear_path(const struct nilfs_btree *btree, | |||
109 | level < NILFS_BTREE_LEVEL_MAX; | 110 | level < NILFS_BTREE_LEVEL_MAX; |
110 | level++) { | 111 | level++) { |
111 | if (path[level].bp_bh != NULL) { | 112 | if (path[level].bp_bh != NULL) { |
112 | nilfs_bmap_put_block(&btree->bt_bmap, | 113 | brelse(path[level].bp_bh); |
113 | path[level].bp_bh); | ||
114 | path[level].bp_bh = NULL; | 114 | path[level].bp_bh = NULL; |
115 | } | 115 | } |
116 | /* sib_bh is released or deleted by prepare or commit | 116 | /* sib_bh is released or deleted by prepare or commit |
@@ -123,10 +123,29 @@ static void nilfs_btree_clear_path(const struct nilfs_btree *btree, | |||
123 | } | 123 | } |
124 | } | 124 | } |
125 | 125 | ||
126 | |||
127 | /* | 126 | /* |
128 | * B-tree node operations | 127 | * B-tree node operations |
129 | */ | 128 | */ |
129 | static int nilfs_btree_get_block(const struct nilfs_btree *btree, __u64 ptr, | ||
130 | struct buffer_head **bhp) | ||
131 | { | ||
132 | struct address_space *btnc = | ||
133 | &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; | ||
134 | return nilfs_btnode_get(btnc, ptr, 0, bhp, 0); | ||
135 | } | ||
136 | |||
137 | static int nilfs_btree_get_new_block(const struct nilfs_btree *btree, | ||
138 | __u64 ptr, struct buffer_head **bhp) | ||
139 | { | ||
140 | struct address_space *btnc = | ||
141 | &NILFS_BMAP_I((struct nilfs_bmap *)btree)->i_btnode_cache; | ||
142 | int ret; | ||
143 | |||
144 | ret = nilfs_btnode_get(btnc, ptr, 0, bhp, 1); | ||
145 | if (!ret) | ||
146 | set_buffer_nilfs_volatile(*bhp); | ||
147 | return ret; | ||
148 | } | ||
130 | 149 | ||
131 | static inline int | 150 | static inline int |
132 | nilfs_btree_node_get_flags(const struct nilfs_btree *btree, | 151 | nilfs_btree_node_get_flags(const struct nilfs_btree *btree, |
@@ -488,8 +507,7 @@ static int nilfs_btree_do_lookup(const struct nilfs_btree *btree, | |||
488 | path[level].bp_index = index; | 507 | path[level].bp_index = index; |
489 | 508 | ||
490 | for (level--; level >= minlevel; level--) { | 509 | for (level--; level >= minlevel; level--) { |
491 | ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, | 510 | ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); |
492 | &path[level].bp_bh); | ||
493 | if (ret < 0) | 511 | if (ret < 0) |
494 | return ret; | 512 | return ret; |
495 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 513 | node = nilfs_btree_get_nonroot_node(btree, path, level); |
@@ -535,8 +553,7 @@ static int nilfs_btree_do_lookup_last(const struct nilfs_btree *btree, | |||
535 | path[level].bp_index = index; | 553 | path[level].bp_index = index; |
536 | 554 | ||
537 | for (level--; level > 0; level--) { | 555 | for (level--; level > 0; level--) { |
538 | ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, | 556 | ret = nilfs_btree_get_block(btree, ptr, &path[level].bp_bh); |
539 | &path[level].bp_bh); | ||
540 | if (ret < 0) | 557 | if (ret < 0) |
541 | return ret; | 558 | return ret; |
542 | node = nilfs_btree_get_nonroot_node(btree, path, level); | 559 | node = nilfs_btree_get_nonroot_node(btree, path, level); |
@@ -579,6 +596,87 @@ static int nilfs_btree_lookup(const struct nilfs_bmap *bmap, | |||
579 | return ret; | 596 | return ret; |
580 | } | 597 | } |
581 | 598 | ||
599 | static int nilfs_btree_lookup_contig(const struct nilfs_bmap *bmap, | ||
600 | __u64 key, __u64 *ptrp, unsigned maxblocks) | ||
601 | { | ||
602 | struct nilfs_btree *btree = (struct nilfs_btree *)bmap; | ||
603 | struct nilfs_btree_path *path; | ||
604 | struct nilfs_btree_node *node; | ||
605 | struct inode *dat = NULL; | ||
606 | __u64 ptr, ptr2; | ||
607 | sector_t blocknr; | ||
608 | int level = NILFS_BTREE_LEVEL_NODE_MIN; | ||
609 | int ret, cnt, index, maxlevel; | ||
610 | |||
611 | path = nilfs_btree_alloc_path(btree); | ||
612 | if (path == NULL) | ||
613 | return -ENOMEM; | ||
614 | nilfs_btree_init_path(btree, path); | ||
615 | ret = nilfs_btree_do_lookup(btree, path, key, &ptr, level); | ||
616 | if (ret < 0) | ||
617 | goto out; | ||
618 | |||
619 | if (NILFS_BMAP_USE_VBN(bmap)) { | ||
620 | dat = nilfs_bmap_get_dat(bmap); | ||
621 | ret = nilfs_dat_translate(dat, ptr, &blocknr); | ||
622 | if (ret < 0) | ||
623 | goto out; | ||
624 | ptr = blocknr; | ||
625 | } | ||
626 | cnt = 1; | ||
627 | if (cnt == maxblocks) | ||
628 | goto end; | ||
629 | |||
630 | maxlevel = nilfs_btree_height(btree) - 1; | ||
631 | node = nilfs_btree_get_node(btree, path, level); | ||
632 | index = path[level].bp_index + 1; | ||
633 | for (;;) { | ||
634 | while (index < nilfs_btree_node_get_nchildren(btree, node)) { | ||
635 | if (nilfs_btree_node_get_key(btree, node, index) != | ||
636 | key + cnt) | ||
637 | goto end; | ||
638 | ptr2 = nilfs_btree_node_get_ptr(btree, node, index); | ||
639 | if (dat) { | ||
640 | ret = nilfs_dat_translate(dat, ptr2, &blocknr); | ||
641 | if (ret < 0) | ||
642 | goto out; | ||
643 | ptr2 = blocknr; | ||
644 | } | ||
645 | if (ptr2 != ptr + cnt || ++cnt == maxblocks) | ||
646 | goto end; | ||
647 | index++; | ||
648 | continue; | ||
649 | } | ||
650 | if (level == maxlevel) | ||
651 | break; | ||
652 | |||
653 | /* look-up right sibling node */ | ||
654 | node = nilfs_btree_get_node(btree, path, level + 1); | ||
655 | index = path[level + 1].bp_index + 1; | ||
656 | if (index >= nilfs_btree_node_get_nchildren(btree, node) || | ||
657 | nilfs_btree_node_get_key(btree, node, index) != key + cnt) | ||
658 | break; | ||
659 | ptr2 = nilfs_btree_node_get_ptr(btree, node, index); | ||
660 | path[level + 1].bp_index = index; | ||
661 | |||
662 | brelse(path[level].bp_bh); | ||
663 | path[level].bp_bh = NULL; | ||
664 | ret = nilfs_btree_get_block(btree, ptr2, &path[level].bp_bh); | ||
665 | if (ret < 0) | ||
666 | goto out; | ||
667 | node = nilfs_btree_get_nonroot_node(btree, path, level); | ||
668 | index = 0; | ||
669 | path[level].bp_index = index; | ||
670 | } | ||
671 | end: | ||
672 | *ptrp = ptr; | ||
673 | ret = cnt; | ||
674 | out: | ||
675 | nilfs_btree_clear_path(btree, path); | ||
676 | nilfs_btree_free_path(btree, path); | ||
677 | return ret; | ||
678 | } | ||
679 | |||
582 | static void nilfs_btree_promote_key(struct nilfs_btree *btree, | 680 | static void nilfs_btree_promote_key(struct nilfs_btree *btree, |
583 | struct nilfs_btree_path *path, | 681 | struct nilfs_btree_path *path, |
584 | int level, __u64 key) | 682 | int level, __u64 key) |
@@ -669,13 +767,13 @@ static void nilfs_btree_carry_left(struct nilfs_btree *btree, | |||
669 | nilfs_btree_node_get_key(btree, node, 0)); | 767 | nilfs_btree_node_get_key(btree, node, 0)); |
670 | 768 | ||
671 | if (move) { | 769 | if (move) { |
672 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); | 770 | brelse(path[level].bp_bh); |
673 | path[level].bp_bh = path[level].bp_sib_bh; | 771 | path[level].bp_bh = path[level].bp_sib_bh; |
674 | path[level].bp_sib_bh = NULL; | 772 | path[level].bp_sib_bh = NULL; |
675 | path[level].bp_index += lnchildren; | 773 | path[level].bp_index += lnchildren; |
676 | path[level + 1].bp_index--; | 774 | path[level + 1].bp_index--; |
677 | } else { | 775 | } else { |
678 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); | 776 | brelse(path[level].bp_sib_bh); |
679 | path[level].bp_sib_bh = NULL; | 777 | path[level].bp_sib_bh = NULL; |
680 | path[level].bp_index -= n; | 778 | path[level].bp_index -= n; |
681 | } | 779 | } |
@@ -722,14 +820,14 @@ static void nilfs_btree_carry_right(struct nilfs_btree *btree, | |||
722 | path[level + 1].bp_index--; | 820 | path[level + 1].bp_index--; |
723 | 821 | ||
724 | if (move) { | 822 | if (move) { |
725 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); | 823 | brelse(path[level].bp_bh); |
726 | path[level].bp_bh = path[level].bp_sib_bh; | 824 | path[level].bp_bh = path[level].bp_sib_bh; |
727 | path[level].bp_sib_bh = NULL; | 825 | path[level].bp_sib_bh = NULL; |
728 | path[level].bp_index -= | 826 | path[level].bp_index -= |
729 | nilfs_btree_node_get_nchildren(btree, node); | 827 | nilfs_btree_node_get_nchildren(btree, node); |
730 | path[level + 1].bp_index++; | 828 | path[level + 1].bp_index++; |
731 | } else { | 829 | } else { |
732 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); | 830 | brelse(path[level].bp_sib_bh); |
733 | path[level].bp_sib_bh = NULL; | 831 | path[level].bp_sib_bh = NULL; |
734 | } | 832 | } |
735 | 833 | ||
@@ -781,7 +879,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, | |||
781 | *keyp = nilfs_btree_node_get_key(btree, right, 0); | 879 | *keyp = nilfs_btree_node_get_key(btree, right, 0); |
782 | *ptrp = path[level].bp_newreq.bpr_ptr; | 880 | *ptrp = path[level].bp_newreq.bpr_ptr; |
783 | 881 | ||
784 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_bh); | 882 | brelse(path[level].bp_bh); |
785 | path[level].bp_bh = path[level].bp_sib_bh; | 883 | path[level].bp_bh = path[level].bp_sib_bh; |
786 | path[level].bp_sib_bh = NULL; | 884 | path[level].bp_sib_bh = NULL; |
787 | } else { | 885 | } else { |
@@ -790,7 +888,7 @@ static void nilfs_btree_split(struct nilfs_btree *btree, | |||
790 | *keyp = nilfs_btree_node_get_key(btree, right, 0); | 888 | *keyp = nilfs_btree_node_get_key(btree, right, 0); |
791 | *ptrp = path[level].bp_newreq.bpr_ptr; | 889 | *ptrp = path[level].bp_newreq.bpr_ptr; |
792 | 890 | ||
793 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); | 891 | brelse(path[level].bp_sib_bh); |
794 | path[level].bp_sib_bh = NULL; | 892 | path[level].bp_sib_bh = NULL; |
795 | } | 893 | } |
796 | 894 | ||
@@ -897,12 +995,12 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
897 | level = NILFS_BTREE_LEVEL_DATA; | 995 | level = NILFS_BTREE_LEVEL_DATA; |
898 | 996 | ||
899 | /* allocate a new ptr for data block */ | 997 | /* allocate a new ptr for data block */ |
900 | if (btree->bt_ops->btop_find_target != NULL) | 998 | if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) |
901 | path[level].bp_newreq.bpr_ptr = | 999 | path[level].bp_newreq.bpr_ptr = |
902 | btree->bt_ops->btop_find_target(btree, path, key); | 1000 | nilfs_btree_find_target_v(btree, path, key); |
903 | 1001 | ||
904 | ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( | 1002 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, |
905 | &btree->bt_bmap, &path[level].bp_newreq); | 1003 | &path[level].bp_newreq); |
906 | if (ret < 0) | 1004 | if (ret < 0) |
907 | goto err_out_data; | 1005 | goto err_out_data; |
908 | 1006 | ||
@@ -924,8 +1022,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
924 | if (pindex > 0) { | 1022 | if (pindex > 0) { |
925 | sibptr = nilfs_btree_node_get_ptr(btree, parent, | 1023 | sibptr = nilfs_btree_node_get_ptr(btree, parent, |
926 | pindex - 1); | 1024 | pindex - 1); |
927 | ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, | 1025 | ret = nilfs_btree_get_block(btree, sibptr, &bh); |
928 | &bh); | ||
929 | if (ret < 0) | 1026 | if (ret < 0) |
930 | goto err_out_child_node; | 1027 | goto err_out_child_node; |
931 | sib = (struct nilfs_btree_node *)bh->b_data; | 1028 | sib = (struct nilfs_btree_node *)bh->b_data; |
@@ -936,7 +1033,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
936 | stats->bs_nblocks++; | 1033 | stats->bs_nblocks++; |
937 | goto out; | 1034 | goto out; |
938 | } else | 1035 | } else |
939 | nilfs_bmap_put_block(&btree->bt_bmap, bh); | 1036 | brelse(bh); |
940 | } | 1037 | } |
941 | 1038 | ||
942 | /* right sibling */ | 1039 | /* right sibling */ |
@@ -944,8 +1041,7 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
944 | nilfs_btree_node_get_nchildren(btree, parent) - 1) { | 1041 | nilfs_btree_node_get_nchildren(btree, parent) - 1) { |
945 | sibptr = nilfs_btree_node_get_ptr(btree, parent, | 1042 | sibptr = nilfs_btree_node_get_ptr(btree, parent, |
946 | pindex + 1); | 1043 | pindex + 1); |
947 | ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, | 1044 | ret = nilfs_btree_get_block(btree, sibptr, &bh); |
948 | &bh); | ||
949 | if (ret < 0) | 1045 | if (ret < 0) |
950 | goto err_out_child_node; | 1046 | goto err_out_child_node; |
951 | sib = (struct nilfs_btree_node *)bh->b_data; | 1047 | sib = (struct nilfs_btree_node *)bh->b_data; |
@@ -956,19 +1052,19 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
956 | stats->bs_nblocks++; | 1052 | stats->bs_nblocks++; |
957 | goto out; | 1053 | goto out; |
958 | } else | 1054 | } else |
959 | nilfs_bmap_put_block(&btree->bt_bmap, bh); | 1055 | brelse(bh); |
960 | } | 1056 | } |
961 | 1057 | ||
962 | /* split */ | 1058 | /* split */ |
963 | path[level].bp_newreq.bpr_ptr = | 1059 | path[level].bp_newreq.bpr_ptr = |
964 | path[level - 1].bp_newreq.bpr_ptr + 1; | 1060 | path[level - 1].bp_newreq.bpr_ptr + 1; |
965 | ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( | 1061 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, |
966 | &btree->bt_bmap, &path[level].bp_newreq); | 1062 | &path[level].bp_newreq); |
967 | if (ret < 0) | 1063 | if (ret < 0) |
968 | goto err_out_child_node; | 1064 | goto err_out_child_node; |
969 | ret = nilfs_bmap_get_new_block(&btree->bt_bmap, | 1065 | ret = nilfs_btree_get_new_block(btree, |
970 | path[level].bp_newreq.bpr_ptr, | 1066 | path[level].bp_newreq.bpr_ptr, |
971 | &bh); | 1067 | &bh); |
972 | if (ret < 0) | 1068 | if (ret < 0) |
973 | goto err_out_curr_node; | 1069 | goto err_out_curr_node; |
974 | 1070 | ||
@@ -994,12 +1090,12 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
994 | 1090 | ||
995 | /* grow */ | 1091 | /* grow */ |
996 | path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; | 1092 | path[level].bp_newreq.bpr_ptr = path[level - 1].bp_newreq.bpr_ptr + 1; |
997 | ret = btree->bt_bmap.b_pops->bpop_prepare_alloc_ptr( | 1093 | ret = nilfs_bmap_prepare_alloc_ptr(&btree->bt_bmap, |
998 | &btree->bt_bmap, &path[level].bp_newreq); | 1094 | &path[level].bp_newreq); |
999 | if (ret < 0) | 1095 | if (ret < 0) |
1000 | goto err_out_child_node; | 1096 | goto err_out_child_node; |
1001 | ret = nilfs_bmap_get_new_block(&btree->bt_bmap, | 1097 | ret = nilfs_btree_get_new_block(btree, path[level].bp_newreq.bpr_ptr, |
1002 | path[level].bp_newreq.bpr_ptr, &bh); | 1098 | &bh); |
1003 | if (ret < 0) | 1099 | if (ret < 0) |
1004 | goto err_out_curr_node; | 1100 | goto err_out_curr_node; |
1005 | 1101 | ||
@@ -1023,18 +1119,16 @@ static int nilfs_btree_prepare_insert(struct nilfs_btree *btree, | |||
1023 | 1119 | ||
1024 | /* error */ | 1120 | /* error */ |
1025 | err_out_curr_node: | 1121 | err_out_curr_node: |
1026 | btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, | 1122 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); |
1027 | &path[level].bp_newreq); | ||
1028 | err_out_child_node: | 1123 | err_out_child_node: |
1029 | for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { | 1124 | for (level--; level > NILFS_BTREE_LEVEL_DATA; level--) { |
1030 | nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); | 1125 | nilfs_btnode_delete(path[level].bp_sib_bh); |
1031 | btree->bt_bmap.b_pops->bpop_abort_alloc_ptr( | 1126 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, |
1032 | &btree->bt_bmap, &path[level].bp_newreq); | 1127 | &path[level].bp_newreq); |
1033 | 1128 | ||
1034 | } | 1129 | } |
1035 | 1130 | ||
1036 | btree->bt_bmap.b_pops->bpop_abort_alloc_ptr(&btree->bt_bmap, | 1131 | nilfs_bmap_abort_alloc_ptr(&btree->bt_bmap, &path[level].bp_newreq); |
1037 | &path[level].bp_newreq); | ||
1038 | err_out_data: | 1132 | err_out_data: |
1039 | *levelp = level; | 1133 | *levelp = level; |
1040 | stats->bs_nblocks = 0; | 1134 | stats->bs_nblocks = 0; |
@@ -1049,14 +1143,12 @@ static void nilfs_btree_commit_insert(struct nilfs_btree *btree, | |||
1049 | 1143 | ||
1050 | set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); | 1144 | set_buffer_nilfs_volatile((struct buffer_head *)((unsigned long)ptr)); |
1051 | ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; | 1145 | ptr = path[NILFS_BTREE_LEVEL_DATA].bp_newreq.bpr_ptr; |
1052 | if (btree->bt_ops->btop_set_target != NULL) | 1146 | if (NILFS_BMAP_USE_VBN(&btree->bt_bmap)) |
1053 | btree->bt_ops->btop_set_target(btree, key, ptr); | 1147 | nilfs_btree_set_target_v(btree, key, ptr); |
1054 | 1148 | ||
1055 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { | 1149 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { |
1056 | if (btree->bt_bmap.b_pops->bpop_commit_alloc_ptr != NULL) { | 1150 | nilfs_bmap_commit_alloc_ptr(&btree->bt_bmap, |
1057 | btree->bt_bmap.b_pops->bpop_commit_alloc_ptr( | 1151 | &path[level - 1].bp_newreq); |
1058 | &btree->bt_bmap, &path[level - 1].bp_newreq); | ||
1059 | } | ||
1060 | path[level].bp_op(btree, path, level, &key, &ptr); | 1152 | path[level].bp_op(btree, path, level, &key, &ptr); |
1061 | } | 1153 | } |
1062 | 1154 | ||
@@ -1153,7 +1245,7 @@ static void nilfs_btree_borrow_left(struct nilfs_btree *btree, | |||
1153 | nilfs_btree_promote_key(btree, path, level + 1, | 1245 | nilfs_btree_promote_key(btree, path, level + 1, |
1154 | nilfs_btree_node_get_key(btree, node, 0)); | 1246 | nilfs_btree_node_get_key(btree, node, 0)); |
1155 | 1247 | ||
1156 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); | 1248 | brelse(path[level].bp_sib_bh); |
1157 | path[level].bp_sib_bh = NULL; | 1249 | path[level].bp_sib_bh = NULL; |
1158 | path[level].bp_index += n; | 1250 | path[level].bp_index += n; |
1159 | } | 1251 | } |
@@ -1192,7 +1284,7 @@ static void nilfs_btree_borrow_right(struct nilfs_btree *btree, | |||
1192 | nilfs_btree_node_get_key(btree, right, 0)); | 1284 | nilfs_btree_node_get_key(btree, right, 0)); |
1193 | path[level + 1].bp_index--; | 1285 | path[level + 1].bp_index--; |
1194 | 1286 | ||
1195 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); | 1287 | brelse(path[level].bp_sib_bh); |
1196 | path[level].bp_sib_bh = NULL; | 1288 | path[level].bp_sib_bh = NULL; |
1197 | } | 1289 | } |
1198 | 1290 | ||
@@ -1221,7 +1313,7 @@ static void nilfs_btree_concat_left(struct nilfs_btree *btree, | |||
1221 | unlock_buffer(path[level].bp_bh); | 1313 | unlock_buffer(path[level].bp_bh); |
1222 | unlock_buffer(path[level].bp_sib_bh); | 1314 | unlock_buffer(path[level].bp_sib_bh); |
1223 | 1315 | ||
1224 | nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_bh); | 1316 | nilfs_btnode_delete(path[level].bp_bh); |
1225 | path[level].bp_bh = path[level].bp_sib_bh; | 1317 | path[level].bp_bh = path[level].bp_sib_bh; |
1226 | path[level].bp_sib_bh = NULL; | 1318 | path[level].bp_sib_bh = NULL; |
1227 | path[level].bp_index += nilfs_btree_node_get_nchildren(btree, left); | 1319 | path[level].bp_index += nilfs_btree_node_get_nchildren(btree, left); |
@@ -1252,7 +1344,7 @@ static void nilfs_btree_concat_right(struct nilfs_btree *btree, | |||
1252 | unlock_buffer(path[level].bp_bh); | 1344 | unlock_buffer(path[level].bp_bh); |
1253 | unlock_buffer(path[level].bp_sib_bh); | 1345 | unlock_buffer(path[level].bp_sib_bh); |
1254 | 1346 | ||
1255 | nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_sib_bh); | 1347 | nilfs_btnode_delete(path[level].bp_sib_bh); |
1256 | path[level].bp_sib_bh = NULL; | 1348 | path[level].bp_sib_bh = NULL; |
1257 | path[level + 1].bp_index++; | 1349 | path[level + 1].bp_index++; |
1258 | } | 1350 | } |
@@ -1276,7 +1368,7 @@ static void nilfs_btree_shrink(struct nilfs_btree *btree, | |||
1276 | nilfs_btree_node_move_left(btree, root, child, n); | 1368 | nilfs_btree_node_move_left(btree, root, child, n); |
1277 | unlock_buffer(path[level].bp_bh); | 1369 | unlock_buffer(path[level].bp_bh); |
1278 | 1370 | ||
1279 | nilfs_bmap_delete_block(&btree->bt_bmap, path[level].bp_bh); | 1371 | nilfs_btnode_delete(path[level].bp_bh); |
1280 | path[level].bp_bh = NULL; | 1372 | path[level].bp_bh = NULL; |
1281 | } | 1373 | } |
1282 | 1374 | ||
@@ -1300,12 +1392,10 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
1300 | path[level].bp_oldreq.bpr_ptr = | 1392 | path[level].bp_oldreq.bpr_ptr = |
1301 | nilfs_btree_node_get_ptr(btree, node, | 1393 | nilfs_btree_node_get_ptr(btree, node, |
1302 | path[level].bp_index); | 1394 | path[level].bp_index); |
1303 | if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { | 1395 | ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, |
1304 | ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( | 1396 | &path[level].bp_oldreq); |
1305 | &btree->bt_bmap, &path[level].bp_oldreq); | 1397 | if (ret < 0) |
1306 | if (ret < 0) | 1398 | goto err_out_child_node; |
1307 | goto err_out_child_node; | ||
1308 | } | ||
1309 | 1399 | ||
1310 | if (nilfs_btree_node_get_nchildren(btree, node) > | 1400 | if (nilfs_btree_node_get_nchildren(btree, node) > |
1311 | nilfs_btree_node_nchildren_min(btree, node)) { | 1401 | nilfs_btree_node_nchildren_min(btree, node)) { |
@@ -1321,8 +1411,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
1321 | /* left sibling */ | 1411 | /* left sibling */ |
1322 | sibptr = nilfs_btree_node_get_ptr(btree, parent, | 1412 | sibptr = nilfs_btree_node_get_ptr(btree, parent, |
1323 | pindex - 1); | 1413 | pindex - 1); |
1324 | ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, | 1414 | ret = nilfs_btree_get_block(btree, sibptr, &bh); |
1325 | &bh); | ||
1326 | if (ret < 0) | 1415 | if (ret < 0) |
1327 | goto err_out_curr_node; | 1416 | goto err_out_curr_node; |
1328 | sib = (struct nilfs_btree_node *)bh->b_data; | 1417 | sib = (struct nilfs_btree_node *)bh->b_data; |
@@ -1343,8 +1432,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
1343 | /* right sibling */ | 1432 | /* right sibling */ |
1344 | sibptr = nilfs_btree_node_get_ptr(btree, parent, | 1433 | sibptr = nilfs_btree_node_get_ptr(btree, parent, |
1345 | pindex + 1); | 1434 | pindex + 1); |
1346 | ret = nilfs_bmap_get_block(&btree->bt_bmap, sibptr, | 1435 | ret = nilfs_btree_get_block(btree, sibptr, &bh); |
1347 | &bh); | ||
1348 | if (ret < 0) | 1436 | if (ret < 0) |
1349 | goto err_out_curr_node; | 1437 | goto err_out_curr_node; |
1350 | sib = (struct nilfs_btree_node *)bh->b_data; | 1438 | sib = (struct nilfs_btree_node *)bh->b_data; |
@@ -1381,12 +1469,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
1381 | node = nilfs_btree_get_root(btree); | 1469 | node = nilfs_btree_get_root(btree); |
1382 | path[level].bp_oldreq.bpr_ptr = | 1470 | path[level].bp_oldreq.bpr_ptr = |
1383 | nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); | 1471 | nilfs_btree_node_get_ptr(btree, node, path[level].bp_index); |
1384 | if (btree->bt_bmap.b_pops->bpop_prepare_end_ptr != NULL) { | 1472 | |
1385 | ret = btree->bt_bmap.b_pops->bpop_prepare_end_ptr( | 1473 | ret = nilfs_bmap_prepare_end_ptr(&btree->bt_bmap, |
1386 | &btree->bt_bmap, &path[level].bp_oldreq); | 1474 | &path[level].bp_oldreq); |
1387 | if (ret < 0) | 1475 | if (ret < 0) |
1388 | goto err_out_child_node; | 1476 | goto err_out_child_node; |
1389 | } | 1477 | |
1390 | /* child of the root node is deleted */ | 1478 | /* child of the root node is deleted */ |
1391 | path[level].bp_op = nilfs_btree_do_delete; | 1479 | path[level].bp_op = nilfs_btree_do_delete; |
1392 | stats->bs_nblocks++; | 1480 | stats->bs_nblocks++; |
@@ -1398,15 +1486,12 @@ static int nilfs_btree_prepare_delete(struct nilfs_btree *btree, | |||
1398 | 1486 | ||
1399 | /* error */ | 1487 | /* error */ |
1400 | err_out_curr_node: | 1488 | err_out_curr_node: |
1401 | if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) | 1489 | nilfs_bmap_abort_end_ptr(&btree->bt_bmap, &path[level].bp_oldreq); |
1402 | btree->bt_bmap.b_pops->bpop_abort_end_ptr( | ||
1403 | &btree->bt_bmap, &path[level].bp_oldreq); | ||
1404 | err_out_child_node: | 1490 | err_out_child_node: |
1405 | for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { | 1491 | for (level--; level >= NILFS_BTREE_LEVEL_NODE_MIN; level--) { |
1406 | nilfs_bmap_put_block(&btree->bt_bmap, path[level].bp_sib_bh); | 1492 | brelse(path[level].bp_sib_bh); |
1407 | if (btree->bt_bmap.b_pops->bpop_abort_end_ptr != NULL) | 1493 | nilfs_bmap_abort_end_ptr(&btree->bt_bmap, |
1408 | btree->bt_bmap.b_pops->bpop_abort_end_ptr( | 1494 | &path[level].bp_oldreq); |
1409 | &btree->bt_bmap, &path[level].bp_oldreq); | ||
1410 | } | 1495 | } |
1411 | *levelp = level; | 1496 | *levelp = level; |
1412 | stats->bs_nblocks = 0; | 1497 | stats->bs_nblocks = 0; |
@@ -1420,9 +1505,8 @@ static void nilfs_btree_commit_delete(struct nilfs_btree *btree, | |||
1420 | int level; | 1505 | int level; |
1421 | 1506 | ||
1422 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { | 1507 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; level <= maxlevel; level++) { |
1423 | if (btree->bt_bmap.b_pops->bpop_commit_end_ptr != NULL) | 1508 | nilfs_bmap_commit_end_ptr(&btree->bt_bmap, |
1424 | btree->bt_bmap.b_pops->bpop_commit_end_ptr( | 1509 | &path[level].bp_oldreq); |
1425 | &btree->bt_bmap, &path[level].bp_oldreq); | ||
1426 | path[level].bp_op(btree, path, level, NULL, NULL); | 1510 | path[level].bp_op(btree, path, level, NULL, NULL); |
1427 | } | 1511 | } |
1428 | 1512 | ||
@@ -1501,7 +1585,7 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) | |||
1501 | if (nchildren > 1) | 1585 | if (nchildren > 1) |
1502 | return 0; | 1586 | return 0; |
1503 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); | 1587 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); |
1504 | ret = nilfs_bmap_get_block(bmap, ptr, &bh); | 1588 | ret = nilfs_btree_get_block(btree, ptr, &bh); |
1505 | if (ret < 0) | 1589 | if (ret < 0) |
1506 | return ret; | 1590 | return ret; |
1507 | node = (struct nilfs_btree_node *)bh->b_data; | 1591 | node = (struct nilfs_btree_node *)bh->b_data; |
@@ -1515,9 +1599,9 @@ static int nilfs_btree_check_delete(struct nilfs_bmap *bmap, __u64 key) | |||
1515 | nextmaxkey = (nchildren > 1) ? | 1599 | nextmaxkey = (nchildren > 1) ? |
1516 | nilfs_btree_node_get_key(btree, node, nchildren - 2) : 0; | 1600 | nilfs_btree_node_get_key(btree, node, nchildren - 2) : 0; |
1517 | if (bh != NULL) | 1601 | if (bh != NULL) |
1518 | nilfs_bmap_put_block(bmap, bh); | 1602 | brelse(bh); |
1519 | 1603 | ||
1520 | return (maxkey == key) && (nextmaxkey < bmap->b_low); | 1604 | return (maxkey == key) && (nextmaxkey < NILFS_BMAP_LARGE_LOW); |
1521 | } | 1605 | } |
1522 | 1606 | ||
1523 | static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, | 1607 | static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, |
@@ -1542,7 +1626,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, | |||
1542 | nchildren = nilfs_btree_node_get_nchildren(btree, root); | 1626 | nchildren = nilfs_btree_node_get_nchildren(btree, root); |
1543 | WARN_ON(nchildren > 1); | 1627 | WARN_ON(nchildren > 1); |
1544 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); | 1628 | ptr = nilfs_btree_node_get_ptr(btree, root, nchildren - 1); |
1545 | ret = nilfs_bmap_get_block(bmap, ptr, &bh); | 1629 | ret = nilfs_btree_get_block(btree, ptr, &bh); |
1546 | if (ret < 0) | 1630 | if (ret < 0) |
1547 | return ret; | 1631 | return ret; |
1548 | node = (struct nilfs_btree_node *)bh->b_data; | 1632 | node = (struct nilfs_btree_node *)bh->b_data; |
@@ -1563,7 +1647,7 @@ static int nilfs_btree_gather_data(struct nilfs_bmap *bmap, | |||
1563 | } | 1647 | } |
1564 | 1648 | ||
1565 | if (bh != NULL) | 1649 | if (bh != NULL) |
1566 | nilfs_bmap_put_block(bmap, bh); | 1650 | brelse(bh); |
1567 | 1651 | ||
1568 | return nitems; | 1652 | return nitems; |
1569 | } | 1653 | } |
@@ -1584,10 +1668,10 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, | |||
1584 | 1668 | ||
1585 | /* for data */ | 1669 | /* for data */ |
1586 | /* cannot find near ptr */ | 1670 | /* cannot find near ptr */ |
1587 | if (btree->bt_ops->btop_find_target != NULL) | 1671 | if (NILFS_BMAP_USE_VBN(bmap)) |
1588 | dreq->bpr_ptr | 1672 | dreq->bpr_ptr = nilfs_btree_find_target_v(btree, NULL, key); |
1589 | = btree->bt_ops->btop_find_target(btree, NULL, key); | 1673 | |
1590 | ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, dreq); | 1674 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, dreq); |
1591 | if (ret < 0) | 1675 | if (ret < 0) |
1592 | return ret; | 1676 | return ret; |
1593 | 1677 | ||
@@ -1595,11 +1679,11 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, | |||
1595 | stats->bs_nblocks++; | 1679 | stats->bs_nblocks++; |
1596 | if (nreq != NULL) { | 1680 | if (nreq != NULL) { |
1597 | nreq->bpr_ptr = dreq->bpr_ptr + 1; | 1681 | nreq->bpr_ptr = dreq->bpr_ptr + 1; |
1598 | ret = bmap->b_pops->bpop_prepare_alloc_ptr(bmap, nreq); | 1682 | ret = nilfs_bmap_prepare_alloc_ptr(bmap, nreq); |
1599 | if (ret < 0) | 1683 | if (ret < 0) |
1600 | goto err_out_dreq; | 1684 | goto err_out_dreq; |
1601 | 1685 | ||
1602 | ret = nilfs_bmap_get_new_block(bmap, nreq->bpr_ptr, &bh); | 1686 | ret = nilfs_btree_get_new_block(btree, nreq->bpr_ptr, &bh); |
1603 | if (ret < 0) | 1687 | if (ret < 0) |
1604 | goto err_out_nreq; | 1688 | goto err_out_nreq; |
1605 | 1689 | ||
@@ -1612,9 +1696,9 @@ nilfs_btree_prepare_convert_and_insert(struct nilfs_bmap *bmap, __u64 key, | |||
1612 | 1696 | ||
1613 | /* error */ | 1697 | /* error */ |
1614 | err_out_nreq: | 1698 | err_out_nreq: |
1615 | bmap->b_pops->bpop_abort_alloc_ptr(bmap, nreq); | 1699 | nilfs_bmap_abort_alloc_ptr(bmap, nreq); |
1616 | err_out_dreq: | 1700 | err_out_dreq: |
1617 | bmap->b_pops->bpop_abort_alloc_ptr(bmap, dreq); | 1701 | nilfs_bmap_abort_alloc_ptr(bmap, dreq); |
1618 | stats->bs_nblocks = 0; | 1702 | stats->bs_nblocks = 0; |
1619 | return ret; | 1703 | return ret; |
1620 | 1704 | ||
@@ -1624,7 +1708,7 @@ static void | |||
1624 | nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | 1708 | nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, |
1625 | __u64 key, __u64 ptr, | 1709 | __u64 key, __u64 ptr, |
1626 | const __u64 *keys, const __u64 *ptrs, | 1710 | const __u64 *keys, const __u64 *ptrs, |
1627 | int n, __u64 low, __u64 high, | 1711 | int n, |
1628 | union nilfs_bmap_ptr_req *dreq, | 1712 | union nilfs_bmap_ptr_req *dreq, |
1629 | union nilfs_bmap_ptr_req *nreq, | 1713 | union nilfs_bmap_ptr_req *nreq, |
1630 | struct buffer_head *bh) | 1714 | struct buffer_head *bh) |
@@ -1642,12 +1726,10 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
1642 | 1726 | ||
1643 | /* convert and insert */ | 1727 | /* convert and insert */ |
1644 | btree = (struct nilfs_btree *)bmap; | 1728 | btree = (struct nilfs_btree *)bmap; |
1645 | nilfs_btree_init(bmap, low, high); | 1729 | nilfs_btree_init(bmap); |
1646 | if (nreq != NULL) { | 1730 | if (nreq != NULL) { |
1647 | if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) { | 1731 | nilfs_bmap_commit_alloc_ptr(bmap, dreq); |
1648 | bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); | 1732 | nilfs_bmap_commit_alloc_ptr(bmap, nreq); |
1649 | bmap->b_pops->bpop_commit_alloc_ptr(bmap, nreq); | ||
1650 | } | ||
1651 | 1733 | ||
1652 | /* create child node at level 1 */ | 1734 | /* create child node at level 1 */ |
1653 | lock_buffer(bh); | 1735 | lock_buffer(bh); |
@@ -1661,7 +1743,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
1661 | nilfs_bmap_set_dirty(bmap); | 1743 | nilfs_bmap_set_dirty(bmap); |
1662 | 1744 | ||
1663 | unlock_buffer(bh); | 1745 | unlock_buffer(bh); |
1664 | nilfs_bmap_put_block(bmap, bh); | 1746 | brelse(bh); |
1665 | 1747 | ||
1666 | /* create root node at level 2 */ | 1748 | /* create root node at level 2 */ |
1667 | node = nilfs_btree_get_root(btree); | 1749 | node = nilfs_btree_get_root(btree); |
@@ -1669,8 +1751,7 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
1669 | nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, | 1751 | nilfs_btree_node_init(btree, node, NILFS_BTREE_NODE_ROOT, |
1670 | 2, 1, &keys[0], &tmpptr); | 1752 | 2, 1, &keys[0], &tmpptr); |
1671 | } else { | 1753 | } else { |
1672 | if (bmap->b_pops->bpop_commit_alloc_ptr != NULL) | 1754 | nilfs_bmap_commit_alloc_ptr(bmap, dreq); |
1673 | bmap->b_pops->bpop_commit_alloc_ptr(bmap, dreq); | ||
1674 | 1755 | ||
1675 | /* create root node at level 1 */ | 1756 | /* create root node at level 1 */ |
1676 | node = nilfs_btree_get_root(btree); | 1757 | node = nilfs_btree_get_root(btree); |
@@ -1682,8 +1763,8 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
1682 | nilfs_bmap_set_dirty(bmap); | 1763 | nilfs_bmap_set_dirty(bmap); |
1683 | } | 1764 | } |
1684 | 1765 | ||
1685 | if (btree->bt_ops->btop_set_target != NULL) | 1766 | if (NILFS_BMAP_USE_VBN(bmap)) |
1686 | btree->bt_ops->btop_set_target(btree, key, dreq->bpr_ptr); | 1767 | nilfs_btree_set_target_v(btree, key, dreq->bpr_ptr); |
1687 | } | 1768 | } |
1688 | 1769 | ||
1689 | /** | 1770 | /** |
@@ -1694,13 +1775,10 @@ nilfs_btree_commit_convert_and_insert(struct nilfs_bmap *bmap, | |||
1694 | * @keys: | 1775 | * @keys: |
1695 | * @ptrs: | 1776 | * @ptrs: |
1696 | * @n: | 1777 | * @n: |
1697 | * @low: | ||
1698 | * @high: | ||
1699 | */ | 1778 | */ |
1700 | int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, | 1779 | int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, |
1701 | __u64 key, __u64 ptr, | 1780 | __u64 key, __u64 ptr, |
1702 | const __u64 *keys, const __u64 *ptrs, | 1781 | const __u64 *keys, const __u64 *ptrs, int n) |
1703 | int n, __u64 low, __u64 high) | ||
1704 | { | 1782 | { |
1705 | struct buffer_head *bh; | 1783 | struct buffer_head *bh; |
1706 | union nilfs_bmap_ptr_req dreq, nreq, *di, *ni; | 1784 | union nilfs_bmap_ptr_req dreq, nreq, *di, *ni; |
@@ -1725,7 +1803,7 @@ int nilfs_btree_convert_and_insert(struct nilfs_bmap *bmap, | |||
1725 | if (ret < 0) | 1803 | if (ret < 0) |
1726 | return ret; | 1804 | return ret; |
1727 | nilfs_btree_commit_convert_and_insert(bmap, key, ptr, keys, ptrs, n, | 1805 | nilfs_btree_commit_convert_and_insert(bmap, key, ptr, keys, ptrs, n, |
1728 | low, high, di, ni, bh); | 1806 | di, ni, bh); |
1729 | nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); | 1807 | nilfs_bmap_add_blocks(bmap, stats.bs_nblocks); |
1730 | return 0; | 1808 | return 0; |
1731 | } | 1809 | } |
@@ -1754,9 +1832,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, | |||
1754 | nilfs_btree_node_get_ptr(btree, parent, | 1832 | nilfs_btree_node_get_ptr(btree, parent, |
1755 | path[level + 1].bp_index); | 1833 | path[level + 1].bp_index); |
1756 | path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1; | 1834 | path[level].bp_newreq.bpr_ptr = path[level].bp_oldreq.bpr_ptr + 1; |
1757 | ret = nilfs_bmap_prepare_update(&btree->bt_bmap, | 1835 | ret = nilfs_bmap_prepare_update_v(&btree->bt_bmap, |
1758 | &path[level].bp_oldreq, | 1836 | &path[level].bp_oldreq, |
1759 | &path[level].bp_newreq); | 1837 | &path[level].bp_newreq); |
1760 | if (ret < 0) | 1838 | if (ret < 0) |
1761 | return ret; | 1839 | return ret; |
1762 | 1840 | ||
@@ -1768,9 +1846,9 @@ static int nilfs_btree_prepare_update_v(struct nilfs_btree *btree, | |||
1768 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, | 1846 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, |
1769 | &path[level].bp_ctxt); | 1847 | &path[level].bp_ctxt); |
1770 | if (ret < 0) { | 1848 | if (ret < 0) { |
1771 | nilfs_bmap_abort_update(&btree->bt_bmap, | 1849 | nilfs_bmap_abort_update_v(&btree->bt_bmap, |
1772 | &path[level].bp_oldreq, | 1850 | &path[level].bp_oldreq, |
1773 | &path[level].bp_newreq); | 1851 | &path[level].bp_newreq); |
1774 | return ret; | 1852 | return ret; |
1775 | } | 1853 | } |
1776 | } | 1854 | } |
@@ -1784,9 +1862,9 @@ static void nilfs_btree_commit_update_v(struct nilfs_btree *btree, | |||
1784 | { | 1862 | { |
1785 | struct nilfs_btree_node *parent; | 1863 | struct nilfs_btree_node *parent; |
1786 | 1864 | ||
1787 | nilfs_bmap_commit_update(&btree->bt_bmap, | 1865 | nilfs_bmap_commit_update_v(&btree->bt_bmap, |
1788 | &path[level].bp_oldreq, | 1866 | &path[level].bp_oldreq, |
1789 | &path[level].bp_newreq); | 1867 | &path[level].bp_newreq); |
1790 | 1868 | ||
1791 | if (buffer_nilfs_node(path[level].bp_bh)) { | 1869 | if (buffer_nilfs_node(path[level].bp_bh)) { |
1792 | nilfs_btnode_commit_change_key( | 1870 | nilfs_btnode_commit_change_key( |
@@ -1805,9 +1883,9 @@ static void nilfs_btree_abort_update_v(struct nilfs_btree *btree, | |||
1805 | struct nilfs_btree_path *path, | 1883 | struct nilfs_btree_path *path, |
1806 | int level) | 1884 | int level) |
1807 | { | 1885 | { |
1808 | nilfs_bmap_abort_update(&btree->bt_bmap, | 1886 | nilfs_bmap_abort_update_v(&btree->bt_bmap, |
1809 | &path[level].bp_oldreq, | 1887 | &path[level].bp_oldreq, |
1810 | &path[level].bp_newreq); | 1888 | &path[level].bp_newreq); |
1811 | if (buffer_nilfs_node(path[level].bp_bh)) | 1889 | if (buffer_nilfs_node(path[level].bp_bh)) |
1812 | nilfs_btnode_abort_change_key( | 1890 | nilfs_btnode_abort_change_key( |
1813 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, | 1891 | &NILFS_BMAP_I(&btree->bt_bmap)->i_btnode_cache, |
@@ -1930,7 +2008,9 @@ static int nilfs_btree_propagate(const struct nilfs_bmap *bmap, | |||
1930 | goto out; | 2008 | goto out; |
1931 | } | 2009 | } |
1932 | 2010 | ||
1933 | ret = btree->bt_ops->btop_propagate(btree, path, level, bh); | 2011 | ret = NILFS_BMAP_USE_VBN(bmap) ? |
2012 | nilfs_btree_propagate_v(btree, path, level, bh) : | ||
2013 | nilfs_btree_propagate_p(btree, path, level, bh); | ||
1934 | 2014 | ||
1935 | out: | 2015 | out: |
1936 | nilfs_btree_clear_path(btree, path); | 2016 | nilfs_btree_clear_path(btree, path); |
@@ -2066,12 +2146,9 @@ static int nilfs_btree_assign_v(struct nilfs_btree *btree, | |||
2066 | ptr = nilfs_btree_node_get_ptr(btree, parent, | 2146 | ptr = nilfs_btree_node_get_ptr(btree, parent, |
2067 | path[level + 1].bp_index); | 2147 | path[level + 1].bp_index); |
2068 | req.bpr_ptr = ptr; | 2148 | req.bpr_ptr = ptr; |
2069 | ret = btree->bt_bmap.b_pops->bpop_prepare_start_ptr(&btree->bt_bmap, | 2149 | ret = nilfs_bmap_start_v(&btree->bt_bmap, &req, blocknr); |
2070 | &req); | 2150 | if (unlikely(ret < 0)) |
2071 | if (ret < 0) | ||
2072 | return ret; | 2151 | return ret; |
2073 | btree->bt_bmap.b_pops->bpop_commit_start_ptr(&btree->bt_bmap, | ||
2074 | &req, blocknr); | ||
2075 | 2152 | ||
2076 | key = nilfs_btree_node_get_key(btree, parent, | 2153 | key = nilfs_btree_node_get_key(btree, parent, |
2077 | path[level + 1].bp_index); | 2154 | path[level + 1].bp_index); |
@@ -2114,8 +2191,9 @@ static int nilfs_btree_assign(struct nilfs_bmap *bmap, | |||
2114 | goto out; | 2191 | goto out; |
2115 | } | 2192 | } |
2116 | 2193 | ||
2117 | ret = btree->bt_ops->btop_assign(btree, path, level, bh, | 2194 | ret = NILFS_BMAP_USE_VBN(bmap) ? |
2118 | blocknr, binfo); | 2195 | nilfs_btree_assign_v(btree, path, level, bh, blocknr, binfo) : |
2196 | nilfs_btree_assign_p(btree, path, level, bh, blocknr, binfo); | ||
2119 | 2197 | ||
2120 | out: | 2198 | out: |
2121 | nilfs_btree_clear_path(btree, path); | 2199 | nilfs_btree_clear_path(btree, path); |
@@ -2171,7 +2249,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) | |||
2171 | WARN_ON(ret == -ENOENT); | 2249 | WARN_ON(ret == -ENOENT); |
2172 | goto out; | 2250 | goto out; |
2173 | } | 2251 | } |
2174 | ret = nilfs_bmap_get_block(&btree->bt_bmap, ptr, &bh); | 2252 | ret = nilfs_btree_get_block(btree, ptr, &bh); |
2175 | if (ret < 0) { | 2253 | if (ret < 0) { |
2176 | WARN_ON(ret == -ENOENT); | 2254 | WARN_ON(ret == -ENOENT); |
2177 | goto out; | 2255 | goto out; |
@@ -2179,7 +2257,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) | |||
2179 | 2257 | ||
2180 | if (!buffer_dirty(bh)) | 2258 | if (!buffer_dirty(bh)) |
2181 | nilfs_btnode_mark_dirty(bh); | 2259 | nilfs_btnode_mark_dirty(bh); |
2182 | nilfs_bmap_put_block(&btree->bt_bmap, bh); | 2260 | brelse(bh); |
2183 | if (!nilfs_bmap_dirty(&btree->bt_bmap)) | 2261 | if (!nilfs_bmap_dirty(&btree->bt_bmap)) |
2184 | nilfs_bmap_set_dirty(&btree->bt_bmap); | 2262 | nilfs_bmap_set_dirty(&btree->bt_bmap); |
2185 | 2263 | ||
@@ -2191,6 +2269,7 @@ static int nilfs_btree_mark(struct nilfs_bmap *bmap, __u64 key, int level) | |||
2191 | 2269 | ||
2192 | static const struct nilfs_bmap_operations nilfs_btree_ops = { | 2270 | static const struct nilfs_bmap_operations nilfs_btree_ops = { |
2193 | .bop_lookup = nilfs_btree_lookup, | 2271 | .bop_lookup = nilfs_btree_lookup, |
2272 | .bop_lookup_contig = nilfs_btree_lookup_contig, | ||
2194 | .bop_insert = nilfs_btree_insert, | 2273 | .bop_insert = nilfs_btree_insert, |
2195 | .bop_delete = nilfs_btree_delete, | 2274 | .bop_delete = nilfs_btree_delete, |
2196 | .bop_clear = NULL, | 2275 | .bop_clear = NULL, |
@@ -2210,6 +2289,7 @@ static const struct nilfs_bmap_operations nilfs_btree_ops = { | |||
2210 | 2289 | ||
2211 | static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { | 2290 | static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { |
2212 | .bop_lookup = NULL, | 2291 | .bop_lookup = NULL, |
2292 | .bop_lookup_contig = NULL, | ||
2213 | .bop_insert = NULL, | 2293 | .bop_insert = NULL, |
2214 | .bop_delete = NULL, | 2294 | .bop_delete = NULL, |
2215 | .bop_clear = NULL, | 2295 | .bop_clear = NULL, |
@@ -2227,43 +2307,13 @@ static const struct nilfs_bmap_operations nilfs_btree_ops_gc = { | |||
2227 | .bop_gather_data = NULL, | 2307 | .bop_gather_data = NULL, |
2228 | }; | 2308 | }; |
2229 | 2309 | ||
2230 | static const struct nilfs_btree_operations nilfs_btree_ops_v = { | 2310 | int nilfs_btree_init(struct nilfs_bmap *bmap) |
2231 | .btop_find_target = nilfs_btree_find_target_v, | ||
2232 | .btop_set_target = nilfs_btree_set_target_v, | ||
2233 | .btop_propagate = nilfs_btree_propagate_v, | ||
2234 | .btop_assign = nilfs_btree_assign_v, | ||
2235 | }; | ||
2236 | |||
2237 | static const struct nilfs_btree_operations nilfs_btree_ops_p = { | ||
2238 | .btop_find_target = NULL, | ||
2239 | .btop_set_target = NULL, | ||
2240 | .btop_propagate = nilfs_btree_propagate_p, | ||
2241 | .btop_assign = nilfs_btree_assign_p, | ||
2242 | }; | ||
2243 | |||
2244 | int nilfs_btree_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) | ||
2245 | { | 2311 | { |
2246 | struct nilfs_btree *btree; | ||
2247 | |||
2248 | btree = (struct nilfs_btree *)bmap; | ||
2249 | bmap->b_ops = &nilfs_btree_ops; | 2312 | bmap->b_ops = &nilfs_btree_ops; |
2250 | bmap->b_low = low; | ||
2251 | bmap->b_high = high; | ||
2252 | switch (bmap->b_inode->i_ino) { | ||
2253 | case NILFS_DAT_INO: | ||
2254 | btree->bt_ops = &nilfs_btree_ops_p; | ||
2255 | break; | ||
2256 | default: | ||
2257 | btree->bt_ops = &nilfs_btree_ops_v; | ||
2258 | break; | ||
2259 | } | ||
2260 | |||
2261 | return 0; | 2313 | return 0; |
2262 | } | 2314 | } |
2263 | 2315 | ||
2264 | void nilfs_btree_init_gc(struct nilfs_bmap *bmap) | 2316 | void nilfs_btree_init_gc(struct nilfs_bmap *bmap) |
2265 | { | 2317 | { |
2266 | bmap->b_low = NILFS_BMAP_LARGE_LOW; | ||
2267 | bmap->b_high = NILFS_BMAP_LARGE_HIGH; | ||
2268 | bmap->b_ops = &nilfs_btree_ops_gc; | 2318 | bmap->b_ops = &nilfs_btree_ops_gc; |
2269 | } | 2319 | } |
diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h index 4766deb52fb1..0e72bbbc6b64 100644 --- a/fs/nilfs2/btree.h +++ b/fs/nilfs2/btree.h | |||
@@ -34,28 +34,6 @@ struct nilfs_btree; | |||
34 | struct nilfs_btree_path; | 34 | struct nilfs_btree_path; |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * struct nilfs_btree_operations - B-tree operation table | ||
38 | */ | ||
39 | struct nilfs_btree_operations { | ||
40 | __u64 (*btop_find_target)(const struct nilfs_btree *, | ||
41 | const struct nilfs_btree_path *, __u64); | ||
42 | void (*btop_set_target)(struct nilfs_btree *, __u64, __u64); | ||
43 | |||
44 | struct the_nilfs *(*btop_get_nilfs)(struct nilfs_btree *); | ||
45 | |||
46 | int (*btop_propagate)(struct nilfs_btree *, | ||
47 | struct nilfs_btree_path *, | ||
48 | int, | ||
49 | struct buffer_head *); | ||
50 | int (*btop_assign)(struct nilfs_btree *, | ||
51 | struct nilfs_btree_path *, | ||
52 | int, | ||
53 | struct buffer_head **, | ||
54 | sector_t, | ||
55 | union nilfs_binfo *); | ||
56 | }; | ||
57 | |||
58 | /** | ||
59 | * struct nilfs_btree_node - B-tree node | 37 | * struct nilfs_btree_node - B-tree node |
60 | * @bn_flags: flags | 38 | * @bn_flags: flags |
61 | * @bn_level: level | 39 | * @bn_level: level |
@@ -80,13 +58,9 @@ struct nilfs_btree_node { | |||
80 | /** | 58 | /** |
81 | * struct nilfs_btree - B-tree structure | 59 | * struct nilfs_btree - B-tree structure |
82 | * @bt_bmap: bmap base structure | 60 | * @bt_bmap: bmap base structure |
83 | * @bt_ops: B-tree operation table | ||
84 | */ | 61 | */ |
85 | struct nilfs_btree { | 62 | struct nilfs_btree { |
86 | struct nilfs_bmap bt_bmap; | 63 | struct nilfs_bmap bt_bmap; |
87 | |||
88 | /* B-tree-specific members */ | ||
89 | const struct nilfs_btree_operations *bt_ops; | ||
90 | }; | 64 | }; |
91 | 65 | ||
92 | 66 | ||
@@ -108,10 +82,9 @@ struct nilfs_btree { | |||
108 | 82 | ||
109 | int nilfs_btree_path_cache_init(void); | 83 | int nilfs_btree_path_cache_init(void); |
110 | void nilfs_btree_path_cache_destroy(void); | 84 | void nilfs_btree_path_cache_destroy(void); |
111 | int nilfs_btree_init(struct nilfs_bmap *, __u64, __u64); | 85 | int nilfs_btree_init(struct nilfs_bmap *); |
112 | int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, | 86 | int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64, |
113 | const __u64 *, const __u64 *, | 87 | const __u64 *, const __u64 *, int); |
114 | int, __u64, __u64); | ||
115 | void nilfs_btree_init_gc(struct nilfs_bmap *); | 88 | void nilfs_btree_init_gc(struct nilfs_bmap *); |
116 | 89 | ||
117 | #endif /* _NILFS_BTREE_H */ | 90 | #endif /* _NILFS_BTREE_H */ |
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index cadd36b14d07..aec942cf79e3 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
@@ -295,10 +295,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
295 | return -EINVAL; | 295 | return -EINVAL; |
296 | } | 296 | } |
297 | 297 | ||
298 | /* cannot delete the latest checkpoint */ | ||
299 | if (start == nilfs_mdt_cno(cpfile) - 1) | ||
300 | return -EPERM; | ||
301 | |||
302 | down_write(&NILFS_MDT(cpfile)->mi_sem); | 298 | down_write(&NILFS_MDT(cpfile)->mi_sem); |
303 | 299 | ||
304 | ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); | 300 | ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); |
@@ -311,7 +307,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
311 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); | 307 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); |
312 | if (ret < 0) { | 308 | if (ret < 0) { |
313 | if (ret != -ENOENT) | 309 | if (ret != -ENOENT) |
314 | goto out_header; | 310 | break; |
315 | /* skip hole */ | 311 | /* skip hole */ |
316 | ret = 0; | 312 | ret = 0; |
317 | continue; | 313 | continue; |
@@ -344,7 +340,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
344 | continue; | 340 | continue; |
345 | printk(KERN_ERR "%s: cannot delete block\n", | 341 | printk(KERN_ERR "%s: cannot delete block\n", |
346 | __func__); | 342 | __func__); |
347 | goto out_header; | 343 | break; |
348 | } | 344 | } |
349 | } | 345 | } |
350 | 346 | ||
@@ -362,7 +358,6 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
362 | kunmap_atomic(kaddr, KM_USER0); | 358 | kunmap_atomic(kaddr, KM_USER0); |
363 | } | 359 | } |
364 | 360 | ||
365 | out_header: | ||
366 | brelse(header_bh); | 361 | brelse(header_bh); |
367 | 362 | ||
368 | out_sem: | 363 | out_sem: |
@@ -384,9 +379,10 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, | |||
384 | } | 379 | } |
385 | 380 | ||
386 | static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | 381 | static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, |
387 | struct nilfs_cpinfo *ci, size_t nci) | 382 | void *buf, unsigned cisz, size_t nci) |
388 | { | 383 | { |
389 | struct nilfs_checkpoint *cp; | 384 | struct nilfs_checkpoint *cp; |
385 | struct nilfs_cpinfo *ci = buf; | ||
390 | struct buffer_head *bh; | 386 | struct buffer_head *bh; |
391 | size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; | 387 | size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; |
392 | __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; | 388 | __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; |
@@ -410,17 +406,22 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | |||
410 | kaddr = kmap_atomic(bh->b_page, KM_USER0); | 406 | kaddr = kmap_atomic(bh->b_page, KM_USER0); |
411 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); | 407 | cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); |
412 | for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { | 408 | for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { |
413 | if (!nilfs_checkpoint_invalid(cp)) | 409 | if (!nilfs_checkpoint_invalid(cp)) { |
414 | nilfs_cpfile_checkpoint_to_cpinfo( | 410 | nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, |
415 | cpfile, cp, &ci[n++]); | 411 | ci); |
412 | ci = (void *)ci + cisz; | ||
413 | n++; | ||
414 | } | ||
416 | } | 415 | } |
417 | kunmap_atomic(kaddr, KM_USER0); | 416 | kunmap_atomic(kaddr, KM_USER0); |
418 | brelse(bh); | 417 | brelse(bh); |
419 | } | 418 | } |
420 | 419 | ||
421 | ret = n; | 420 | ret = n; |
422 | if (n > 0) | 421 | if (n > 0) { |
423 | *cnop = ci[n - 1].ci_cno + 1; | 422 | ci = (void *)ci - cisz; |
423 | *cnop = ci->ci_cno + 1; | ||
424 | } | ||
424 | 425 | ||
425 | out: | 426 | out: |
426 | up_read(&NILFS_MDT(cpfile)->mi_sem); | 427 | up_read(&NILFS_MDT(cpfile)->mi_sem); |
@@ -428,11 +429,12 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, | |||
428 | } | 429 | } |
429 | 430 | ||
430 | static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, | 431 | static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, |
431 | struct nilfs_cpinfo *ci, size_t nci) | 432 | void *buf, unsigned cisz, size_t nci) |
432 | { | 433 | { |
433 | struct buffer_head *bh; | 434 | struct buffer_head *bh; |
434 | struct nilfs_cpfile_header *header; | 435 | struct nilfs_cpfile_header *header; |
435 | struct nilfs_checkpoint *cp; | 436 | struct nilfs_checkpoint *cp; |
437 | struct nilfs_cpinfo *ci = buf; | ||
436 | __u64 curr = *cnop, next; | 438 | __u64 curr = *cnop, next; |
437 | unsigned long curr_blkoff, next_blkoff; | 439 | unsigned long curr_blkoff, next_blkoff; |
438 | void *kaddr; | 440 | void *kaddr; |
@@ -472,7 +474,9 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, | |||
472 | if (unlikely(nilfs_checkpoint_invalid(cp) || | 474 | if (unlikely(nilfs_checkpoint_invalid(cp) || |
473 | !nilfs_checkpoint_snapshot(cp))) | 475 | !nilfs_checkpoint_snapshot(cp))) |
474 | break; | 476 | break; |
475 | nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n++]); | 477 | nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); |
478 | ci = (void *)ci + cisz; | ||
479 | n++; | ||
476 | next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); | 480 | next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); |
477 | if (next == 0) | 481 | if (next == 0) |
478 | break; /* reach end of the snapshot list */ | 482 | break; /* reach end of the snapshot list */ |
@@ -511,13 +515,13 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, | |||
511 | */ | 515 | */ |
512 | 516 | ||
513 | ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, | 517 | ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, |
514 | struct nilfs_cpinfo *ci, size_t nci) | 518 | void *buf, unsigned cisz, size_t nci) |
515 | { | 519 | { |
516 | switch (mode) { | 520 | switch (mode) { |
517 | case NILFS_CHECKPOINT: | 521 | case NILFS_CHECKPOINT: |
518 | return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci); | 522 | return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci); |
519 | case NILFS_SNAPSHOT: | 523 | case NILFS_SNAPSHOT: |
520 | return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); | 524 | return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci); |
521 | default: | 525 | default: |
522 | return -EINVAL; | 526 | return -EINVAL; |
523 | } | 527 | } |
@@ -533,20 +537,14 @@ int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) | |||
533 | struct nilfs_cpinfo ci; | 537 | struct nilfs_cpinfo ci; |
534 | __u64 tcno = cno; | 538 | __u64 tcno = cno; |
535 | ssize_t nci; | 539 | ssize_t nci; |
536 | int ret; | ||
537 | 540 | ||
538 | nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1); | 541 | nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); |
539 | if (nci < 0) | 542 | if (nci < 0) |
540 | return nci; | 543 | return nci; |
541 | else if (nci == 0 || ci.ci_cno != cno) | 544 | else if (nci == 0 || ci.ci_cno != cno) |
542 | return -ENOENT; | 545 | return -ENOENT; |
543 | 546 | else if (nilfs_cpinfo_snapshot(&ci)) | |
544 | /* cannot delete the latest checkpoint nor snapshots */ | 547 | return -EBUSY; |
545 | ret = nilfs_cpinfo_snapshot(&ci); | ||
546 | if (ret < 0) | ||
547 | return ret; | ||
548 | else if (ret > 0 || cno == nilfs_mdt_cno(cpfile) - 1) | ||
549 | return -EPERM; | ||
550 | 548 | ||
551 | return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); | 549 | return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); |
552 | } | 550 | } |
diff --git a/fs/nilfs2/cpfile.h b/fs/nilfs2/cpfile.h index 1a8a1008c342..788a45950197 100644 --- a/fs/nilfs2/cpfile.h +++ b/fs/nilfs2/cpfile.h | |||
@@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64); | |||
39 | int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); | 39 | int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); |
40 | int nilfs_cpfile_is_snapshot(struct inode *, __u64); | 40 | int nilfs_cpfile_is_snapshot(struct inode *, __u64); |
41 | int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); | 41 | int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); |
42 | ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, | 42 | ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, void *, unsigned, |
43 | struct nilfs_cpinfo *, size_t); | 43 | size_t); |
44 | 44 | ||
45 | #endif /* _NILFS_CPFILE_H */ | 45 | #endif /* _NILFS_CPFILE_H */ |
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index bb8a5818e7f1..8927ca27e6f7 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c | |||
@@ -92,21 +92,6 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req) | |||
92 | nilfs_palloc_abort_alloc_entry(dat, req); | 92 | nilfs_palloc_abort_alloc_entry(dat, req); |
93 | } | 93 | } |
94 | 94 | ||
95 | int nilfs_dat_prepare_free(struct inode *dat, struct nilfs_palloc_req *req) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | ret = nilfs_palloc_prepare_free_entry(dat, req); | ||
100 | if (ret < 0) | ||
101 | return ret; | ||
102 | ret = nilfs_dat_prepare_entry(dat, req, 0); | ||
103 | if (ret < 0) { | ||
104 | nilfs_palloc_abort_free_entry(dat, req); | ||
105 | return ret; | ||
106 | } | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) | 95 | void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) |
111 | { | 96 | { |
112 | struct nilfs_dat_entry *entry; | 97 | struct nilfs_dat_entry *entry; |
@@ -149,15 +134,6 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req, | |||
149 | entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, | 134 | entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, |
150 | req->pr_entry_bh, kaddr); | 135 | req->pr_entry_bh, kaddr); |
151 | entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat)); | 136 | entry->de_start = cpu_to_le64(nilfs_mdt_cno(dat)); |
152 | if (entry->de_blocknr != cpu_to_le64(0) || | ||
153 | entry->de_end != cpu_to_le64(NILFS_CNO_MAX)) { | ||
154 | printk(KERN_CRIT | ||
155 | "%s: vbn = %llu, start = %llu, end = %llu, pbn = %llu\n", | ||
156 | __func__, (unsigned long long)req->pr_entry_nr, | ||
157 | (unsigned long long)le64_to_cpu(entry->de_start), | ||
158 | (unsigned long long)le64_to_cpu(entry->de_end), | ||
159 | (unsigned long long)le64_to_cpu(entry->de_blocknr)); | ||
160 | } | ||
161 | entry->de_blocknr = cpu_to_le64(blocknr); | 137 | entry->de_blocknr = cpu_to_le64(blocknr); |
162 | kunmap_atomic(kaddr, KM_USER0); | 138 | kunmap_atomic(kaddr, KM_USER0); |
163 | 139 | ||
@@ -391,36 +367,37 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) | |||
391 | return ret; | 367 | return ret; |
392 | } | 368 | } |
393 | 369 | ||
394 | ssize_t nilfs_dat_get_vinfo(struct inode *dat, struct nilfs_vinfo *vinfo, | 370 | ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, |
395 | size_t nvi) | 371 | size_t nvi) |
396 | { | 372 | { |
397 | struct buffer_head *entry_bh; | 373 | struct buffer_head *entry_bh; |
398 | struct nilfs_dat_entry *entry; | 374 | struct nilfs_dat_entry *entry; |
375 | struct nilfs_vinfo *vinfo = buf; | ||
399 | __u64 first, last; | 376 | __u64 first, last; |
400 | void *kaddr; | 377 | void *kaddr; |
401 | unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block; | 378 | unsigned long entries_per_block = NILFS_MDT(dat)->mi_entries_per_block; |
402 | int i, j, n, ret; | 379 | int i, j, n, ret; |
403 | 380 | ||
404 | for (i = 0; i < nvi; i += n) { | 381 | for (i = 0; i < nvi; i += n) { |
405 | ret = nilfs_palloc_get_entry_block(dat, vinfo[i].vi_vblocknr, | 382 | ret = nilfs_palloc_get_entry_block(dat, vinfo->vi_vblocknr, |
406 | 0, &entry_bh); | 383 | 0, &entry_bh); |
407 | if (ret < 0) | 384 | if (ret < 0) |
408 | return ret; | 385 | return ret; |
409 | kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); | 386 | kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); |
410 | /* last virtual block number in this block */ | 387 | /* last virtual block number in this block */ |
411 | first = vinfo[i].vi_vblocknr; | 388 | first = vinfo->vi_vblocknr; |
412 | do_div(first, entries_per_block); | 389 | do_div(first, entries_per_block); |
413 | first *= entries_per_block; | 390 | first *= entries_per_block; |
414 | last = first + entries_per_block - 1; | 391 | last = first + entries_per_block - 1; |
415 | for (j = i, n = 0; | 392 | for (j = i, n = 0; |
416 | j < nvi && vinfo[j].vi_vblocknr >= first && | 393 | j < nvi && vinfo->vi_vblocknr >= first && |
417 | vinfo[j].vi_vblocknr <= last; | 394 | vinfo->vi_vblocknr <= last; |
418 | j++, n++) { | 395 | j++, n++, vinfo = (void *)vinfo + visz) { |
419 | entry = nilfs_palloc_block_get_entry( | 396 | entry = nilfs_palloc_block_get_entry( |
420 | dat, vinfo[j].vi_vblocknr, entry_bh, kaddr); | 397 | dat, vinfo->vi_vblocknr, entry_bh, kaddr); |
421 | vinfo[j].vi_start = le64_to_cpu(entry->de_start); | 398 | vinfo->vi_start = le64_to_cpu(entry->de_start); |
422 | vinfo[j].vi_end = le64_to_cpu(entry->de_end); | 399 | vinfo->vi_end = le64_to_cpu(entry->de_end); |
423 | vinfo[j].vi_blocknr = le64_to_cpu(entry->de_blocknr); | 400 | vinfo->vi_blocknr = le64_to_cpu(entry->de_blocknr); |
424 | } | 401 | } |
425 | kunmap_atomic(kaddr, KM_USER0); | 402 | kunmap_atomic(kaddr, KM_USER0); |
426 | brelse(entry_bh); | 403 | brelse(entry_bh); |
diff --git a/fs/nilfs2/dat.h b/fs/nilfs2/dat.h index d9560654a4b7..d328b81eead4 100644 --- a/fs/nilfs2/dat.h +++ b/fs/nilfs2/dat.h | |||
@@ -47,6 +47,6 @@ void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *); | |||
47 | int nilfs_dat_mark_dirty(struct inode *, __u64); | 47 | int nilfs_dat_mark_dirty(struct inode *, __u64); |
48 | int nilfs_dat_freev(struct inode *, __u64 *, size_t); | 48 | int nilfs_dat_freev(struct inode *, __u64 *, size_t); |
49 | int nilfs_dat_move(struct inode *, __u64, sector_t); | 49 | int nilfs_dat_move(struct inode *, __u64, sector_t); |
50 | ssize_t nilfs_dat_get_vinfo(struct inode *, struct nilfs_vinfo *, size_t); | 50 | ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t); |
51 | 51 | ||
52 | #endif /* _NILFS_DAT_H */ | 52 | #endif /* _NILFS_DAT_H */ |
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index 54100acc1102..1a4fa04cf071 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c | |||
@@ -43,7 +43,6 @@ | |||
43 | */ | 43 | */ |
44 | 44 | ||
45 | #include <linux/pagemap.h> | 45 | #include <linux/pagemap.h> |
46 | #include <linux/smp_lock.h> | ||
47 | #include "nilfs.h" | 46 | #include "nilfs.h" |
48 | #include "page.h" | 47 | #include "page.h" |
49 | 48 | ||
diff --git a/fs/nilfs2/direct.c b/fs/nilfs2/direct.c index c6379e482781..342d9765df8d 100644 --- a/fs/nilfs2/direct.c +++ b/fs/nilfs2/direct.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "page.h" | 25 | #include "page.h" |
26 | #include "direct.h" | 26 | #include "direct.h" |
27 | #include "alloc.h" | 27 | #include "alloc.h" |
28 | #include "dat.h" | ||
28 | 29 | ||
29 | static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct) | 30 | static inline __le64 *nilfs_direct_dptrs(const struct nilfs_direct *direct) |
30 | { | 31 | { |
@@ -62,6 +63,47 @@ static int nilfs_direct_lookup(const struct nilfs_bmap *bmap, | |||
62 | return 0; | 63 | return 0; |
63 | } | 64 | } |
64 | 65 | ||
66 | static int nilfs_direct_lookup_contig(const struct nilfs_bmap *bmap, | ||
67 | __u64 key, __u64 *ptrp, | ||
68 | unsigned maxblocks) | ||
69 | { | ||
70 | struct nilfs_direct *direct = (struct nilfs_direct *)bmap; | ||
71 | struct inode *dat = NULL; | ||
72 | __u64 ptr, ptr2; | ||
73 | sector_t blocknr; | ||
74 | int ret, cnt; | ||
75 | |||
76 | if (key > NILFS_DIRECT_KEY_MAX || | ||
77 | (ptr = nilfs_direct_get_ptr(direct, key)) == | ||
78 | NILFS_BMAP_INVALID_PTR) | ||
79 | return -ENOENT; | ||
80 | |||
81 | if (NILFS_BMAP_USE_VBN(bmap)) { | ||
82 | dat = nilfs_bmap_get_dat(bmap); | ||
83 | ret = nilfs_dat_translate(dat, ptr, &blocknr); | ||
84 | if (ret < 0) | ||
85 | return ret; | ||
86 | ptr = blocknr; | ||
87 | } | ||
88 | |||
89 | maxblocks = min_t(unsigned, maxblocks, NILFS_DIRECT_KEY_MAX - key + 1); | ||
90 | for (cnt = 1; cnt < maxblocks && | ||
91 | (ptr2 = nilfs_direct_get_ptr(direct, key + cnt)) != | ||
92 | NILFS_BMAP_INVALID_PTR; | ||
93 | cnt++) { | ||
94 | if (dat) { | ||
95 | ret = nilfs_dat_translate(dat, ptr2, &blocknr); | ||
96 | if (ret < 0) | ||
97 | return ret; | ||
98 | ptr2 = blocknr; | ||
99 | } | ||
100 | if (ptr2 != ptr + cnt) | ||
101 | break; | ||
102 | } | ||
103 | *ptrp = ptr; | ||
104 | return cnt; | ||
105 | } | ||
106 | |||
65 | static __u64 | 107 | static __u64 |
66 | nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key) | 108 | nilfs_direct_find_target_v(const struct nilfs_direct *direct, __u64 key) |
67 | { | 109 | { |
@@ -90,10 +132,9 @@ static int nilfs_direct_prepare_insert(struct nilfs_direct *direct, | |||
90 | { | 132 | { |
91 | int ret; | 133 | int ret; |
92 | 134 | ||
93 | if (direct->d_ops->dop_find_target != NULL) | 135 | if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) |
94 | req->bpr_ptr = direct->d_ops->dop_find_target(direct, key); | 136 | req->bpr_ptr = nilfs_direct_find_target_v(direct, key); |
95 | ret = direct->d_bmap.b_pops->bpop_prepare_alloc_ptr(&direct->d_bmap, | 137 | ret = nilfs_bmap_prepare_alloc_ptr(&direct->d_bmap, req); |
96 | req); | ||
97 | if (ret < 0) | 138 | if (ret < 0) |
98 | return ret; | 139 | return ret; |
99 | 140 | ||
@@ -111,16 +152,14 @@ static void nilfs_direct_commit_insert(struct nilfs_direct *direct, | |||
111 | bh = (struct buffer_head *)((unsigned long)ptr); | 152 | bh = (struct buffer_head *)((unsigned long)ptr); |
112 | set_buffer_nilfs_volatile(bh); | 153 | set_buffer_nilfs_volatile(bh); |
113 | 154 | ||
114 | if (direct->d_bmap.b_pops->bpop_commit_alloc_ptr != NULL) | 155 | nilfs_bmap_commit_alloc_ptr(&direct->d_bmap, req); |
115 | direct->d_bmap.b_pops->bpop_commit_alloc_ptr( | ||
116 | &direct->d_bmap, req); | ||
117 | nilfs_direct_set_ptr(direct, key, req->bpr_ptr); | 156 | nilfs_direct_set_ptr(direct, key, req->bpr_ptr); |
118 | 157 | ||
119 | if (!nilfs_bmap_dirty(&direct->d_bmap)) | 158 | if (!nilfs_bmap_dirty(&direct->d_bmap)) |
120 | nilfs_bmap_set_dirty(&direct->d_bmap); | 159 | nilfs_bmap_set_dirty(&direct->d_bmap); |
121 | 160 | ||
122 | if (direct->d_ops->dop_set_target != NULL) | 161 | if (NILFS_BMAP_USE_VBN(&direct->d_bmap)) |
123 | direct->d_ops->dop_set_target(direct, key, req->bpr_ptr); | 162 | nilfs_direct_set_target_v(direct, key, req->bpr_ptr); |
124 | } | 163 | } |
125 | 164 | ||
126 | static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | 165 | static int nilfs_direct_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) |
@@ -152,25 +191,18 @@ static int nilfs_direct_prepare_delete(struct nilfs_direct *direct, | |||
152 | { | 191 | { |
153 | int ret; | 192 | int ret; |
154 | 193 | ||
155 | if (direct->d_bmap.b_pops->bpop_prepare_end_ptr != NULL) { | 194 | req->bpr_ptr = nilfs_direct_get_ptr(direct, key); |
156 | req->bpr_ptr = nilfs_direct_get_ptr(direct, key); | 195 | ret = nilfs_bmap_prepare_end_ptr(&direct->d_bmap, req); |
157 | ret = direct->d_bmap.b_pops->bpop_prepare_end_ptr( | 196 | if (!ret) |
158 | &direct->d_bmap, req); | 197 | stats->bs_nblocks = 1; |
159 | if (ret < 0) | 198 | return ret; |
160 | return ret; | ||
161 | } | ||
162 | |||
163 | stats->bs_nblocks = 1; | ||
164 | return 0; | ||
165 | } | 199 | } |
166 | 200 | ||
167 | static void nilfs_direct_commit_delete(struct nilfs_direct *direct, | 201 | static void nilfs_direct_commit_delete(struct nilfs_direct *direct, |
168 | union nilfs_bmap_ptr_req *req, | 202 | union nilfs_bmap_ptr_req *req, |
169 | __u64 key) | 203 | __u64 key) |
170 | { | 204 | { |
171 | if (direct->d_bmap.b_pops->bpop_commit_end_ptr != NULL) | 205 | nilfs_bmap_commit_end_ptr(&direct->d_bmap, req); |
172 | direct->d_bmap.b_pops->bpop_commit_end_ptr( | ||
173 | &direct->d_bmap, req); | ||
174 | nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); | 206 | nilfs_direct_set_ptr(direct, key, NILFS_BMAP_INVALID_PTR); |
175 | } | 207 | } |
176 | 208 | ||
@@ -244,8 +276,7 @@ static int nilfs_direct_gather_data(struct nilfs_bmap *bmap, | |||
244 | } | 276 | } |
245 | 277 | ||
246 | int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, | 278 | int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, |
247 | __u64 key, __u64 *keys, __u64 *ptrs, | 279 | __u64 key, __u64 *keys, __u64 *ptrs, int n) |
248 | int n, __u64 low, __u64 high) | ||
249 | { | 280 | { |
250 | struct nilfs_direct *direct; | 281 | struct nilfs_direct *direct; |
251 | __le64 *dptrs; | 282 | __le64 *dptrs; |
@@ -275,8 +306,7 @@ int nilfs_direct_delete_and_convert(struct nilfs_bmap *bmap, | |||
275 | dptrs[i] = NILFS_BMAP_INVALID_PTR; | 306 | dptrs[i] = NILFS_BMAP_INVALID_PTR; |
276 | } | 307 | } |
277 | 308 | ||
278 | nilfs_direct_init(bmap, low, high); | 309 | nilfs_direct_init(bmap); |
279 | |||
280 | return 0; | 310 | return 0; |
281 | } | 311 | } |
282 | 312 | ||
@@ -293,11 +323,11 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, | |||
293 | if (!buffer_nilfs_volatile(bh)) { | 323 | if (!buffer_nilfs_volatile(bh)) { |
294 | oldreq.bpr_ptr = ptr; | 324 | oldreq.bpr_ptr = ptr; |
295 | newreq.bpr_ptr = ptr; | 325 | newreq.bpr_ptr = ptr; |
296 | ret = nilfs_bmap_prepare_update(&direct->d_bmap, &oldreq, | 326 | ret = nilfs_bmap_prepare_update_v(&direct->d_bmap, &oldreq, |
297 | &newreq); | 327 | &newreq); |
298 | if (ret < 0) | 328 | if (ret < 0) |
299 | return ret; | 329 | return ret; |
300 | nilfs_bmap_commit_update(&direct->d_bmap, &oldreq, &newreq); | 330 | nilfs_bmap_commit_update_v(&direct->d_bmap, &oldreq, &newreq); |
301 | set_buffer_nilfs_volatile(bh); | 331 | set_buffer_nilfs_volatile(bh); |
302 | nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); | 332 | nilfs_direct_set_ptr(direct, key, newreq.bpr_ptr); |
303 | } else | 333 | } else |
@@ -309,12 +339,10 @@ static int nilfs_direct_propagate_v(struct nilfs_direct *direct, | |||
309 | static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, | 339 | static int nilfs_direct_propagate(const struct nilfs_bmap *bmap, |
310 | struct buffer_head *bh) | 340 | struct buffer_head *bh) |
311 | { | 341 | { |
312 | struct nilfs_direct *direct; | 342 | struct nilfs_direct *direct = (struct nilfs_direct *)bmap; |
313 | 343 | ||
314 | direct = (struct nilfs_direct *)bmap; | 344 | return NILFS_BMAP_USE_VBN(bmap) ? |
315 | return (direct->d_ops->dop_propagate != NULL) ? | 345 | nilfs_direct_propagate_v(direct, bh) : 0; |
316 | direct->d_ops->dop_propagate(direct, bh) : | ||
317 | 0; | ||
318 | } | 346 | } |
319 | 347 | ||
320 | static int nilfs_direct_assign_v(struct nilfs_direct *direct, | 348 | static int nilfs_direct_assign_v(struct nilfs_direct *direct, |
@@ -327,12 +355,9 @@ static int nilfs_direct_assign_v(struct nilfs_direct *direct, | |||
327 | int ret; | 355 | int ret; |
328 | 356 | ||
329 | req.bpr_ptr = ptr; | 357 | req.bpr_ptr = ptr; |
330 | ret = direct->d_bmap.b_pops->bpop_prepare_start_ptr( | 358 | ret = nilfs_bmap_start_v(&direct->d_bmap, &req, blocknr); |
331 | &direct->d_bmap, &req); | 359 | if (unlikely(ret < 0)) |
332 | if (ret < 0) | ||
333 | return ret; | 360 | return ret; |
334 | direct->d_bmap.b_pops->bpop_commit_start_ptr(&direct->d_bmap, | ||
335 | &req, blocknr); | ||
336 | 361 | ||
337 | binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); | 362 | binfo->bi_v.bi_vblocknr = nilfs_bmap_ptr_to_dptr(ptr); |
338 | binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); | 363 | binfo->bi_v.bi_blkoff = nilfs_bmap_key_to_dkey(key); |
@@ -377,12 +402,14 @@ static int nilfs_direct_assign(struct nilfs_bmap *bmap, | |||
377 | return -EINVAL; | 402 | return -EINVAL; |
378 | } | 403 | } |
379 | 404 | ||
380 | return direct->d_ops->dop_assign(direct, key, ptr, bh, | 405 | return NILFS_BMAP_USE_VBN(bmap) ? |
381 | blocknr, binfo); | 406 | nilfs_direct_assign_v(direct, key, ptr, bh, blocknr, binfo) : |
407 | nilfs_direct_assign_p(direct, key, ptr, bh, blocknr, binfo); | ||
382 | } | 408 | } |
383 | 409 | ||
384 | static const struct nilfs_bmap_operations nilfs_direct_ops = { | 410 | static const struct nilfs_bmap_operations nilfs_direct_ops = { |
385 | .bop_lookup = nilfs_direct_lookup, | 411 | .bop_lookup = nilfs_direct_lookup, |
412 | .bop_lookup_contig = nilfs_direct_lookup_contig, | ||
386 | .bop_insert = nilfs_direct_insert, | 413 | .bop_insert = nilfs_direct_insert, |
387 | .bop_delete = nilfs_direct_delete, | 414 | .bop_delete = nilfs_direct_delete, |
388 | .bop_clear = NULL, | 415 | .bop_clear = NULL, |
@@ -401,36 +428,8 @@ static const struct nilfs_bmap_operations nilfs_direct_ops = { | |||
401 | }; | 428 | }; |
402 | 429 | ||
403 | 430 | ||
404 | static const struct nilfs_direct_operations nilfs_direct_ops_v = { | 431 | int nilfs_direct_init(struct nilfs_bmap *bmap) |
405 | .dop_find_target = nilfs_direct_find_target_v, | ||
406 | .dop_set_target = nilfs_direct_set_target_v, | ||
407 | .dop_propagate = nilfs_direct_propagate_v, | ||
408 | .dop_assign = nilfs_direct_assign_v, | ||
409 | }; | ||
410 | |||
411 | static const struct nilfs_direct_operations nilfs_direct_ops_p = { | ||
412 | .dop_find_target = NULL, | ||
413 | .dop_set_target = NULL, | ||
414 | .dop_propagate = NULL, | ||
415 | .dop_assign = nilfs_direct_assign_p, | ||
416 | }; | ||
417 | |||
418 | int nilfs_direct_init(struct nilfs_bmap *bmap, __u64 low, __u64 high) | ||
419 | { | 432 | { |
420 | struct nilfs_direct *direct; | ||
421 | |||
422 | direct = (struct nilfs_direct *)bmap; | ||
423 | bmap->b_ops = &nilfs_direct_ops; | 433 | bmap->b_ops = &nilfs_direct_ops; |
424 | bmap->b_low = low; | ||
425 | bmap->b_high = high; | ||
426 | switch (bmap->b_inode->i_ino) { | ||
427 | case NILFS_DAT_INO: | ||
428 | direct->d_ops = &nilfs_direct_ops_p; | ||
429 | break; | ||
430 | default: | ||
431 | direct->d_ops = &nilfs_direct_ops_v; | ||
432 | break; | ||
433 | } | ||
434 | |||
435 | return 0; | 434 | return 0; |
436 | } | 435 | } |
diff --git a/fs/nilfs2/direct.h b/fs/nilfs2/direct.h index 45d2c5cda812..a5ffd66e25d0 100644 --- a/fs/nilfs2/direct.h +++ b/fs/nilfs2/direct.h | |||
@@ -31,18 +31,6 @@ | |||
31 | struct nilfs_direct; | 31 | struct nilfs_direct; |
32 | 32 | ||
33 | /** | 33 | /** |
34 | * struct nilfs_direct_operations - direct mapping operation table | ||
35 | */ | ||
36 | struct nilfs_direct_operations { | ||
37 | __u64 (*dop_find_target)(const struct nilfs_direct *, __u64); | ||
38 | void (*dop_set_target)(struct nilfs_direct *, __u64, __u64); | ||
39 | int (*dop_propagate)(struct nilfs_direct *, struct buffer_head *); | ||
40 | int (*dop_assign)(struct nilfs_direct *, __u64, __u64, | ||
41 | struct buffer_head **, sector_t, | ||
42 | union nilfs_binfo *); | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * struct nilfs_direct_node - direct node | 34 | * struct nilfs_direct_node - direct node |
47 | * @dn_flags: flags | 35 | * @dn_flags: flags |
48 | * @dn_pad: padding | 36 | * @dn_pad: padding |
@@ -55,13 +43,9 @@ struct nilfs_direct_node { | |||
55 | /** | 43 | /** |
56 | * struct nilfs_direct - direct mapping | 44 | * struct nilfs_direct - direct mapping |
57 | * @d_bmap: bmap structure | 45 | * @d_bmap: bmap structure |
58 | * @d_ops: direct mapping operation table | ||
59 | */ | 46 | */ |
60 | struct nilfs_direct { | 47 | struct nilfs_direct { |
61 | struct nilfs_bmap d_bmap; | 48 | struct nilfs_bmap d_bmap; |
62 | |||
63 | /* direct-mapping-specific members */ | ||
64 | const struct nilfs_direct_operations *d_ops; | ||
65 | }; | 49 | }; |
66 | 50 | ||
67 | 51 | ||
@@ -70,9 +54,9 @@ struct nilfs_direct { | |||
70 | #define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1) | 54 | #define NILFS_DIRECT_KEY_MAX (NILFS_DIRECT_NBLOCKS - 1) |
71 | 55 | ||
72 | 56 | ||
73 | int nilfs_direct_init(struct nilfs_bmap *, __u64, __u64); | 57 | int nilfs_direct_init(struct nilfs_bmap *); |
74 | int nilfs_direct_delete_and_convert(struct nilfs_bmap *, __u64, __u64 *, | 58 | int nilfs_direct_delete_and_convert(struct nilfs_bmap *, __u64, __u64 *, |
75 | __u64 *, int, __u64, __u64); | 59 | __u64 *, int); |
76 | 60 | ||
77 | 61 | ||
78 | #endif /* _NILFS_DIRECT_H */ | 62 | #endif /* _NILFS_DIRECT_H */ |
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 19d2102b6a69..1b3c2bb20da9 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c | |||
@@ -52,8 +52,9 @@ | |||
52 | #include "dat.h" | 52 | #include "dat.h" |
53 | #include "ifile.h" | 53 | #include "ifile.h" |
54 | 54 | ||
55 | static struct address_space_operations def_gcinode_aops = {}; | 55 | static struct address_space_operations def_gcinode_aops = { |
56 | /* XXX need def_gcinode_iops/fops? */ | 56 | .sync_page = block_sync_page, |
57 | }; | ||
57 | 58 | ||
58 | /* | 59 | /* |
59 | * nilfs_gccache_submit_read_data() - add data buffer and submit read request | 60 | * nilfs_gccache_submit_read_data() - add data buffer and submit read request |
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 49ab4a49bb4f..fe9d8f2a13f8 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -43,22 +43,23 @@ | |||
43 | * | 43 | * |
44 | * This function does not issue actual read request of the specified data | 44 | * This function does not issue actual read request of the specified data |
45 | * block. It is done by VFS. | 45 | * block. It is done by VFS. |
46 | * Bulk read for direct-io is not supported yet. (should be supported) | ||
47 | */ | 46 | */ |
48 | int nilfs_get_block(struct inode *inode, sector_t blkoff, | 47 | int nilfs_get_block(struct inode *inode, sector_t blkoff, |
49 | struct buffer_head *bh_result, int create) | 48 | struct buffer_head *bh_result, int create) |
50 | { | 49 | { |
51 | struct nilfs_inode_info *ii = NILFS_I(inode); | 50 | struct nilfs_inode_info *ii = NILFS_I(inode); |
52 | unsigned long blknum = 0; | 51 | __u64 blknum = 0; |
53 | int err = 0, ret; | 52 | int err = 0, ret; |
54 | struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); | 53 | struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); |
54 | unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; | ||
55 | 55 | ||
56 | /* This exclusion control is a workaround; should be revised */ | 56 | down_read(&NILFS_MDT(dat)->mi_sem); |
57 | down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 57 | ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks); |
58 | ret = nilfs_bmap_lookup(ii->i_bmap, (unsigned long)blkoff, &blknum); | 58 | up_read(&NILFS_MDT(dat)->mi_sem); |
59 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 59 | if (ret >= 0) { /* found */ |
60 | if (ret == 0) { /* found */ | ||
61 | map_bh(bh_result, inode->i_sb, blknum); | 60 | map_bh(bh_result, inode->i_sb, blknum); |
61 | if (ret > 0) | ||
62 | bh_result->b_size = (ret << inode->i_blkbits); | ||
62 | goto out; | 63 | goto out; |
63 | } | 64 | } |
64 | /* data block was not found */ | 65 | /* data block was not found */ |
@@ -240,7 +241,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
240 | struct address_space_operations nilfs_aops = { | 241 | struct address_space_operations nilfs_aops = { |
241 | .writepage = nilfs_writepage, | 242 | .writepage = nilfs_writepage, |
242 | .readpage = nilfs_readpage, | 243 | .readpage = nilfs_readpage, |
243 | /* .sync_page = nilfs_sync_page, */ | 244 | .sync_page = block_sync_page, |
244 | .writepages = nilfs_writepages, | 245 | .writepages = nilfs_writepages, |
245 | .set_page_dirty = nilfs_set_page_dirty, | 246 | .set_page_dirty = nilfs_set_page_dirty, |
246 | .readpages = nilfs_readpages, | 247 | .readpages = nilfs_readpages, |
@@ -249,6 +250,7 @@ struct address_space_operations nilfs_aops = { | |||
249 | /* .releasepage = nilfs_releasepage, */ | 250 | /* .releasepage = nilfs_releasepage, */ |
250 | .invalidatepage = block_invalidatepage, | 251 | .invalidatepage = block_invalidatepage, |
251 | .direct_IO = nilfs_direct_IO, | 252 | .direct_IO = nilfs_direct_IO, |
253 | .is_partially_uptodate = block_is_partially_uptodate, | ||
252 | }; | 254 | }; |
253 | 255 | ||
254 | struct inode *nilfs_new_inode(struct inode *dir, int mode) | 256 | struct inode *nilfs_new_inode(struct inode *dir, int mode) |
@@ -307,10 +309,6 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) | |||
307 | /* ii->i_file_acl = 0; */ | 309 | /* ii->i_file_acl = 0; */ |
308 | /* ii->i_dir_acl = 0; */ | 310 | /* ii->i_dir_acl = 0; */ |
309 | ii->i_dir_start_lookup = 0; | 311 | ii->i_dir_start_lookup = 0; |
310 | #ifdef CONFIG_NILFS_FS_POSIX_ACL | ||
311 | ii->i_acl = NULL; | ||
312 | ii->i_default_acl = NULL; | ||
313 | #endif | ||
314 | ii->i_cno = 0; | 312 | ii->i_cno = 0; |
315 | nilfs_set_inode_flags(inode); | 313 | nilfs_set_inode_flags(inode); |
316 | spin_lock(&sbi->s_next_gen_lock); | 314 | spin_lock(&sbi->s_next_gen_lock); |
@@ -432,10 +430,6 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, | |||
432 | 430 | ||
433 | raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); | 431 | raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); |
434 | 432 | ||
435 | #ifdef CONFIG_NILFS_FS_POSIX_ACL | ||
436 | ii->i_acl = NILFS_ACL_NOT_CACHED; | ||
437 | ii->i_default_acl = NILFS_ACL_NOT_CACHED; | ||
438 | #endif | ||
439 | if (nilfs_read_inode_common(inode, raw_inode)) | 433 | if (nilfs_read_inode_common(inode, raw_inode)) |
440 | goto failed_unmap; | 434 | goto failed_unmap; |
441 | 435 | ||
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index d6759b92006f..6ea5f872e2de 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -152,7 +152,7 @@ nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | |||
152 | 152 | ||
153 | down_read(&nilfs->ns_segctor_sem); | 153 | down_read(&nilfs->ns_segctor_sem); |
154 | ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, | 154 | ret = nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf, |
155 | nmembs); | 155 | size, nmembs); |
156 | up_read(&nilfs->ns_segctor_sem); | 156 | up_read(&nilfs->ns_segctor_sem); |
157 | return ret; | 157 | return ret; |
158 | } | 158 | } |
@@ -182,7 +182,8 @@ nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | |||
182 | int ret; | 182 | int ret; |
183 | 183 | ||
184 | down_read(&nilfs->ns_segctor_sem); | 184 | down_read(&nilfs->ns_segctor_sem); |
185 | ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs); | 185 | ret = nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, size, |
186 | nmembs); | ||
186 | up_read(&nilfs->ns_segctor_sem); | 187 | up_read(&nilfs->ns_segctor_sem); |
187 | return ret; | 188 | return ret; |
188 | } | 189 | } |
@@ -212,7 +213,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | |||
212 | int ret; | 213 | int ret; |
213 | 214 | ||
214 | down_read(&nilfs->ns_segctor_sem); | 215 | down_read(&nilfs->ns_segctor_sem); |
215 | ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); | 216 | ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs); |
216 | up_read(&nilfs->ns_segctor_sem); | 217 | up_read(&nilfs->ns_segctor_sem); |
217 | return ret; | 218 | return ret; |
218 | } | 219 | } |
@@ -435,24 +436,6 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, | |||
435 | return nmembs; | 436 | return nmembs; |
436 | } | 437 | } |
437 | 438 | ||
438 | static int nilfs_ioctl_free_segments(struct the_nilfs *nilfs, | ||
439 | struct nilfs_argv *argv, void *buf) | ||
440 | { | ||
441 | size_t nmembs = argv->v_nmembs; | ||
442 | struct nilfs_sb_info *sbi = nilfs->ns_writer; | ||
443 | int ret; | ||
444 | |||
445 | if (unlikely(!sbi)) { | ||
446 | /* never happens because called for a writable mount */ | ||
447 | WARN_ON(1); | ||
448 | return -EROFS; | ||
449 | } | ||
450 | ret = nilfs_segctor_add_segments_to_be_freed( | ||
451 | NILFS_SC(sbi), buf, nmembs); | ||
452 | |||
453 | return (ret < 0) ? ret : nmembs; | ||
454 | } | ||
455 | |||
456 | int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | 439 | int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, |
457 | struct nilfs_argv *argv, void **kbufs) | 440 | struct nilfs_argv *argv, void **kbufs) |
458 | { | 441 | { |
@@ -491,14 +474,6 @@ int nilfs_ioctl_prepare_clean_segments(struct the_nilfs *nilfs, | |||
491 | msg = "cannot mark copying blocks dirty"; | 474 | msg = "cannot mark copying blocks dirty"; |
492 | goto failed; | 475 | goto failed; |
493 | } | 476 | } |
494 | ret = nilfs_ioctl_free_segments(nilfs, &argv[4], kbufs[4]); | ||
495 | if (ret < 0) { | ||
496 | /* | ||
497 | * can safely abort because this operation is atomic. | ||
498 | */ | ||
499 | msg = "cannot set segments to be freed"; | ||
500 | goto failed; | ||
501 | } | ||
502 | return 0; | 477 | return 0; |
503 | 478 | ||
504 | failed: | 479 | failed: |
@@ -615,7 +590,7 @@ static int nilfs_ioctl_get_info(struct inode *inode, struct file *filp, | |||
615 | if (copy_from_user(&argv, argp, sizeof(argv))) | 590 | if (copy_from_user(&argv, argp, sizeof(argv))) |
616 | return -EFAULT; | 591 | return -EFAULT; |
617 | 592 | ||
618 | if (argv.v_size != membsz) | 593 | if (argv.v_size < membsz) |
619 | return -EINVAL; | 594 | return -EINVAL; |
620 | 595 | ||
621 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); | 596 | ret = nilfs_ioctl_wrap_copy(nilfs, &argv, _IOC_DIR(cmd), dofunc); |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index bb78745a0e30..2dfd47714ae5 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
@@ -412,8 +412,10 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | |||
412 | return 0; /* Do not request flush for shadow page cache */ | 412 | return 0; /* Do not request flush for shadow page cache */ |
413 | if (!sb) { | 413 | if (!sb) { |
414 | writer = nilfs_get_writer(NILFS_MDT(inode)->mi_nilfs); | 414 | writer = nilfs_get_writer(NILFS_MDT(inode)->mi_nilfs); |
415 | if (!writer) | 415 | if (!writer) { |
416 | nilfs_put_writer(NILFS_MDT(inode)->mi_nilfs); | ||
416 | return -EROFS; | 417 | return -EROFS; |
418 | } | ||
417 | sb = writer->s_super; | 419 | sb = writer->s_super; |
418 | } | 420 | } |
419 | 421 | ||
@@ -430,6 +432,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | |||
430 | 432 | ||
431 | static struct address_space_operations def_mdt_aops = { | 433 | static struct address_space_operations def_mdt_aops = { |
432 | .writepage = nilfs_mdt_write_page, | 434 | .writepage = nilfs_mdt_write_page, |
435 | .sync_page = block_sync_page, | ||
433 | }; | 436 | }; |
434 | 437 | ||
435 | static struct inode_operations def_mdt_iops; | 438 | static struct inode_operations def_mdt_iops; |
@@ -449,7 +452,7 @@ struct inode * | |||
449 | nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, | 452 | nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, |
450 | ino_t ino, gfp_t gfp_mask) | 453 | ino_t ino, gfp_t gfp_mask) |
451 | { | 454 | { |
452 | struct inode *inode = nilfs_alloc_inode(sb); | 455 | struct inode *inode = nilfs_alloc_inode_common(nilfs); |
453 | 456 | ||
454 | if (!inode) | 457 | if (!inode) |
455 | return NULL; | 458 | return NULL; |
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index da6fc0bba2e5..724c63766e82 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -58,10 +58,6 @@ struct nilfs_inode_info { | |||
58 | */ | 58 | */ |
59 | struct rw_semaphore xattr_sem; | 59 | struct rw_semaphore xattr_sem; |
60 | #endif | 60 | #endif |
61 | #ifdef CONFIG_NILFS_POSIX_ACL | ||
62 | struct posix_acl *i_acl; | ||
63 | struct posix_acl *i_default_acl; | ||
64 | #endif | ||
65 | struct buffer_head *i_bh; /* i_bh contains a new or dirty | 61 | struct buffer_head *i_bh; /* i_bh contains a new or dirty |
66 | disk inode */ | 62 | disk inode */ |
67 | struct inode vfs_inode; | 63 | struct inode vfs_inode; |
@@ -263,6 +259,7 @@ extern void nilfs_dirty_inode(struct inode *); | |||
263 | extern struct dentry *nilfs_get_parent(struct dentry *); | 259 | extern struct dentry *nilfs_get_parent(struct dentry *); |
264 | 260 | ||
265 | /* super.c */ | 261 | /* super.c */ |
262 | extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); | ||
266 | extern struct inode *nilfs_alloc_inode(struct super_block *); | 263 | extern struct inode *nilfs_alloc_inode(struct super_block *); |
267 | extern void nilfs_destroy_inode(struct inode *); | 264 | extern void nilfs_destroy_inode(struct inode *); |
268 | extern void nilfs_error(struct super_block *, const char *, const char *, ...) | 265 | extern void nilfs_error(struct super_block *, const char *, const char *, ...) |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index 57afa9d24061..d80cc71be749 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include "segment.h" | 28 | #include "segment.h" |
29 | #include "sufile.h" | 29 | #include "sufile.h" |
30 | #include "page.h" | 30 | #include "page.h" |
31 | #include "seglist.h" | ||
32 | #include "segbuf.h" | 31 | #include "segbuf.h" |
33 | 32 | ||
34 | /* | 33 | /* |
@@ -395,6 +394,24 @@ static void dispose_recovery_list(struct list_head *head) | |||
395 | } | 394 | } |
396 | } | 395 | } |
397 | 396 | ||
397 | struct nilfs_segment_entry { | ||
398 | struct list_head list; | ||
399 | __u64 segnum; | ||
400 | }; | ||
401 | |||
402 | static int nilfs_segment_list_add(struct list_head *head, __u64 segnum) | ||
403 | { | ||
404 | struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS); | ||
405 | |||
406 | if (unlikely(!ent)) | ||
407 | return -ENOMEM; | ||
408 | |||
409 | ent->segnum = segnum; | ||
410 | INIT_LIST_HEAD(&ent->list); | ||
411 | list_add_tail(&ent->list, head); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
398 | void nilfs_dispose_segment_list(struct list_head *head) | 415 | void nilfs_dispose_segment_list(struct list_head *head) |
399 | { | 416 | { |
400 | while (!list_empty(head)) { | 417 | while (!list_empty(head)) { |
@@ -402,7 +419,7 @@ void nilfs_dispose_segment_list(struct list_head *head) | |||
402 | = list_entry(head->next, | 419 | = list_entry(head->next, |
403 | struct nilfs_segment_entry, list); | 420 | struct nilfs_segment_entry, list); |
404 | list_del(&ent->list); | 421 | list_del(&ent->list); |
405 | nilfs_free_segment_entry(ent); | 422 | kfree(ent); |
406 | } | 423 | } |
407 | } | 424 | } |
408 | 425 | ||
@@ -431,12 +448,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
431 | if (unlikely(err)) | 448 | if (unlikely(err)) |
432 | goto failed; | 449 | goto failed; |
433 | 450 | ||
434 | err = -ENOMEM; | ||
435 | for (i = 1; i < 4; i++) { | 451 | for (i = 1; i < 4; i++) { |
436 | ent = nilfs_alloc_segment_entry(segnum[i]); | 452 | err = nilfs_segment_list_add(head, segnum[i]); |
437 | if (unlikely(!ent)) | 453 | if (unlikely(err)) |
438 | goto failed; | 454 | goto failed; |
439 | list_add_tail(&ent->list, head); | ||
440 | } | 455 | } |
441 | 456 | ||
442 | /* | 457 | /* |
@@ -450,7 +465,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, | |||
450 | goto failed; | 465 | goto failed; |
451 | } | 466 | } |
452 | list_del(&ent->list); | 467 | list_del(&ent->list); |
453 | nilfs_free_segment_entry(ent); | 468 | kfree(ent); |
454 | } | 469 | } |
455 | 470 | ||
456 | /* Allocate new segments for recovery */ | 471 | /* Allocate new segments for recovery */ |
@@ -791,7 +806,6 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, | |||
791 | u64 seg_seq; | 806 | u64 seg_seq; |
792 | __u64 segnum, nextnum = 0; | 807 | __u64 segnum, nextnum = 0; |
793 | __u64 cno; | 808 | __u64 cno; |
794 | struct nilfs_segment_entry *ent; | ||
795 | LIST_HEAD(segments); | 809 | LIST_HEAD(segments); |
796 | int empty_seg = 0, scan_newer = 0; | 810 | int empty_seg = 0, scan_newer = 0; |
797 | int ret; | 811 | int ret; |
@@ -892,12 +906,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, | |||
892 | if (empty_seg++) | 906 | if (empty_seg++) |
893 | goto super_root_found; /* found a valid super root */ | 907 | goto super_root_found; /* found a valid super root */ |
894 | 908 | ||
895 | ent = nilfs_alloc_segment_entry(segnum); | 909 | ret = nilfs_segment_list_add(&segments, segnum); |
896 | if (unlikely(!ent)) { | 910 | if (unlikely(ret)) |
897 | ret = -ENOMEM; | ||
898 | goto failed; | 911 | goto failed; |
899 | } | ||
900 | list_add_tail(&ent->list, &segments); | ||
901 | 912 | ||
902 | seg_seq++; | 913 | seg_seq++; |
903 | segnum = nextnum; | 914 | segnum = nextnum; |
diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 1e68821b4a9b..9e3fe17bb96b 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/crc32.h> | 26 | #include <linux/crc32.h> |
27 | #include "page.h" | 27 | #include "page.h" |
28 | #include "segbuf.h" | 28 | #include "segbuf.h" |
29 | #include "seglist.h" | ||
30 | 29 | ||
31 | 30 | ||
32 | static struct kmem_cache *nilfs_segbuf_cachep; | 31 | static struct kmem_cache *nilfs_segbuf_cachep; |
@@ -394,7 +393,7 @@ int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, | |||
394 | * Last BIO is always sent through the following | 393 | * Last BIO is always sent through the following |
395 | * submission. | 394 | * submission. |
396 | */ | 395 | */ |
397 | rw |= (1 << BIO_RW_SYNCIO); | 396 | rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); |
398 | res = nilfs_submit_seg_bio(wi, rw); | 397 | res = nilfs_submit_seg_bio(wi, rw); |
399 | if (unlikely(res)) | 398 | if (unlikely(res)) |
400 | goto failed_bio; | 399 | goto failed_bio; |
diff --git a/fs/nilfs2/seglist.h b/fs/nilfs2/seglist.h deleted file mode 100644 index d39df9144e99..000000000000 --- a/fs/nilfs2/seglist.h +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* | ||
2 | * seglist.h - expediential structure and routines to handle list of segments | ||
3 | * (would be removed in a future release) | ||
4 | * | ||
5 | * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | * | ||
21 | * Written by Ryusuke Konishi <ryusuke@osrg.net> | ||
22 | * | ||
23 | */ | ||
24 | #ifndef _NILFS_SEGLIST_H | ||
25 | #define _NILFS_SEGLIST_H | ||
26 | |||
27 | #include <linux/fs.h> | ||
28 | #include <linux/buffer_head.h> | ||
29 | #include <linux/nilfs2_fs.h> | ||
30 | #include "sufile.h" | ||
31 | |||
32 | struct nilfs_segment_entry { | ||
33 | __u64 segnum; | ||
34 | |||
35 | #define NILFS_SLH_FREED 0x0001 /* The segment was freed provisonally. | ||
36 | It must be cancelled if | ||
37 | construction aborted */ | ||
38 | |||
39 | unsigned flags; | ||
40 | struct list_head list; | ||
41 | struct buffer_head *bh_su; | ||
42 | struct nilfs_segment_usage *raw_su; | ||
43 | }; | ||
44 | |||
45 | |||
46 | void nilfs_dispose_segment_list(struct list_head *); | ||
47 | |||
48 | static inline struct nilfs_segment_entry * | ||
49 | nilfs_alloc_segment_entry(__u64 segnum) | ||
50 | { | ||
51 | struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS); | ||
52 | |||
53 | if (likely(ent)) { | ||
54 | ent->segnum = segnum; | ||
55 | ent->flags = 0; | ||
56 | ent->bh_su = NULL; | ||
57 | ent->raw_su = NULL; | ||
58 | INIT_LIST_HEAD(&ent->list); | ||
59 | } | ||
60 | return ent; | ||
61 | } | ||
62 | |||
63 | static inline int nilfs_open_segment_entry(struct nilfs_segment_entry *ent, | ||
64 | struct inode *sufile) | ||
65 | { | ||
66 | return nilfs_sufile_get_segment_usage(sufile, ent->segnum, | ||
67 | &ent->raw_su, &ent->bh_su); | ||
68 | } | ||
69 | |||
70 | static inline void nilfs_close_segment_entry(struct nilfs_segment_entry *ent, | ||
71 | struct inode *sufile) | ||
72 | { | ||
73 | if (!ent->bh_su) | ||
74 | return; | ||
75 | nilfs_sufile_put_segment_usage(sufile, ent->segnum, ent->bh_su); | ||
76 | ent->bh_su = NULL; | ||
77 | ent->raw_su = NULL; | ||
78 | } | ||
79 | |||
80 | static inline void nilfs_free_segment_entry(struct nilfs_segment_entry *ent) | ||
81 | { | ||
82 | kfree(ent); | ||
83 | } | ||
84 | |||
85 | #endif /* _NILFS_SEGLIST_H */ | ||
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 22c7f65c2403..51ff3d0a4ee2 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include "sufile.h" | 39 | #include "sufile.h" |
40 | #include "cpfile.h" | 40 | #include "cpfile.h" |
41 | #include "ifile.h" | 41 | #include "ifile.h" |
42 | #include "seglist.h" | ||
43 | #include "segbuf.h" | 42 | #include "segbuf.h" |
44 | 43 | ||
45 | 44 | ||
@@ -79,7 +78,8 @@ enum { | |||
79 | /* State flags of collection */ | 78 | /* State flags of collection */ |
80 | #define NILFS_CF_NODE 0x0001 /* Collecting node blocks */ | 79 | #define NILFS_CF_NODE 0x0001 /* Collecting node blocks */ |
81 | #define NILFS_CF_IFILE_STARTED 0x0002 /* IFILE stage has started */ | 80 | #define NILFS_CF_IFILE_STARTED 0x0002 /* IFILE stage has started */ |
82 | #define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED) | 81 | #define NILFS_CF_SUFREED 0x0004 /* segment usages has been freed */ |
82 | #define NILFS_CF_HISTORY_MASK (NILFS_CF_IFILE_STARTED | NILFS_CF_SUFREED) | ||
83 | 83 | ||
84 | /* Operations depending on the construction mode and file type */ | 84 | /* Operations depending on the construction mode and file type */ |
85 | struct nilfs_sc_operations { | 85 | struct nilfs_sc_operations { |
@@ -810,7 +810,7 @@ static int nilfs_segctor_clean(struct nilfs_sc_info *sci) | |||
810 | { | 810 | { |
811 | return list_empty(&sci->sc_dirty_files) && | 811 | return list_empty(&sci->sc_dirty_files) && |
812 | !test_bit(NILFS_SC_DIRTY, &sci->sc_flags) && | 812 | !test_bit(NILFS_SC_DIRTY, &sci->sc_flags) && |
813 | list_empty(&sci->sc_cleaning_segments) && | 813 | sci->sc_nfreesegs == 0 && |
814 | (!nilfs_doing_gc() || list_empty(&sci->sc_gc_inodes)); | 814 | (!nilfs_doing_gc() || list_empty(&sci->sc_gc_inodes)); |
815 | } | 815 | } |
816 | 816 | ||
@@ -1005,44 +1005,6 @@ static void nilfs_drop_collected_inodes(struct list_head *head) | |||
1005 | } | 1005 | } |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static void nilfs_segctor_cancel_free_segments(struct nilfs_sc_info *sci, | ||
1009 | struct inode *sufile) | ||
1010 | |||
1011 | { | ||
1012 | struct list_head *head = &sci->sc_cleaning_segments; | ||
1013 | struct nilfs_segment_entry *ent; | ||
1014 | int err; | ||
1015 | |||
1016 | list_for_each_entry(ent, head, list) { | ||
1017 | if (!(ent->flags & NILFS_SLH_FREED)) | ||
1018 | break; | ||
1019 | err = nilfs_sufile_cancel_free(sufile, ent->segnum); | ||
1020 | WARN_ON(err); /* do not happen */ | ||
1021 | ent->flags &= ~NILFS_SLH_FREED; | ||
1022 | } | ||
1023 | } | ||
1024 | |||
1025 | static int nilfs_segctor_prepare_free_segments(struct nilfs_sc_info *sci, | ||
1026 | struct inode *sufile) | ||
1027 | { | ||
1028 | struct list_head *head = &sci->sc_cleaning_segments; | ||
1029 | struct nilfs_segment_entry *ent; | ||
1030 | int err; | ||
1031 | |||
1032 | list_for_each_entry(ent, head, list) { | ||
1033 | err = nilfs_sufile_free(sufile, ent->segnum); | ||
1034 | if (unlikely(err)) | ||
1035 | return err; | ||
1036 | ent->flags |= NILFS_SLH_FREED; | ||
1037 | } | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static void nilfs_segctor_commit_free_segments(struct nilfs_sc_info *sci) | ||
1042 | { | ||
1043 | nilfs_dispose_segment_list(&sci->sc_cleaning_segments); | ||
1044 | } | ||
1045 | |||
1046 | static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci, | 1008 | static int nilfs_segctor_apply_buffers(struct nilfs_sc_info *sci, |
1047 | struct inode *inode, | 1009 | struct inode *inode, |
1048 | struct list_head *listp, | 1010 | struct list_head *listp, |
@@ -1161,6 +1123,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) | |||
1161 | struct the_nilfs *nilfs = sbi->s_nilfs; | 1123 | struct the_nilfs *nilfs = sbi->s_nilfs; |
1162 | struct list_head *head; | 1124 | struct list_head *head; |
1163 | struct nilfs_inode_info *ii; | 1125 | struct nilfs_inode_info *ii; |
1126 | size_t ndone; | ||
1164 | int err = 0; | 1127 | int err = 0; |
1165 | 1128 | ||
1166 | switch (sci->sc_stage.scnt) { | 1129 | switch (sci->sc_stage.scnt) { |
@@ -1250,10 +1213,16 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) | |||
1250 | break; | 1213 | break; |
1251 | sci->sc_stage.scnt++; /* Fall through */ | 1214 | sci->sc_stage.scnt++; /* Fall through */ |
1252 | case NILFS_ST_SUFILE: | 1215 | case NILFS_ST_SUFILE: |
1253 | err = nilfs_segctor_prepare_free_segments(sci, | 1216 | err = nilfs_sufile_freev(nilfs->ns_sufile, sci->sc_freesegs, |
1254 | nilfs->ns_sufile); | 1217 | sci->sc_nfreesegs, &ndone); |
1255 | if (unlikely(err)) | 1218 | if (unlikely(err)) { |
1219 | nilfs_sufile_cancel_freev(nilfs->ns_sufile, | ||
1220 | sci->sc_freesegs, ndone, | ||
1221 | NULL); | ||
1256 | break; | 1222 | break; |
1223 | } | ||
1224 | sci->sc_stage.flags |= NILFS_CF_SUFREED; | ||
1225 | |||
1257 | err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile, | 1226 | err = nilfs_segctor_scan_file(sci, nilfs->ns_sufile, |
1258 | &nilfs_sc_file_ops); | 1227 | &nilfs_sc_file_ops); |
1259 | if (unlikely(err)) | 1228 | if (unlikely(err)) |
@@ -1486,7 +1455,15 @@ static void nilfs_segctor_end_construction(struct nilfs_sc_info *sci, | |||
1486 | { | 1455 | { |
1487 | if (unlikely(err)) { | 1456 | if (unlikely(err)) { |
1488 | nilfs_segctor_free_incomplete_segments(sci, nilfs); | 1457 | nilfs_segctor_free_incomplete_segments(sci, nilfs); |
1489 | nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); | 1458 | if (sci->sc_stage.flags & NILFS_CF_SUFREED) { |
1459 | int ret; | ||
1460 | |||
1461 | ret = nilfs_sufile_cancel_freev(nilfs->ns_sufile, | ||
1462 | sci->sc_freesegs, | ||
1463 | sci->sc_nfreesegs, | ||
1464 | NULL); | ||
1465 | WARN_ON(ret); /* do not happen */ | ||
1466 | } | ||
1490 | } | 1467 | } |
1491 | nilfs_segctor_clear_segment_buffers(sci); | 1468 | nilfs_segctor_clear_segment_buffers(sci); |
1492 | } | 1469 | } |
@@ -1585,7 +1562,13 @@ static int nilfs_segctor_collect(struct nilfs_sc_info *sci, | |||
1585 | if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) | 1562 | if (mode != SC_LSEG_SR || sci->sc_stage.scnt < NILFS_ST_CPFILE) |
1586 | break; | 1563 | break; |
1587 | 1564 | ||
1588 | nilfs_segctor_cancel_free_segments(sci, nilfs->ns_sufile); | 1565 | if (sci->sc_stage.flags & NILFS_CF_SUFREED) { |
1566 | err = nilfs_sufile_cancel_freev(nilfs->ns_sufile, | ||
1567 | sci->sc_freesegs, | ||
1568 | sci->sc_nfreesegs, | ||
1569 | NULL); | ||
1570 | WARN_ON(err); /* do not happen */ | ||
1571 | } | ||
1589 | nilfs_segctor_clear_segment_buffers(sci); | 1572 | nilfs_segctor_clear_segment_buffers(sci); |
1590 | 1573 | ||
1591 | err = nilfs_segctor_extend_segments(sci, nilfs, nadd); | 1574 | err = nilfs_segctor_extend_segments(sci, nilfs, nadd); |
@@ -1846,26 +1829,13 @@ static int nilfs_segctor_write(struct nilfs_sc_info *sci, | |||
1846 | err = nilfs_segbuf_write(segbuf, &wi); | 1829 | err = nilfs_segbuf_write(segbuf, &wi); |
1847 | 1830 | ||
1848 | res = nilfs_segbuf_wait(segbuf, &wi); | 1831 | res = nilfs_segbuf_wait(segbuf, &wi); |
1849 | err = unlikely(err) ? : res; | 1832 | err = err ? : res; |
1850 | if (unlikely(err)) | 1833 | if (err) |
1851 | return err; | 1834 | return err; |
1852 | } | 1835 | } |
1853 | return 0; | 1836 | return 0; |
1854 | } | 1837 | } |
1855 | 1838 | ||
1856 | static int nilfs_page_has_uncleared_buffer(struct page *page) | ||
1857 | { | ||
1858 | struct buffer_head *head, *bh; | ||
1859 | |||
1860 | head = bh = page_buffers(page); | ||
1861 | do { | ||
1862 | if (buffer_dirty(bh) && !list_empty(&bh->b_assoc_buffers)) | ||
1863 | return 1; | ||
1864 | bh = bh->b_this_page; | ||
1865 | } while (bh != head); | ||
1866 | return 0; | ||
1867 | } | ||
1868 | |||
1869 | static void __nilfs_end_page_io(struct page *page, int err) | 1839 | static void __nilfs_end_page_io(struct page *page, int err) |
1870 | { | 1840 | { |
1871 | if (!err) { | 1841 | if (!err) { |
@@ -1889,13 +1859,26 @@ static void nilfs_end_page_io(struct page *page, int err) | |||
1889 | if (!page) | 1859 | if (!page) |
1890 | return; | 1860 | return; |
1891 | 1861 | ||
1892 | if (buffer_nilfs_node(page_buffers(page)) && | 1862 | if (buffer_nilfs_node(page_buffers(page)) && !PageWriteback(page)) { |
1893 | nilfs_page_has_uncleared_buffer(page)) | 1863 | /* |
1894 | /* For b-tree node pages, this function may be called twice | 1864 | * For b-tree node pages, this function may be called twice |
1895 | or more because they might be split in a segment. | 1865 | * or more because they might be split in a segment. |
1896 | This check assures that cleanup has been done for all | 1866 | */ |
1897 | buffers in a split btnode page. */ | 1867 | if (PageDirty(page)) { |
1868 | /* | ||
1869 | * For pages holding split b-tree node buffers, dirty | ||
1870 | * flag on the buffers may be cleared discretely. | ||
1871 | * In that case, the page is once redirtied for | ||
1872 | * remaining buffers, and it must be cancelled if | ||
1873 | * all the buffers get cleaned later. | ||
1874 | */ | ||
1875 | lock_page(page); | ||
1876 | if (nilfs_page_buffers_clean(page)) | ||
1877 | __nilfs_clear_page_dirty(page); | ||
1878 | unlock_page(page); | ||
1879 | } | ||
1898 | return; | 1880 | return; |
1881 | } | ||
1899 | 1882 | ||
1900 | __nilfs_end_page_io(page, err); | 1883 | __nilfs_end_page_io(page, err); |
1901 | } | 1884 | } |
@@ -1957,7 +1940,7 @@ static void nilfs_segctor_abort_write(struct nilfs_sc_info *sci, | |||
1957 | } | 1940 | } |
1958 | if (bh->b_page != fs_page) { | 1941 | if (bh->b_page != fs_page) { |
1959 | nilfs_end_page_io(fs_page, err); | 1942 | nilfs_end_page_io(fs_page, err); |
1960 | if (unlikely(fs_page == failed_page)) | 1943 | if (fs_page && fs_page == failed_page) |
1961 | goto done; | 1944 | goto done; |
1962 | fs_page = bh->b_page; | 1945 | fs_page = bh->b_page; |
1963 | } | 1946 | } |
@@ -2224,10 +2207,8 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) | |||
2224 | nilfs_segctor_complete_write(sci); | 2207 | nilfs_segctor_complete_write(sci); |
2225 | 2208 | ||
2226 | /* Commit segments */ | 2209 | /* Commit segments */ |
2227 | if (has_sr) { | 2210 | if (has_sr) |
2228 | nilfs_segctor_commit_free_segments(sci); | ||
2229 | nilfs_segctor_clear_metadata_dirty(sci); | 2211 | nilfs_segctor_clear_metadata_dirty(sci); |
2230 | } | ||
2231 | 2212 | ||
2232 | nilfs_segctor_end_construction(sci, nilfs, 0); | 2213 | nilfs_segctor_end_construction(sci, nilfs, 0); |
2233 | 2214 | ||
@@ -2301,48 +2282,6 @@ void nilfs_flush_segment(struct super_block *sb, ino_t ino) | |||
2301 | /* assign bit 0 to data files */ | 2282 | /* assign bit 0 to data files */ |
2302 | } | 2283 | } |
2303 | 2284 | ||
2304 | int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *sci, | ||
2305 | __u64 *segnum, size_t nsegs) | ||
2306 | { | ||
2307 | struct nilfs_segment_entry *ent; | ||
2308 | struct the_nilfs *nilfs = sci->sc_sbi->s_nilfs; | ||
2309 | struct inode *sufile = nilfs->ns_sufile; | ||
2310 | LIST_HEAD(list); | ||
2311 | __u64 *pnum; | ||
2312 | size_t i; | ||
2313 | int err; | ||
2314 | |||
2315 | for (pnum = segnum, i = 0; i < nsegs; pnum++, i++) { | ||
2316 | ent = nilfs_alloc_segment_entry(*pnum); | ||
2317 | if (unlikely(!ent)) { | ||
2318 | err = -ENOMEM; | ||
2319 | goto failed; | ||
2320 | } | ||
2321 | list_add_tail(&ent->list, &list); | ||
2322 | |||
2323 | err = nilfs_open_segment_entry(ent, sufile); | ||
2324 | if (unlikely(err)) | ||
2325 | goto failed; | ||
2326 | |||
2327 | if (unlikely(!nilfs_segment_usage_dirty(ent->raw_su))) | ||
2328 | printk(KERN_WARNING "NILFS: unused segment is " | ||
2329 | "requested to be cleaned (segnum=%llu)\n", | ||
2330 | (unsigned long long)ent->segnum); | ||
2331 | nilfs_close_segment_entry(ent, sufile); | ||
2332 | } | ||
2333 | list_splice(&list, sci->sc_cleaning_segments.prev); | ||
2334 | return 0; | ||
2335 | |||
2336 | failed: | ||
2337 | nilfs_dispose_segment_list(&list); | ||
2338 | return err; | ||
2339 | } | ||
2340 | |||
2341 | void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *sci) | ||
2342 | { | ||
2343 | nilfs_dispose_segment_list(&sci->sc_cleaning_segments); | ||
2344 | } | ||
2345 | |||
2346 | struct nilfs_segctor_wait_request { | 2285 | struct nilfs_segctor_wait_request { |
2347 | wait_queue_t wq; | 2286 | wait_queue_t wq; |
2348 | __u32 seq; | 2287 | __u32 seq; |
@@ -2607,10 +2546,13 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, | |||
2607 | err = nilfs_init_gcdat_inode(nilfs); | 2546 | err = nilfs_init_gcdat_inode(nilfs); |
2608 | if (unlikely(err)) | 2547 | if (unlikely(err)) |
2609 | goto out_unlock; | 2548 | goto out_unlock; |
2549 | |||
2610 | err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); | 2550 | err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); |
2611 | if (unlikely(err)) | 2551 | if (unlikely(err)) |
2612 | goto out_unlock; | 2552 | goto out_unlock; |
2613 | 2553 | ||
2554 | sci->sc_freesegs = kbufs[4]; | ||
2555 | sci->sc_nfreesegs = argv[4].v_nmembs; | ||
2614 | list_splice_init(&nilfs->ns_gc_inodes, sci->sc_gc_inodes.prev); | 2556 | list_splice_init(&nilfs->ns_gc_inodes, sci->sc_gc_inodes.prev); |
2615 | 2557 | ||
2616 | for (;;) { | 2558 | for (;;) { |
@@ -2629,6 +2571,8 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, | |||
2629 | } | 2571 | } |
2630 | 2572 | ||
2631 | out_unlock: | 2573 | out_unlock: |
2574 | sci->sc_freesegs = NULL; | ||
2575 | sci->sc_nfreesegs = 0; | ||
2632 | nilfs_clear_gcdat_inode(nilfs); | 2576 | nilfs_clear_gcdat_inode(nilfs); |
2633 | nilfs_transaction_unlock(sbi); | 2577 | nilfs_transaction_unlock(sbi); |
2634 | return err; | 2578 | return err; |
@@ -2835,7 +2779,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) | |||
2835 | INIT_LIST_HEAD(&sci->sc_dirty_files); | 2779 | INIT_LIST_HEAD(&sci->sc_dirty_files); |
2836 | INIT_LIST_HEAD(&sci->sc_segbufs); | 2780 | INIT_LIST_HEAD(&sci->sc_segbufs); |
2837 | INIT_LIST_HEAD(&sci->sc_gc_inodes); | 2781 | INIT_LIST_HEAD(&sci->sc_gc_inodes); |
2838 | INIT_LIST_HEAD(&sci->sc_cleaning_segments); | ||
2839 | INIT_LIST_HEAD(&sci->sc_copied_buffers); | 2782 | INIT_LIST_HEAD(&sci->sc_copied_buffers); |
2840 | 2783 | ||
2841 | sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; | 2784 | sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; |
@@ -2901,9 +2844,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) | |||
2901 | nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1); | 2844 | nilfs_dispose_list(sbi, &sci->sc_dirty_files, 1); |
2902 | } | 2845 | } |
2903 | 2846 | ||
2904 | if (!list_empty(&sci->sc_cleaning_segments)) | ||
2905 | nilfs_dispose_segment_list(&sci->sc_cleaning_segments); | ||
2906 | |||
2907 | WARN_ON(!list_empty(&sci->sc_segbufs)); | 2847 | WARN_ON(!list_empty(&sci->sc_segbufs)); |
2908 | 2848 | ||
2909 | down_write(&sbi->s_nilfs->ns_segctor_sem); | 2849 | down_write(&sbi->s_nilfs->ns_segctor_sem); |
diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 476bdd5df5be..0d2a475a741b 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h | |||
@@ -90,8 +90,9 @@ struct nilfs_segsum_pointer { | |||
90 | * @sc_nblk_inc: Block count of current generation | 90 | * @sc_nblk_inc: Block count of current generation |
91 | * @sc_dirty_files: List of files to be written | 91 | * @sc_dirty_files: List of files to be written |
92 | * @sc_gc_inodes: List of GC inodes having blocks to be written | 92 | * @sc_gc_inodes: List of GC inodes having blocks to be written |
93 | * @sc_cleaning_segments: List of segments to be freed through construction | ||
94 | * @sc_copied_buffers: List of copied buffers (buffer heads) to freeze data | 93 | * @sc_copied_buffers: List of copied buffers (buffer heads) to freeze data |
94 | * @sc_freesegs: array of segment numbers to be freed | ||
95 | * @sc_nfreesegs: number of segments on @sc_freesegs | ||
95 | * @sc_dsync_inode: inode whose data pages are written for a sync operation | 96 | * @sc_dsync_inode: inode whose data pages are written for a sync operation |
96 | * @sc_dsync_start: start byte offset of data pages | 97 | * @sc_dsync_start: start byte offset of data pages |
97 | * @sc_dsync_end: end byte offset of data pages (inclusive) | 98 | * @sc_dsync_end: end byte offset of data pages (inclusive) |
@@ -131,9 +132,11 @@ struct nilfs_sc_info { | |||
131 | 132 | ||
132 | struct list_head sc_dirty_files; | 133 | struct list_head sc_dirty_files; |
133 | struct list_head sc_gc_inodes; | 134 | struct list_head sc_gc_inodes; |
134 | struct list_head sc_cleaning_segments; | ||
135 | struct list_head sc_copied_buffers; | 135 | struct list_head sc_copied_buffers; |
136 | 136 | ||
137 | __u64 *sc_freesegs; | ||
138 | size_t sc_nfreesegs; | ||
139 | |||
137 | struct nilfs_inode_info *sc_dsync_inode; | 140 | struct nilfs_inode_info *sc_dsync_inode; |
138 | loff_t sc_dsync_start; | 141 | loff_t sc_dsync_start; |
139 | loff_t sc_dsync_end; | 142 | loff_t sc_dsync_end; |
@@ -225,10 +228,6 @@ extern void nilfs_flush_segment(struct super_block *, ino_t); | |||
225 | extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, | 228 | extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, |
226 | void **); | 229 | void **); |
227 | 230 | ||
228 | extern int nilfs_segctor_add_segments_to_be_freed(struct nilfs_sc_info *, | ||
229 | __u64 *, size_t); | ||
230 | extern void nilfs_segctor_clear_segments_to_be_freed(struct nilfs_sc_info *); | ||
231 | |||
232 | extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); | 231 | extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); |
233 | extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *); | 232 | extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *); |
234 | 233 | ||
@@ -240,5 +239,6 @@ extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *, | |||
240 | extern int nilfs_recover_logical_segments(struct the_nilfs *, | 239 | extern int nilfs_recover_logical_segments(struct the_nilfs *, |
241 | struct nilfs_sb_info *, | 240 | struct nilfs_sb_info *, |
242 | struct nilfs_recovery_info *); | 241 | struct nilfs_recovery_info *); |
242 | extern void nilfs_dispose_segment_list(struct list_head *); | ||
243 | 243 | ||
244 | #endif /* _NILFS_SEGMENT_H */ | 244 | #endif /* _NILFS_SEGMENT_H */ |
diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 98e68677f045..37994d4a59cc 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 | * | 19 | * |
20 | * Written by Koji Sato <koji@osrg.net>. | 20 | * Written by Koji Sato <koji@osrg.net>. |
21 | * Rivised by Ryusuke Konishi <ryusuke@osrg.net>. | ||
21 | */ | 22 | */ |
22 | 23 | ||
23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
@@ -108,6 +109,102 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh, | |||
108 | nilfs_mdt_mark_buffer_dirty(header_bh); | 109 | nilfs_mdt_mark_buffer_dirty(header_bh); |
109 | } | 110 | } |
110 | 111 | ||
112 | /** | ||
113 | * nilfs_sufile_updatev - modify multiple segment usages at a time | ||
114 | * @sufile: inode of segment usage file | ||
115 | * @segnumv: array of segment numbers | ||
116 | * @nsegs: size of @segnumv array | ||
117 | * @create: creation flag | ||
118 | * @ndone: place to store number of modified segments on @segnumv | ||
119 | * @dofunc: primitive operation for the update | ||
120 | * | ||
121 | * Description: nilfs_sufile_updatev() repeatedly calls @dofunc | ||
122 | * against the given array of segments. The @dofunc is called with | ||
123 | * buffers of a header block and the sufile block in which the target | ||
124 | * segment usage entry is contained. If @ndone is given, the number | ||
125 | * of successfully modified segments from the head is stored in the | ||
126 | * place @ndone points to. | ||
127 | * | ||
128 | * Return Value: On success, zero is returned. On error, one of the | ||
129 | * following negative error codes is returned. | ||
130 | * | ||
131 | * %-EIO - I/O error. | ||
132 | * | ||
133 | * %-ENOMEM - Insufficient amount of memory available. | ||
134 | * | ||
135 | * %-ENOENT - Given segment usage is in hole block (may be returned if | ||
136 | * @create is zero) | ||
137 | * | ||
138 | * %-EINVAL - Invalid segment usage number | ||
139 | */ | ||
140 | int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs, | ||
141 | int create, size_t *ndone, | ||
142 | void (*dofunc)(struct inode *, __u64, | ||
143 | struct buffer_head *, | ||
144 | struct buffer_head *)) | ||
145 | { | ||
146 | struct buffer_head *header_bh, *bh; | ||
147 | unsigned long blkoff, prev_blkoff; | ||
148 | __u64 *seg; | ||
149 | size_t nerr = 0, n = 0; | ||
150 | int ret = 0; | ||
151 | |||
152 | if (unlikely(nsegs == 0)) | ||
153 | goto out; | ||
154 | |||
155 | down_write(&NILFS_MDT(sufile)->mi_sem); | ||
156 | for (seg = segnumv; seg < segnumv + nsegs; seg++) { | ||
157 | if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) { | ||
158 | printk(KERN_WARNING | ||
159 | "%s: invalid segment number: %llu\n", __func__, | ||
160 | (unsigned long long)*seg); | ||
161 | nerr++; | ||
162 | } | ||
163 | } | ||
164 | if (nerr > 0) { | ||
165 | ret = -EINVAL; | ||
166 | goto out_sem; | ||
167 | } | ||
168 | |||
169 | ret = nilfs_sufile_get_header_block(sufile, &header_bh); | ||
170 | if (ret < 0) | ||
171 | goto out_sem; | ||
172 | |||
173 | seg = segnumv; | ||
174 | blkoff = nilfs_sufile_get_blkoff(sufile, *seg); | ||
175 | ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh); | ||
176 | if (ret < 0) | ||
177 | goto out_header; | ||
178 | |||
179 | for (;;) { | ||
180 | dofunc(sufile, *seg, header_bh, bh); | ||
181 | |||
182 | if (++seg >= segnumv + nsegs) | ||
183 | break; | ||
184 | prev_blkoff = blkoff; | ||
185 | blkoff = nilfs_sufile_get_blkoff(sufile, *seg); | ||
186 | if (blkoff == prev_blkoff) | ||
187 | continue; | ||
188 | |||
189 | /* get different block */ | ||
190 | brelse(bh); | ||
191 | ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh); | ||
192 | if (unlikely(ret < 0)) | ||
193 | goto out_header; | ||
194 | } | ||
195 | brelse(bh); | ||
196 | |||
197 | out_header: | ||
198 | n = seg - segnumv; | ||
199 | brelse(header_bh); | ||
200 | out_sem: | ||
201 | up_write(&NILFS_MDT(sufile)->mi_sem); | ||
202 | out: | ||
203 | if (ndone) | ||
204 | *ndone = n; | ||
205 | return ret; | ||
206 | } | ||
207 | |||
111 | int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, | 208 | int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create, |
112 | void (*dofunc)(struct inode *, __u64, | 209 | void (*dofunc)(struct inode *, __u64, |
113 | struct buffer_head *, | 210 | struct buffer_head *, |
@@ -490,7 +587,8 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, | |||
490 | * nilfs_sufile_get_suinfo - | 587 | * nilfs_sufile_get_suinfo - |
491 | * @sufile: inode of segment usage file | 588 | * @sufile: inode of segment usage file |
492 | * @segnum: segment number to start looking | 589 | * @segnum: segment number to start looking |
493 | * @si: array of suinfo | 590 | * @buf: array of suinfo |
591 | * @sisz: byte size of suinfo | ||
494 | * @nsi: size of suinfo array | 592 | * @nsi: size of suinfo array |
495 | * | 593 | * |
496 | * Description: | 594 | * Description: |
@@ -502,11 +600,12 @@ void nilfs_sufile_do_set_error(struct inode *sufile, __u64 segnum, | |||
502 | * | 600 | * |
503 | * %-ENOMEM - Insufficient amount of memory available. | 601 | * %-ENOMEM - Insufficient amount of memory available. |
504 | */ | 602 | */ |
505 | ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, | 603 | ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, |
506 | struct nilfs_suinfo *si, size_t nsi) | 604 | unsigned sisz, size_t nsi) |
507 | { | 605 | { |
508 | struct buffer_head *su_bh; | 606 | struct buffer_head *su_bh; |
509 | struct nilfs_segment_usage *su; | 607 | struct nilfs_segment_usage *su; |
608 | struct nilfs_suinfo *si = buf; | ||
510 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; | 609 | size_t susz = NILFS_MDT(sufile)->mi_entry_size; |
511 | struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; | 610 | struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; |
512 | void *kaddr; | 611 | void *kaddr; |
@@ -531,20 +630,22 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, | |||
531 | if (ret != -ENOENT) | 630 | if (ret != -ENOENT) |
532 | goto out; | 631 | goto out; |
533 | /* hole */ | 632 | /* hole */ |
534 | memset(&si[i], 0, sizeof(struct nilfs_suinfo) * n); | 633 | memset(si, 0, sisz * n); |
634 | si = (void *)si + sisz * n; | ||
535 | continue; | 635 | continue; |
536 | } | 636 | } |
537 | 637 | ||
538 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); | 638 | kaddr = kmap_atomic(su_bh->b_page, KM_USER0); |
539 | su = nilfs_sufile_block_get_segment_usage( | 639 | su = nilfs_sufile_block_get_segment_usage( |
540 | sufile, segnum, su_bh, kaddr); | 640 | sufile, segnum, su_bh, kaddr); |
541 | for (j = 0; j < n; j++, su = (void *)su + susz) { | 641 | for (j = 0; j < n; |
542 | si[i + j].sui_lastmod = le64_to_cpu(su->su_lastmod); | 642 | j++, su = (void *)su + susz, si = (void *)si + sisz) { |
543 | si[i + j].sui_nblocks = le32_to_cpu(su->su_nblocks); | 643 | si->sui_lastmod = le64_to_cpu(su->su_lastmod); |
544 | si[i + j].sui_flags = le32_to_cpu(su->su_flags) & | 644 | si->sui_nblocks = le32_to_cpu(su->su_nblocks); |
645 | si->sui_flags = le32_to_cpu(su->su_flags) & | ||
545 | ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE); | 646 | ~(1UL << NILFS_SEGMENT_USAGE_ACTIVE); |
546 | if (nilfs_segment_is_active(nilfs, segnum + j)) | 647 | if (nilfs_segment_is_active(nilfs, segnum + j)) |
547 | si[i + j].sui_flags |= | 648 | si->sui_flags |= |
548 | (1UL << NILFS_SEGMENT_USAGE_ACTIVE); | 649 | (1UL << NILFS_SEGMENT_USAGE_ACTIVE); |
549 | } | 650 | } |
550 | kunmap_atomic(kaddr, KM_USER0); | 651 | kunmap_atomic(kaddr, KM_USER0); |
diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index a2e2efd4ade1..a2c4d76c3366 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h | |||
@@ -43,43 +43,27 @@ void nilfs_sufile_put_segment_usage(struct inode *, __u64, | |||
43 | struct buffer_head *); | 43 | struct buffer_head *); |
44 | int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *); | 44 | int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *); |
45 | int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *); | 45 | int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *); |
46 | ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *, | 46 | ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned, |
47 | size_t); | 47 | size_t); |
48 | 48 | ||
49 | int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *, | ||
50 | void (*dofunc)(struct inode *, __u64, | ||
51 | struct buffer_head *, | ||
52 | struct buffer_head *)); | ||
49 | int nilfs_sufile_update(struct inode *, __u64, int, | 53 | int nilfs_sufile_update(struct inode *, __u64, int, |
50 | void (*dofunc)(struct inode *, __u64, | 54 | void (*dofunc)(struct inode *, __u64, |
51 | struct buffer_head *, | 55 | struct buffer_head *, |
52 | struct buffer_head *)); | 56 | struct buffer_head *)); |
53 | void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, | ||
54 | struct buffer_head *); | ||
55 | void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *, | 57 | void nilfs_sufile_do_scrap(struct inode *, __u64, struct buffer_head *, |
56 | struct buffer_head *); | 58 | struct buffer_head *); |
57 | void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *, | 59 | void nilfs_sufile_do_free(struct inode *, __u64, struct buffer_head *, |
58 | struct buffer_head *); | 60 | struct buffer_head *); |
61 | void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, | ||
62 | struct buffer_head *); | ||
59 | void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, | 63 | void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, |
60 | struct buffer_head *); | 64 | struct buffer_head *); |
61 | 65 | ||
62 | /** | 66 | /** |
63 | * nilfs_sufile_cancel_free - | ||
64 | * @sufile: inode of segment usage file | ||
65 | * @segnum: segment number | ||
66 | * | ||
67 | * Description: | ||
68 | * | ||
69 | * Return Value: On success, 0 is returned. On error, one of the following | ||
70 | * negative error codes is returned. | ||
71 | * | ||
72 | * %-EIO - I/O error. | ||
73 | * | ||
74 | * %-ENOMEM - Insufficient amount of memory available. | ||
75 | */ | ||
76 | static inline int nilfs_sufile_cancel_free(struct inode *sufile, __u64 segnum) | ||
77 | { | ||
78 | return nilfs_sufile_update(sufile, segnum, 0, | ||
79 | nilfs_sufile_do_cancel_free); | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * nilfs_sufile_scrap - make a segment garbage | 67 | * nilfs_sufile_scrap - make a segment garbage |
84 | * @sufile: inode of segment usage file | 68 | * @sufile: inode of segment usage file |
85 | * @segnum: segment number to be freed | 69 | * @segnum: segment number to be freed |
@@ -100,6 +84,38 @@ static inline int nilfs_sufile_free(struct inode *sufile, __u64 segnum) | |||
100 | } | 84 | } |
101 | 85 | ||
102 | /** | 86 | /** |
87 | * nilfs_sufile_freev - free segments | ||
88 | * @sufile: inode of segment usage file | ||
89 | * @segnumv: array of segment numbers | ||
90 | * @nsegs: size of @segnumv array | ||
91 | * @ndone: place to store the number of freed segments | ||
92 | */ | ||
93 | static inline int nilfs_sufile_freev(struct inode *sufile, __u64 *segnumv, | ||
94 | size_t nsegs, size_t *ndone) | ||
95 | { | ||
96 | return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone, | ||
97 | nilfs_sufile_do_free); | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * nilfs_sufile_cancel_freev - reallocate freeing segments | ||
102 | * @sufile: inode of segment usage file | ||
103 | * @segnumv: array of segment numbers | ||
104 | * @nsegs: size of @segnumv array | ||
105 | * @ndone: place to store the number of cancelled segments | ||
106 | * | ||
107 | * Return Value: On success, 0 is returned. On error, a negative error codes | ||
108 | * is returned. | ||
109 | */ | ||
110 | static inline int nilfs_sufile_cancel_freev(struct inode *sufile, | ||
111 | __u64 *segnumv, size_t nsegs, | ||
112 | size_t *ndone) | ||
113 | { | ||
114 | return nilfs_sufile_updatev(sufile, segnumv, nsegs, 0, ndone, | ||
115 | nilfs_sufile_do_cancel_free); | ||
116 | } | ||
117 | |||
118 | /** | ||
103 | * nilfs_sufile_set_error - mark a segment as erroneous | 119 | * nilfs_sufile_set_error - mark a segment as erroneous |
104 | * @sufile: inode of segment usage file | 120 | * @sufile: inode of segment usage file |
105 | * @segnum: segment number | 121 | * @segnum: segment number |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1777a3467bd2..8e2ec43b18f4 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -133,7 +133,7 @@ void nilfs_warning(struct super_block *sb, const char *function, | |||
133 | 133 | ||
134 | static struct kmem_cache *nilfs_inode_cachep; | 134 | static struct kmem_cache *nilfs_inode_cachep; |
135 | 135 | ||
136 | struct inode *nilfs_alloc_inode(struct super_block *sb) | 136 | struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) |
137 | { | 137 | { |
138 | struct nilfs_inode_info *ii; | 138 | struct nilfs_inode_info *ii; |
139 | 139 | ||
@@ -143,10 +143,15 @@ struct inode *nilfs_alloc_inode(struct super_block *sb) | |||
143 | ii->i_bh = NULL; | 143 | ii->i_bh = NULL; |
144 | ii->i_state = 0; | 144 | ii->i_state = 0; |
145 | ii->vfs_inode.i_version = 1; | 145 | ii->vfs_inode.i_version = 1; |
146 | nilfs_btnode_cache_init(&ii->i_btnode_cache); | 146 | nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi); |
147 | return &ii->vfs_inode; | 147 | return &ii->vfs_inode; |
148 | } | 148 | } |
149 | 149 | ||
150 | struct inode *nilfs_alloc_inode(struct super_block *sb) | ||
151 | { | ||
152 | return nilfs_alloc_inode_common(NILFS_SB(sb)->s_nilfs); | ||
153 | } | ||
154 | |||
150 | void nilfs_destroy_inode(struct inode *inode) | 155 | void nilfs_destroy_inode(struct inode *inode) |
151 | { | 156 | { |
152 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); | 157 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); |
@@ -184,16 +189,6 @@ static void nilfs_clear_inode(struct inode *inode) | |||
184 | { | 189 | { |
185 | struct nilfs_inode_info *ii = NILFS_I(inode); | 190 | struct nilfs_inode_info *ii = NILFS_I(inode); |
186 | 191 | ||
187 | #ifdef CONFIG_NILFS_POSIX_ACL | ||
188 | if (ii->i_acl && ii->i_acl != NILFS_ACL_NOT_CACHED) { | ||
189 | posix_acl_release(ii->i_acl); | ||
190 | ii->i_acl = NILFS_ACL_NOT_CACHED; | ||
191 | } | ||
192 | if (ii->i_default_acl && ii->i_default_acl != NILFS_ACL_NOT_CACHED) { | ||
193 | posix_acl_release(ii->i_default_acl); | ||
194 | ii->i_default_acl = NILFS_ACL_NOT_CACHED; | ||
195 | } | ||
196 | #endif | ||
197 | /* | 192 | /* |
198 | * Free resources allocated in nilfs_read_inode(), here. | 193 | * Free resources allocated in nilfs_read_inode(), here. |
199 | */ | 194 | */ |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index e4e5c78bcc93..8b8889825716 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "cpfile.h" | 32 | #include "cpfile.h" |
33 | #include "sufile.h" | 33 | #include "sufile.h" |
34 | #include "dat.h" | 34 | #include "dat.h" |
35 | #include "seglist.h" | ||
36 | #include "segbuf.h" | 35 | #include "segbuf.h" |
37 | 36 | ||
38 | 37 | ||
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 9b0efdad8910..477d37d83b31 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/kmod.h> | 16 | #include <linux/kmod.h> |
17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
18 | #include <asm/byteorder.h> | ||
18 | 19 | ||
19 | static struct nls_table default_table; | 20 | static struct nls_table default_table; |
20 | static struct nls_table *tables = &default_table; | 21 | static struct nls_table *tables = &default_table; |
@@ -43,10 +44,17 @@ static const struct utf8_table utf8_table[] = | |||
43 | {0, /* end of table */} | 44 | {0, /* end of table */} |
44 | }; | 45 | }; |
45 | 46 | ||
46 | int | 47 | #define UNICODE_MAX 0x0010ffff |
47 | utf8_mbtowc(wchar_t *p, const __u8 *s, int n) | 48 | #define PLANE_SIZE 0x00010000 |
49 | |||
50 | #define SURROGATE_MASK 0xfffff800 | ||
51 | #define SURROGATE_PAIR 0x0000d800 | ||
52 | #define SURROGATE_LOW 0x00000400 | ||
53 | #define SURROGATE_BITS 0x000003ff | ||
54 | |||
55 | int utf8_to_utf32(const u8 *s, int len, unicode_t *pu) | ||
48 | { | 56 | { |
49 | long l; | 57 | unsigned long l; |
50 | int c0, c, nc; | 58 | int c0, c, nc; |
51 | const struct utf8_table *t; | 59 | const struct utf8_table *t; |
52 | 60 | ||
@@ -57,12 +65,13 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n) | |||
57 | nc++; | 65 | nc++; |
58 | if ((c0 & t->cmask) == t->cval) { | 66 | if ((c0 & t->cmask) == t->cval) { |
59 | l &= t->lmask; | 67 | l &= t->lmask; |
60 | if (l < t->lval) | 68 | if (l < t->lval || l > UNICODE_MAX || |
69 | (l & SURROGATE_MASK) == SURROGATE_PAIR) | ||
61 | return -1; | 70 | return -1; |
62 | *p = l; | 71 | *pu = (unicode_t) l; |
63 | return nc; | 72 | return nc; |
64 | } | 73 | } |
65 | if (n <= nc) | 74 | if (len <= nc) |
66 | return -1; | 75 | return -1; |
67 | s++; | 76 | s++; |
68 | c = (*s ^ 0x80) & 0xFF; | 77 | c = (*s ^ 0x80) & 0xFF; |
@@ -72,90 +81,133 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n) | |||
72 | } | 81 | } |
73 | return -1; | 82 | return -1; |
74 | } | 83 | } |
84 | EXPORT_SYMBOL(utf8_to_utf32); | ||
75 | 85 | ||
76 | int | 86 | int utf32_to_utf8(unicode_t u, u8 *s, int maxlen) |
77 | utf8_mbstowcs(wchar_t *pwcs, const __u8 *s, int n) | ||
78 | { | 87 | { |
79 | __u16 *op; | 88 | unsigned long l; |
80 | const __u8 *ip; | ||
81 | int size; | ||
82 | |||
83 | op = pwcs; | ||
84 | ip = s; | ||
85 | while (*ip && n > 0) { | ||
86 | if (*ip & 0x80) { | ||
87 | size = utf8_mbtowc(op, ip, n); | ||
88 | if (size == -1) { | ||
89 | /* Ignore character and move on */ | ||
90 | ip++; | ||
91 | n--; | ||
92 | } else { | ||
93 | op++; | ||
94 | ip += size; | ||
95 | n -= size; | ||
96 | } | ||
97 | } else { | ||
98 | *op++ = *ip++; | ||
99 | n--; | ||
100 | } | ||
101 | } | ||
102 | return (op - pwcs); | ||
103 | } | ||
104 | |||
105 | int | ||
106 | utf8_wctomb(__u8 *s, wchar_t wc, int maxlen) | ||
107 | { | ||
108 | long l; | ||
109 | int c, nc; | 89 | int c, nc; |
110 | const struct utf8_table *t; | 90 | const struct utf8_table *t; |
111 | 91 | ||
112 | if (!s) | 92 | if (!s) |
113 | return 0; | 93 | return 0; |
114 | 94 | ||
115 | l = wc; | 95 | l = u; |
96 | if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR) | ||
97 | return -1; | ||
98 | |||
116 | nc = 0; | 99 | nc = 0; |
117 | for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) { | 100 | for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) { |
118 | nc++; | 101 | nc++; |
119 | if (l <= t->lmask) { | 102 | if (l <= t->lmask) { |
120 | c = t->shift; | 103 | c = t->shift; |
121 | *s = t->cval | (l >> c); | 104 | *s = (u8) (t->cval | (l >> c)); |
122 | while (c > 0) { | 105 | while (c > 0) { |
123 | c -= 6; | 106 | c -= 6; |
124 | s++; | 107 | s++; |
125 | *s = 0x80 | ((l >> c) & 0x3F); | 108 | *s = (u8) (0x80 | ((l >> c) & 0x3F)); |
126 | } | 109 | } |
127 | return nc; | 110 | return nc; |
128 | } | 111 | } |
129 | } | 112 | } |
130 | return -1; | 113 | return -1; |
131 | } | 114 | } |
115 | EXPORT_SYMBOL(utf32_to_utf8); | ||
132 | 116 | ||
133 | int | 117 | int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs) |
134 | utf8_wcstombs(__u8 *s, const wchar_t *pwcs, int maxlen) | ||
135 | { | 118 | { |
136 | const __u16 *ip; | 119 | u16 *op; |
137 | __u8 *op; | ||
138 | int size; | 120 | int size; |
121 | unicode_t u; | ||
122 | |||
123 | op = pwcs; | ||
124 | while (*s && len > 0) { | ||
125 | if (*s & 0x80) { | ||
126 | size = utf8_to_utf32(s, len, &u); | ||
127 | if (size < 0) { | ||
128 | /* Ignore character and move on */ | ||
129 | size = 1; | ||
130 | } else if (u >= PLANE_SIZE) { | ||
131 | u -= PLANE_SIZE; | ||
132 | *op++ = (wchar_t) (SURROGATE_PAIR | | ||
133 | ((u >> 10) & SURROGATE_BITS)); | ||
134 | *op++ = (wchar_t) (SURROGATE_PAIR | | ||
135 | SURROGATE_LOW | | ||
136 | (u & SURROGATE_BITS)); | ||
137 | } else { | ||
138 | *op++ = (wchar_t) u; | ||
139 | } | ||
140 | s += size; | ||
141 | len -= size; | ||
142 | } else { | ||
143 | *op++ = *s++; | ||
144 | len--; | ||
145 | } | ||
146 | } | ||
147 | return op - pwcs; | ||
148 | } | ||
149 | EXPORT_SYMBOL(utf8s_to_utf16s); | ||
150 | |||
151 | static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian) | ||
152 | { | ||
153 | switch (endian) { | ||
154 | default: | ||
155 | return c; | ||
156 | case UTF16_LITTLE_ENDIAN: | ||
157 | return __le16_to_cpu(c); | ||
158 | case UTF16_BIG_ENDIAN: | ||
159 | return __be16_to_cpu(c); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian, | ||
164 | u8 *s, int maxlen) | ||
165 | { | ||
166 | u8 *op; | ||
167 | int size; | ||
168 | unsigned long u, v; | ||
139 | 169 | ||
140 | op = s; | 170 | op = s; |
141 | ip = pwcs; | 171 | while (len > 0 && maxlen > 0) { |
142 | while (*ip && maxlen > 0) { | 172 | u = get_utf16(*pwcs, endian); |
143 | if (*ip > 0x7f) { | 173 | if (!u) |
144 | size = utf8_wctomb(op, *ip, maxlen); | 174 | break; |
175 | pwcs++; | ||
176 | len--; | ||
177 | if (u > 0x7f) { | ||
178 | if ((u & SURROGATE_MASK) == SURROGATE_PAIR) { | ||
179 | if (u & SURROGATE_LOW) { | ||
180 | /* Ignore character and move on */ | ||
181 | continue; | ||
182 | } | ||
183 | if (len <= 0) | ||
184 | break; | ||
185 | v = get_utf16(*pwcs, endian); | ||
186 | if ((v & SURROGATE_MASK) != SURROGATE_PAIR || | ||
187 | !(v & SURROGATE_LOW)) { | ||
188 | /* Ignore character and move on */ | ||
189 | continue; | ||
190 | } | ||
191 | u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10) | ||
192 | + (v & SURROGATE_BITS); | ||
193 | pwcs++; | ||
194 | len--; | ||
195 | } | ||
196 | size = utf32_to_utf8(u, op, maxlen); | ||
145 | if (size == -1) { | 197 | if (size == -1) { |
146 | /* Ignore character and move on */ | 198 | /* Ignore character and move on */ |
147 | maxlen--; | ||
148 | } else { | 199 | } else { |
149 | op += size; | 200 | op += size; |
150 | maxlen -= size; | 201 | maxlen -= size; |
151 | } | 202 | } |
152 | } else { | 203 | } else { |
153 | *op++ = (__u8) *ip; | 204 | *op++ = (u8) u; |
205 | maxlen--; | ||
154 | } | 206 | } |
155 | ip++; | ||
156 | } | 207 | } |
157 | return (op - s); | 208 | return op - s; |
158 | } | 209 | } |
210 | EXPORT_SYMBOL(utf16s_to_utf8s); | ||
159 | 211 | ||
160 | int register_nls(struct nls_table * nls) | 212 | int register_nls(struct nls_table * nls) |
161 | { | 213 | { |
@@ -467,9 +519,5 @@ EXPORT_SYMBOL(unregister_nls); | |||
467 | EXPORT_SYMBOL(unload_nls); | 519 | EXPORT_SYMBOL(unload_nls); |
468 | EXPORT_SYMBOL(load_nls); | 520 | EXPORT_SYMBOL(load_nls); |
469 | EXPORT_SYMBOL(load_nls_default); | 521 | EXPORT_SYMBOL(load_nls_default); |
470 | EXPORT_SYMBOL(utf8_mbtowc); | ||
471 | EXPORT_SYMBOL(utf8_mbstowcs); | ||
472 | EXPORT_SYMBOL(utf8_wctomb); | ||
473 | EXPORT_SYMBOL(utf8_wcstombs); | ||
474 | 522 | ||
475 | MODULE_LICENSE("Dual BSD/GPL"); | 523 | MODULE_LICENSE("Dual BSD/GPL"); |
diff --git a/fs/nls/nls_utf8.c b/fs/nls/nls_utf8.c index aa2c42fdd977..0d60a44acacd 100644 --- a/fs/nls/nls_utf8.c +++ b/fs/nls/nls_utf8.c | |||
@@ -15,7 +15,11 @@ static int uni2char(wchar_t uni, unsigned char *out, int boundlen) | |||
15 | { | 15 | { |
16 | int n; | 16 | int n; |
17 | 17 | ||
18 | if ( (n = utf8_wctomb(out, uni, boundlen)) == -1) { | 18 | if (boundlen <= 0) |
19 | return -ENAMETOOLONG; | ||
20 | |||
21 | n = utf32_to_utf8(uni, out, boundlen); | ||
22 | if (n < 0) { | ||
19 | *out = '?'; | 23 | *out = '?'; |
20 | return -EINVAL; | 24 | return -EINVAL; |
21 | } | 25 | } |
@@ -25,11 +29,14 @@ static int uni2char(wchar_t uni, unsigned char *out, int boundlen) | |||
25 | static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) | 29 | static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) |
26 | { | 30 | { |
27 | int n; | 31 | int n; |
32 | unicode_t u; | ||
28 | 33 | ||
29 | if ( (n = utf8_mbtowc(uni, rawstring, boundlen)) == -1) { | 34 | n = utf8_to_utf32(rawstring, boundlen, &u); |
35 | if (n < 0 || u > MAX_WCHAR_T) { | ||
30 | *uni = 0x003f; /* ? */ | 36 | *uni = 0x003f; /* ? */ |
31 | n = -EINVAL; | 37 | return -EINVAL; |
32 | } | 38 | } |
39 | *uni = (wchar_t) u; | ||
33 | return n; | 40 | return n; |
34 | } | 41 | } |
35 | 42 | ||
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig index 31dac7e3b0f1..dffbb0911d02 100644 --- a/fs/notify/Kconfig +++ b/fs/notify/Kconfig | |||
@@ -1,15 +1,5 @@ | |||
1 | config FSNOTIFY | 1 | config FSNOTIFY |
2 | bool "Filesystem notification backend" | 2 | def_bool n |
3 | default y | ||
4 | ---help--- | ||
5 | fsnotify is a backend for filesystem notification. fsnotify does | ||
6 | not provide any userspace interface but does provide the basis | ||
7 | needed for other notification schemes such as dnotify, inotify, | ||
8 | and fanotify. | ||
9 | |||
10 | Say Y here to enable fsnotify suport. | ||
11 | |||
12 | If unsure, say Y. | ||
13 | 3 | ||
14 | source "fs/notify/dnotify/Kconfig" | 4 | source "fs/notify/dnotify/Kconfig" |
15 | source "fs/notify/inotify/Kconfig" | 5 | source "fs/notify/inotify/Kconfig" |
diff --git a/fs/notify/dnotify/Kconfig b/fs/notify/dnotify/Kconfig index 904ff8d5405a..f9c1ca139d8f 100644 --- a/fs/notify/dnotify/Kconfig +++ b/fs/notify/dnotify/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config DNOTIFY | 1 | config DNOTIFY |
2 | bool "Dnotify support" | 2 | bool "Dnotify support" |
3 | depends on FSNOTIFY | 3 | select FSNOTIFY |
4 | default y | 4 | default y |
5 | help | 5 | help |
6 | Dnotify is a directory-based per-fd file change notification system | 6 | Dnotify is a directory-based per-fd file change notification system |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index ec2f7bd76818..037e878e03fc 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -159,7 +159,9 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const | |||
159 | if (!group->ops->should_send_event(group, to_tell, mask)) | 159 | if (!group->ops->should_send_event(group, to_tell, mask)) |
160 | continue; | 160 | continue; |
161 | if (!event) { | 161 | if (!event) { |
162 | event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie); | 162 | event = fsnotify_create_event(to_tell, mask, data, |
163 | data_is, file_name, cookie, | ||
164 | GFP_KERNEL); | ||
163 | /* shit, we OOM'd and now we can't tell, maybe | 165 | /* shit, we OOM'd and now we can't tell, maybe |
164 | * someday someone else will want to do something | 166 | * someday someone else will want to do something |
165 | * here */ | 167 | * here */ |
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig index 5356884289a1..3e56dbffe729 100644 --- a/fs/notify/inotify/Kconfig +++ b/fs/notify/inotify/Kconfig | |||
@@ -15,7 +15,7 @@ config INOTIFY | |||
15 | 15 | ||
16 | config INOTIFY_USER | 16 | config INOTIFY_USER |
17 | bool "Inotify support for userspace" | 17 | bool "Inotify support for userspace" |
18 | depends on FSNOTIFY | 18 | select FSNOTIFY |
19 | default y | 19 | default y |
20 | ---help--- | 20 | ---help--- |
21 | Say Y here to enable inotify support for userspace, including the | 21 | Say Y here to enable inotify support for userspace, including the |
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h index ea2605a58b8a..f234f3a4c8ca 100644 --- a/fs/notify/inotify/inotify.h +++ b/fs/notify/inotify/inotify.h | |||
@@ -15,7 +15,8 @@ struct inotify_inode_mark_entry { | |||
15 | int wd; | 15 | int wd; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | extern void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnotify_group *group); | 18 | extern void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, |
19 | struct fsnotify_group *group); | ||
19 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); | 20 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); |
20 | 21 | ||
21 | extern const struct fsnotify_ops inotify_fsnotify_ops; | 22 | extern const struct fsnotify_ops inotify_fsnotify_ops; |
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index 7ef75b83247e..47cd258fd24d 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
@@ -81,7 +81,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev | |||
81 | 81 | ||
82 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 82 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) |
83 | { | 83 | { |
84 | inotify_destroy_mark_entry(entry, group); | 84 | inotify_ignored_and_remove_idr(entry, group); |
85 | } | 85 | } |
86 | 86 | ||
87 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) | 87 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 982a412ac5bc..f30d9bbc2e1b 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -57,7 +57,6 @@ int inotify_max_user_watches __read_mostly; | |||
57 | 57 | ||
58 | static struct kmem_cache *inotify_inode_mark_cachep __read_mostly; | 58 | static struct kmem_cache *inotify_inode_mark_cachep __read_mostly; |
59 | struct kmem_cache *event_priv_cachep __read_mostly; | 59 | struct kmem_cache *event_priv_cachep __read_mostly; |
60 | static struct fsnotify_event *inotify_ignored_event; | ||
61 | 60 | ||
62 | /* | 61 | /* |
63 | * When inotify registers a new group it increments this and uses that | 62 | * When inotify registers a new group it increments this and uses that |
@@ -296,12 +295,15 @@ static int inotify_fasync(int fd, struct file *file, int on) | |||
296 | static int inotify_release(struct inode *ignored, struct file *file) | 295 | static int inotify_release(struct inode *ignored, struct file *file) |
297 | { | 296 | { |
298 | struct fsnotify_group *group = file->private_data; | 297 | struct fsnotify_group *group = file->private_data; |
298 | struct user_struct *user = group->inotify_data.user; | ||
299 | 299 | ||
300 | fsnotify_clear_marks_by_group(group); | 300 | fsnotify_clear_marks_by_group(group); |
301 | 301 | ||
302 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ | 302 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ |
303 | fsnotify_put_group(group); | 303 | fsnotify_put_group(group); |
304 | 304 | ||
305 | atomic_dec(&user->inotify_devs); | ||
306 | |||
305 | return 0; | 307 | return 0; |
306 | } | 308 | } |
307 | 309 | ||
@@ -362,43 +364,38 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns | |||
362 | return error; | 364 | return error; |
363 | } | 365 | } |
364 | 366 | ||
367 | static void inotify_remove_from_idr(struct fsnotify_group *group, | ||
368 | struct inotify_inode_mark_entry *ientry) | ||
369 | { | ||
370 | struct idr *idr; | ||
371 | |||
372 | spin_lock(&group->inotify_data.idr_lock); | ||
373 | idr = &group->inotify_data.idr; | ||
374 | idr_remove(idr, ientry->wd); | ||
375 | spin_unlock(&group->inotify_data.idr_lock); | ||
376 | ientry->wd = -1; | ||
377 | } | ||
365 | /* | 378 | /* |
366 | * When, for whatever reason, inotify is done with a mark (or what used to be a | 379 | * Send IN_IGNORED for this wd, remove this wd from the idr, and drop the |
367 | * watch) we need to remove that watch from the idr and we need to send IN_IGNORED | 380 | * internal reference help on the mark because it is in the idr. |
368 | * for the given wd. | ||
369 | * | ||
370 | * There is a bit of recursion here. The loop looks like: | ||
371 | * inotify_destroy_mark_entry -> fsnotify_destroy_mark_by_entry -> | ||
372 | * inotify_freeing_mark -> inotify_destory_mark_entry -> restart | ||
373 | * But the loop is broken in 2 places. fsnotify_destroy_mark_by_entry sets | ||
374 | * entry->group = NULL before the call to inotify_freeing_mark, so the if (egroup) | ||
375 | * test below will not call back to fsnotify again. But even if that test wasn't | ||
376 | * there this would still be safe since fsnotify_destroy_mark_by_entry() is | ||
377 | * safe from recursion. | ||
378 | */ | 381 | */ |
379 | void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 382 | void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, |
383 | struct fsnotify_group *group) | ||
380 | { | 384 | { |
381 | struct inotify_inode_mark_entry *ientry; | 385 | struct inotify_inode_mark_entry *ientry; |
386 | struct fsnotify_event *ignored_event; | ||
382 | struct inotify_event_private_data *event_priv; | 387 | struct inotify_event_private_data *event_priv; |
383 | struct fsnotify_event_private_data *fsn_event_priv; | 388 | struct fsnotify_event_private_data *fsn_event_priv; |
384 | struct fsnotify_group *egroup; | ||
385 | struct idr *idr; | ||
386 | |||
387 | spin_lock(&entry->lock); | ||
388 | egroup = entry->group; | ||
389 | 389 | ||
390 | /* if egroup we aren't really done and something might still send events | 390 | ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, |
391 | * for this inode, on the callback we'll send the IN_IGNORED */ | 391 | FSNOTIFY_EVENT_NONE, NULL, 0, |
392 | if (egroup) { | 392 | GFP_NOFS); |
393 | spin_unlock(&entry->lock); | 393 | if (!ignored_event) |
394 | fsnotify_destroy_mark_by_entry(entry); | ||
395 | return; | 394 | return; |
396 | } | ||
397 | spin_unlock(&entry->lock); | ||
398 | 395 | ||
399 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 396 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); |
400 | 397 | ||
401 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); | 398 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); |
402 | if (unlikely(!event_priv)) | 399 | if (unlikely(!event_priv)) |
403 | goto skip_send_ignore; | 400 | goto skip_send_ignore; |
404 | 401 | ||
@@ -407,7 +404,7 @@ void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnoti | |||
407 | fsn_event_priv->group = group; | 404 | fsn_event_priv->group = group; |
408 | event_priv->wd = ientry->wd; | 405 | event_priv->wd = ientry->wd; |
409 | 406 | ||
410 | fsnotify_add_notify_event(group, inotify_ignored_event, fsn_event_priv); | 407 | fsnotify_add_notify_event(group, ignored_event, fsn_event_priv); |
411 | 408 | ||
412 | /* did the private data get added? */ | 409 | /* did the private data get added? */ |
413 | if (list_empty(&fsn_event_priv->event_list)) | 410 | if (list_empty(&fsn_event_priv->event_list)) |
@@ -415,14 +412,16 @@ void inotify_destroy_mark_entry(struct fsnotify_mark_entry *entry, struct fsnoti | |||
415 | 412 | ||
416 | skip_send_ignore: | 413 | skip_send_ignore: |
417 | 414 | ||
415 | /* matches the reference taken when the event was created */ | ||
416 | fsnotify_put_event(ignored_event); | ||
417 | |||
418 | /* remove this entry from the idr */ | 418 | /* remove this entry from the idr */ |
419 | spin_lock(&group->inotify_data.idr_lock); | 419 | inotify_remove_from_idr(group, ientry); |
420 | idr = &group->inotify_data.idr; | ||
421 | idr_remove(idr, ientry->wd); | ||
422 | spin_unlock(&group->inotify_data.idr_lock); | ||
423 | 420 | ||
424 | /* removed from idr, drop that reference */ | 421 | /* removed from idr, drop that reference */ |
425 | fsnotify_put_mark(entry); | 422 | fsnotify_put_mark(entry); |
423 | |||
424 | atomic_dec(&group->inotify_data.user->inotify_watches); | ||
426 | } | 425 | } |
427 | 426 | ||
428 | /* ding dong the mark is dead */ | 427 | /* ding dong the mark is dead */ |
@@ -437,6 +436,7 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod | |||
437 | { | 436 | { |
438 | struct fsnotify_mark_entry *entry = NULL; | 437 | struct fsnotify_mark_entry *entry = NULL; |
439 | struct inotify_inode_mark_entry *ientry; | 438 | struct inotify_inode_mark_entry *ientry; |
439 | struct inotify_inode_mark_entry *tmp_ientry; | ||
440 | int ret = 0; | 440 | int ret = 0; |
441 | int add = (arg & IN_MASK_ADD); | 441 | int add = (arg & IN_MASK_ADD); |
442 | __u32 mask; | 442 | __u32 mask; |
@@ -447,54 +447,66 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod | |||
447 | if (unlikely(!mask)) | 447 | if (unlikely(!mask)) |
448 | return -EINVAL; | 448 | return -EINVAL; |
449 | 449 | ||
450 | ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); | 450 | tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); |
451 | if (unlikely(!ientry)) | 451 | if (unlikely(!tmp_ientry)) |
452 | return -ENOMEM; | 452 | return -ENOMEM; |
453 | /* we set the mask at the end after attaching it */ | 453 | /* we set the mask at the end after attaching it */ |
454 | fsnotify_init_mark(&ientry->fsn_entry, inotify_free_mark); | 454 | fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark); |
455 | ientry->wd = 0; | 455 | tmp_ientry->wd = -1; |
456 | 456 | ||
457 | find_entry: | 457 | find_entry: |
458 | spin_lock(&inode->i_lock); | 458 | spin_lock(&inode->i_lock); |
459 | entry = fsnotify_find_mark_entry(group, inode); | 459 | entry = fsnotify_find_mark_entry(group, inode); |
460 | spin_unlock(&inode->i_lock); | 460 | spin_unlock(&inode->i_lock); |
461 | if (entry) { | 461 | if (entry) { |
462 | kmem_cache_free(inotify_inode_mark_cachep, ientry); | ||
463 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 462 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); |
464 | } else { | 463 | } else { |
465 | if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) { | 464 | ret = -ENOSPC; |
466 | ret = -ENOSPC; | 465 | if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) |
467 | goto out_err; | 466 | goto out_err; |
468 | } | ||
469 | |||
470 | ret = fsnotify_add_mark(&ientry->fsn_entry, group, inode); | ||
471 | if (ret == -EEXIST) | ||
472 | goto find_entry; | ||
473 | else if (ret) | ||
474 | goto out_err; | ||
475 | |||
476 | entry = &ientry->fsn_entry; | ||
477 | retry: | 467 | retry: |
478 | ret = -ENOMEM; | 468 | ret = -ENOMEM; |
479 | if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL))) | 469 | if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL))) |
480 | goto out_err; | 470 | goto out_err; |
481 | 471 | ||
482 | spin_lock(&group->inotify_data.idr_lock); | 472 | spin_lock(&group->inotify_data.idr_lock); |
483 | /* if entry is added to the idr we keep the reference obtained | 473 | ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry, |
484 | * through fsnotify_mark_add. remember to drop this reference | 474 | group->inotify_data.last_wd, |
485 | * when entry is removed from idr */ | 475 | &tmp_ientry->wd); |
486 | ret = idr_get_new_above(&group->inotify_data.idr, entry, | ||
487 | ++group->inotify_data.last_wd, | ||
488 | &ientry->wd); | ||
489 | spin_unlock(&group->inotify_data.idr_lock); | 476 | spin_unlock(&group->inotify_data.idr_lock); |
490 | if (ret) { | 477 | if (ret) { |
491 | if (ret == -EAGAIN) | 478 | if (ret == -EAGAIN) |
492 | goto retry; | 479 | goto retry; |
493 | goto out_err; | 480 | goto out_err; |
494 | } | 481 | } |
482 | |||
483 | ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode); | ||
484 | if (ret) { | ||
485 | inotify_remove_from_idr(group, tmp_ientry); | ||
486 | if (ret == -EEXIST) | ||
487 | goto find_entry; | ||
488 | goto out_err; | ||
489 | } | ||
490 | |||
491 | /* tmp_ientry has been added to the inode, so we are all set up. | ||
492 | * now we just need to make sure tmp_ientry doesn't get freed and | ||
493 | * we need to set up entry and ientry so the generic code can | ||
494 | * do its thing. */ | ||
495 | ientry = tmp_ientry; | ||
496 | entry = &ientry->fsn_entry; | ||
497 | tmp_ientry = NULL; | ||
498 | |||
495 | atomic_inc(&group->inotify_data.user->inotify_watches); | 499 | atomic_inc(&group->inotify_data.user->inotify_watches); |
500 | |||
501 | /* update the idr hint */ | ||
502 | group->inotify_data.last_wd = ientry->wd; | ||
503 | |||
504 | /* we put the mark on the idr, take a reference */ | ||
505 | fsnotify_get_mark(entry); | ||
496 | } | 506 | } |
497 | 507 | ||
508 | ret = ientry->wd; | ||
509 | |||
498 | spin_lock(&entry->lock); | 510 | spin_lock(&entry->lock); |
499 | 511 | ||
500 | old_mask = entry->mask; | 512 | old_mask = entry->mask; |
@@ -525,14 +537,19 @@ retry: | |||
525 | fsnotify_recalc_group_mask(group); | 537 | fsnotify_recalc_group_mask(group); |
526 | } | 538 | } |
527 | 539 | ||
528 | return ientry->wd; | 540 | /* this either matches fsnotify_find_mark_entry, or init_mark_entry |
541 | * depending on which path we took... */ | ||
542 | fsnotify_put_mark(entry); | ||
529 | 543 | ||
530 | out_err: | 544 | out_err: |
531 | /* see this isn't supposed to happen, just kill the watch */ | 545 | /* could be an error, could be that we found an existing mark */ |
532 | if (entry) { | 546 | if (tmp_ientry) { |
533 | fsnotify_destroy_mark_by_entry(entry); | 547 | /* on the idr but didn't make it on the inode */ |
534 | fsnotify_put_mark(entry); | 548 | if (tmp_ientry->wd != -1) |
549 | inotify_remove_from_idr(group, tmp_ientry); | ||
550 | kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry); | ||
535 | } | 551 | } |
552 | |||
536 | return ret; | 553 | return ret; |
537 | } | 554 | } |
538 | 555 | ||
@@ -699,7 +716,7 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) | |||
699 | fsnotify_get_mark(entry); | 716 | fsnotify_get_mark(entry); |
700 | spin_unlock(&group->inotify_data.idr_lock); | 717 | spin_unlock(&group->inotify_data.idr_lock); |
701 | 718 | ||
702 | inotify_destroy_mark_entry(entry, group); | 719 | fsnotify_destroy_mark_by_entry(entry); |
703 | fsnotify_put_mark(entry); | 720 | fsnotify_put_mark(entry); |
704 | 721 | ||
705 | out: | 722 | out: |
@@ -740,9 +757,6 @@ static int __init inotify_user_setup(void) | |||
740 | 757 | ||
741 | inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC); | 758 | inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC); |
742 | event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); | 759 | event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); |
743 | inotify_ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, FSNOTIFY_EVENT_NONE, NULL, 0); | ||
744 | if (!inotify_ignored_event) | ||
745 | panic("unable to allocate the inotify ignored event\n"); | ||
746 | 760 | ||
747 | inotify_max_queued_events = 16384; | 761 | inotify_max_queued_events = 16384; |
748 | inotify_max_user_instances = 128; | 762 | inotify_max_user_instances = 128; |
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 959b73e756fd..521368574e97 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
@@ -136,18 +136,24 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new | |||
136 | { | 136 | { |
137 | if ((old->mask == new->mask) && | 137 | if ((old->mask == new->mask) && |
138 | (old->to_tell == new->to_tell) && | 138 | (old->to_tell == new->to_tell) && |
139 | (old->data_type == new->data_type)) { | 139 | (old->data_type == new->data_type) && |
140 | (old->name_len == new->name_len)) { | ||
140 | switch (old->data_type) { | 141 | switch (old->data_type) { |
141 | case (FSNOTIFY_EVENT_INODE): | 142 | case (FSNOTIFY_EVENT_INODE): |
142 | if (old->inode == new->inode) | 143 | /* remember, after old was put on the wait_q we aren't |
144 | * allowed to look at the inode any more, only thing | ||
145 | * left to check was if the file_name is the same */ | ||
146 | if (old->name_len && | ||
147 | !strcmp(old->file_name, new->file_name)) | ||
143 | return true; | 148 | return true; |
144 | break; | 149 | break; |
145 | case (FSNOTIFY_EVENT_PATH): | 150 | case (FSNOTIFY_EVENT_PATH): |
146 | if ((old->path.mnt == new->path.mnt) && | 151 | if ((old->path.mnt == new->path.mnt) && |
147 | (old->path.dentry == new->path.dentry)) | 152 | (old->path.dentry == new->path.dentry)) |
148 | return true; | 153 | return true; |
154 | break; | ||
149 | case (FSNOTIFY_EVENT_NONE): | 155 | case (FSNOTIFY_EVENT_NONE): |
150 | return true; | 156 | return false; |
151 | }; | 157 | }; |
152 | } | 158 | } |
153 | return false; | 159 | return false; |
@@ -339,18 +345,19 @@ static void initialize_event(struct fsnotify_event *event) | |||
339 | * @name the filename, if available | 345 | * @name the filename, if available |
340 | */ | 346 | */ |
341 | struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data, | 347 | struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data, |
342 | int data_type, const char *name, u32 cookie) | 348 | int data_type, const char *name, u32 cookie, |
349 | gfp_t gfp) | ||
343 | { | 350 | { |
344 | struct fsnotify_event *event; | 351 | struct fsnotify_event *event; |
345 | 352 | ||
346 | event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL); | 353 | event = kmem_cache_alloc(fsnotify_event_cachep, gfp); |
347 | if (!event) | 354 | if (!event) |
348 | return NULL; | 355 | return NULL; |
349 | 356 | ||
350 | initialize_event(event); | 357 | initialize_event(event); |
351 | 358 | ||
352 | if (name) { | 359 | if (name) { |
353 | event->file_name = kstrdup(name, GFP_KERNEL); | 360 | event->file_name = kstrdup(name, gfp); |
354 | if (!event->file_name) { | 361 | if (!event->file_name) { |
355 | kmem_cache_free(fsnotify_event_cachep, event); | 362 | kmem_cache_free(fsnotify_event_cachep, event); |
356 | return NULL; | 363 | return NULL; |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 82c5085559c6..9938034762cc 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
28 | #include <linux/quotaops.h> | 28 | #include <linux/quotaops.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/log2.h> | ||
30 | 31 | ||
31 | #include "aops.h" | 32 | #include "aops.h" |
32 | #include "attrib.h" | 33 | #include "attrib.h" |
@@ -1570,7 +1571,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) | |||
1570 | ntfs_debug("Index collation rule is 0x%x.", | 1571 | ntfs_debug("Index collation rule is 0x%x.", |
1571 | le32_to_cpu(ir->collation_rule)); | 1572 | le32_to_cpu(ir->collation_rule)); |
1572 | ni->itype.index.block_size = le32_to_cpu(ir->index_block_size); | 1573 | ni->itype.index.block_size = le32_to_cpu(ir->index_block_size); |
1573 | if (ni->itype.index.block_size & (ni->itype.index.block_size - 1)) { | 1574 | if (!is_power_of_2(ni->itype.index.block_size)) { |
1574 | ntfs_error(vi->i_sb, "Index block size (%u) is not a power of " | 1575 | ntfs_error(vi->i_sb, "Index block size (%u) is not a power of " |
1575 | "two.", ni->itype.index.block_size); | 1576 | "two.", ni->itype.index.block_size); |
1576 | goto unm_err_out; | 1577 | goto unm_err_out; |
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c index d7932e95b1fd..89b02985c054 100644 --- a/fs/ntfs/logfile.c +++ b/fs/ntfs/logfile.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/highmem.h> | 26 | #include <linux/highmem.h> |
27 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
29 | #include <linux/log2.h> | ||
29 | 30 | ||
30 | #include "attrib.h" | 31 | #include "attrib.h" |
31 | #include "aops.h" | 32 | #include "aops.h" |
@@ -65,7 +66,7 @@ static bool ntfs_check_restart_page_header(struct inode *vi, | |||
65 | logfile_log_page_size < NTFS_BLOCK_SIZE || | 66 | logfile_log_page_size < NTFS_BLOCK_SIZE || |
66 | logfile_system_page_size & | 67 | logfile_system_page_size & |
67 | (logfile_system_page_size - 1) || | 68 | (logfile_system_page_size - 1) || |
68 | logfile_log_page_size & (logfile_log_page_size - 1)) { | 69 | !is_power_of_2(logfile_log_page_size)) { |
69 | ntfs_error(vi->i_sb, "$LogFile uses unsupported page size."); | 70 | ntfs_error(vi->i_sb, "$LogFile uses unsupported page size."); |
70 | return false; | 71 | return false; |
71 | } | 72 | } |
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 678a067d9251..9edcde4974aa 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -475,6 +475,12 @@ struct ocfs2_path { | |||
475 | #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) | 475 | #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el) |
476 | #define path_num_items(_path) ((_path)->p_tree_depth + 1) | 476 | #define path_num_items(_path) ((_path)->p_tree_depth + 1) |
477 | 477 | ||
478 | static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path, | ||
479 | u32 cpos); | ||
480 | static void ocfs2_adjust_rightmost_records(struct inode *inode, | ||
481 | handle_t *handle, | ||
482 | struct ocfs2_path *path, | ||
483 | struct ocfs2_extent_rec *insert_rec); | ||
478 | /* | 484 | /* |
479 | * Reset the actual path elements so that we can re-use the structure | 485 | * Reset the actual path elements so that we can re-use the structure |
480 | * to build another path. Generally, this involves freeing the buffer | 486 | * to build another path. Generally, this involves freeing the buffer |
@@ -1013,6 +1019,54 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el) | |||
1013 | } | 1019 | } |
1014 | 1020 | ||
1015 | /* | 1021 | /* |
1022 | * Change range of the branches in the right most path according to the leaf | ||
1023 | * extent block's rightmost record. | ||
1024 | */ | ||
1025 | static int ocfs2_adjust_rightmost_branch(handle_t *handle, | ||
1026 | struct inode *inode, | ||
1027 | struct ocfs2_extent_tree *et) | ||
1028 | { | ||
1029 | int status; | ||
1030 | struct ocfs2_path *path = NULL; | ||
1031 | struct ocfs2_extent_list *el; | ||
1032 | struct ocfs2_extent_rec *rec; | ||
1033 | |||
1034 | path = ocfs2_new_path_from_et(et); | ||
1035 | if (!path) { | ||
1036 | status = -ENOMEM; | ||
1037 | return status; | ||
1038 | } | ||
1039 | |||
1040 | status = ocfs2_find_path(inode, path, UINT_MAX); | ||
1041 | if (status < 0) { | ||
1042 | mlog_errno(status); | ||
1043 | goto out; | ||
1044 | } | ||
1045 | |||
1046 | status = ocfs2_extend_trans(handle, path_num_items(path) + | ||
1047 | handle->h_buffer_credits); | ||
1048 | if (status < 0) { | ||
1049 | mlog_errno(status); | ||
1050 | goto out; | ||
1051 | } | ||
1052 | |||
1053 | status = ocfs2_journal_access_path(inode, handle, path); | ||
1054 | if (status < 0) { | ||
1055 | mlog_errno(status); | ||
1056 | goto out; | ||
1057 | } | ||
1058 | |||
1059 | el = path_leaf_el(path); | ||
1060 | rec = &el->l_recs[le32_to_cpu(el->l_next_free_rec) - 1]; | ||
1061 | |||
1062 | ocfs2_adjust_rightmost_records(inode, handle, path, rec); | ||
1063 | |||
1064 | out: | ||
1065 | ocfs2_free_path(path); | ||
1066 | return status; | ||
1067 | } | ||
1068 | |||
1069 | /* | ||
1016 | * Add an entire tree branch to our inode. eb_bh is the extent block | 1070 | * Add an entire tree branch to our inode. eb_bh is the extent block |
1017 | * to start at, if we don't want to start the branch at the dinode | 1071 | * to start at, if we don't want to start the branch at the dinode |
1018 | * structure. | 1072 | * structure. |
@@ -1038,7 +1092,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, | |||
1038 | struct ocfs2_extent_block *eb; | 1092 | struct ocfs2_extent_block *eb; |
1039 | struct ocfs2_extent_list *eb_el; | 1093 | struct ocfs2_extent_list *eb_el; |
1040 | struct ocfs2_extent_list *el; | 1094 | struct ocfs2_extent_list *el; |
1041 | u32 new_cpos; | 1095 | u32 new_cpos, root_end; |
1042 | 1096 | ||
1043 | mlog_entry_void(); | 1097 | mlog_entry_void(); |
1044 | 1098 | ||
@@ -1055,6 +1109,27 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, | |||
1055 | 1109 | ||
1056 | new_blocks = le16_to_cpu(el->l_tree_depth); | 1110 | new_blocks = le16_to_cpu(el->l_tree_depth); |
1057 | 1111 | ||
1112 | eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; | ||
1113 | new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); | ||
1114 | root_end = ocfs2_sum_rightmost_rec(et->et_root_el); | ||
1115 | |||
1116 | /* | ||
1117 | * If there is a gap before the root end and the real end | ||
1118 | * of the righmost leaf block, we need to remove the gap | ||
1119 | * between new_cpos and root_end first so that the tree | ||
1120 | * is consistent after we add a new branch(it will start | ||
1121 | * from new_cpos). | ||
1122 | */ | ||
1123 | if (root_end > new_cpos) { | ||
1124 | mlog(0, "adjust the cluster end from %u to %u\n", | ||
1125 | root_end, new_cpos); | ||
1126 | status = ocfs2_adjust_rightmost_branch(handle, inode, et); | ||
1127 | if (status) { | ||
1128 | mlog_errno(status); | ||
1129 | goto bail; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1058 | /* allocate the number of new eb blocks we need */ | 1133 | /* allocate the number of new eb blocks we need */ |
1059 | new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), | 1134 | new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), |
1060 | GFP_KERNEL); | 1135 | GFP_KERNEL); |
@@ -1071,9 +1146,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, | |||
1071 | goto bail; | 1146 | goto bail; |
1072 | } | 1147 | } |
1073 | 1148 | ||
1074 | eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data; | ||
1075 | new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list); | ||
1076 | |||
1077 | /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be | 1149 | /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be |
1078 | * linked with the rest of the tree. | 1150 | * linked with the rest of the tree. |
1079 | * conversly, new_eb_bhs[0] is the new bottommost leaf. | 1151 | * conversly, new_eb_bhs[0] is the new bottommost leaf. |
diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c index 2a947c44e594..a1163b8b417c 100644 --- a/fs/ocfs2/blockcheck.c +++ b/fs/ocfs2/blockcheck.c | |||
@@ -22,6 +22,9 @@ | |||
22 | #include <linux/crc32.h> | 22 | #include <linux/crc32.h> |
23 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
24 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <linux/debugfs.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/fs.h> | ||
25 | #include <asm/byteorder.h> | 28 | #include <asm/byteorder.h> |
26 | 29 | ||
27 | #include <cluster/masklog.h> | 30 | #include <cluster/masklog.h> |
@@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int blocksize, | |||
222 | ocfs2_hamming_fix(data, blocksize * 8, 0, fix); | 225 | ocfs2_hamming_fix(data, blocksize * 8, 0, fix); |
223 | } | 226 | } |
224 | 227 | ||
228 | |||
229 | /* | ||
230 | * Debugfs handling. | ||
231 | */ | ||
232 | |||
233 | #ifdef CONFIG_DEBUG_FS | ||
234 | |||
235 | static int blockcheck_u64_get(void *data, u64 *val) | ||
236 | { | ||
237 | *val = *(u64 *)data; | ||
238 | return 0; | ||
239 | } | ||
240 | DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n"); | ||
241 | |||
242 | static struct dentry *blockcheck_debugfs_create(const char *name, | ||
243 | struct dentry *parent, | ||
244 | u64 *value) | ||
245 | { | ||
246 | return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value, | ||
247 | &blockcheck_fops); | ||
248 | } | ||
249 | |||
250 | static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats) | ||
251 | { | ||
252 | if (stats) { | ||
253 | debugfs_remove(stats->b_debug_check); | ||
254 | stats->b_debug_check = NULL; | ||
255 | debugfs_remove(stats->b_debug_failure); | ||
256 | stats->b_debug_failure = NULL; | ||
257 | debugfs_remove(stats->b_debug_recover); | ||
258 | stats->b_debug_recover = NULL; | ||
259 | debugfs_remove(stats->b_debug_dir); | ||
260 | stats->b_debug_dir = NULL; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats, | ||
265 | struct dentry *parent) | ||
266 | { | ||
267 | int rc = -EINVAL; | ||
268 | |||
269 | if (!stats) | ||
270 | goto out; | ||
271 | |||
272 | stats->b_debug_dir = debugfs_create_dir("blockcheck", parent); | ||
273 | if (!stats->b_debug_dir) | ||
274 | goto out; | ||
275 | |||
276 | stats->b_debug_check = | ||
277 | blockcheck_debugfs_create("blocks_checked", | ||
278 | stats->b_debug_dir, | ||
279 | &stats->b_check_count); | ||
280 | |||
281 | stats->b_debug_failure = | ||
282 | blockcheck_debugfs_create("checksums_failed", | ||
283 | stats->b_debug_dir, | ||
284 | &stats->b_failure_count); | ||
285 | |||
286 | stats->b_debug_recover = | ||
287 | blockcheck_debugfs_create("ecc_recoveries", | ||
288 | stats->b_debug_dir, | ||
289 | &stats->b_recover_count); | ||
290 | if (stats->b_debug_check && stats->b_debug_failure && | ||
291 | stats->b_debug_recover) | ||
292 | rc = 0; | ||
293 | |||
294 | out: | ||
295 | if (rc) | ||
296 | ocfs2_blockcheck_debug_remove(stats); | ||
297 | return rc; | ||
298 | } | ||
299 | #else | ||
300 | static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats, | ||
301 | struct dentry *parent) | ||
302 | { | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats) | ||
307 | { | ||
308 | } | ||
309 | #endif /* CONFIG_DEBUG_FS */ | ||
310 | |||
311 | /* Always-called wrappers for starting and stopping the debugfs files */ | ||
312 | int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats, | ||
313 | struct dentry *parent) | ||
314 | { | ||
315 | return ocfs2_blockcheck_debug_install(stats, parent); | ||
316 | } | ||
317 | |||
318 | void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats) | ||
319 | { | ||
320 | ocfs2_blockcheck_debug_remove(stats); | ||
321 | } | ||
322 | |||
323 | static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats) | ||
324 | { | ||
325 | u64 new_count; | ||
326 | |||
327 | if (!stats) | ||
328 | return; | ||
329 | |||
330 | spin_lock(&stats->b_lock); | ||
331 | stats->b_check_count++; | ||
332 | new_count = stats->b_check_count; | ||
333 | spin_unlock(&stats->b_lock); | ||
334 | |||
335 | if (!new_count) | ||
336 | mlog(ML_NOTICE, "Block check count has wrapped\n"); | ||
337 | } | ||
338 | |||
339 | static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats) | ||
340 | { | ||
341 | u64 new_count; | ||
342 | |||
343 | if (!stats) | ||
344 | return; | ||
345 | |||
346 | spin_lock(&stats->b_lock); | ||
347 | stats->b_failure_count++; | ||
348 | new_count = stats->b_failure_count; | ||
349 | spin_unlock(&stats->b_lock); | ||
350 | |||
351 | if (!new_count) | ||
352 | mlog(ML_NOTICE, "Checksum failure count has wrapped\n"); | ||
353 | } | ||
354 | |||
355 | static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats) | ||
356 | { | ||
357 | u64 new_count; | ||
358 | |||
359 | if (!stats) | ||
360 | return; | ||
361 | |||
362 | spin_lock(&stats->b_lock); | ||
363 | stats->b_recover_count++; | ||
364 | new_count = stats->b_recover_count; | ||
365 | spin_unlock(&stats->b_lock); | ||
366 | |||
367 | if (!new_count) | ||
368 | mlog(ML_NOTICE, "ECC recovery count has wrapped\n"); | ||
369 | } | ||
370 | |||
371 | |||
372 | |||
373 | /* | ||
374 | * These are the low-level APIs for using the ocfs2_block_check structure. | ||
375 | */ | ||
376 | |||
225 | /* | 377 | /* |
226 | * This function generates check information for a block. | 378 | * This function generates check information for a block. |
227 | * data is the block to be checked. bc is a pointer to the | 379 | * data is the block to be checked. bc is a pointer to the |
@@ -266,12 +418,15 @@ void ocfs2_block_check_compute(void *data, size_t blocksize, | |||
266 | * Again, the data passed in should be the on-disk endian. | 418 | * Again, the data passed in should be the on-disk endian. |
267 | */ | 419 | */ |
268 | int ocfs2_block_check_validate(void *data, size_t blocksize, | 420 | int ocfs2_block_check_validate(void *data, size_t blocksize, |
269 | struct ocfs2_block_check *bc) | 421 | struct ocfs2_block_check *bc, |
422 | struct ocfs2_blockcheck_stats *stats) | ||
270 | { | 423 | { |
271 | int rc = 0; | 424 | int rc = 0; |
272 | struct ocfs2_block_check check; | 425 | struct ocfs2_block_check check; |
273 | u32 crc, ecc; | 426 | u32 crc, ecc; |
274 | 427 | ||
428 | ocfs2_blockcheck_inc_check(stats); | ||
429 | |||
275 | check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); | 430 | check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); |
276 | check.bc_ecc = le16_to_cpu(bc->bc_ecc); | 431 | check.bc_ecc = le16_to_cpu(bc->bc_ecc); |
277 | 432 | ||
@@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, | |||
282 | if (crc == check.bc_crc32e) | 437 | if (crc == check.bc_crc32e) |
283 | goto out; | 438 | goto out; |
284 | 439 | ||
440 | ocfs2_blockcheck_inc_failure(stats); | ||
285 | mlog(ML_ERROR, | 441 | mlog(ML_ERROR, |
286 | "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", | 442 | "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", |
287 | (unsigned int)check.bc_crc32e, (unsigned int)crc); | 443 | (unsigned int)check.bc_crc32e, (unsigned int)crc); |
@@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t blocksize, | |||
292 | 448 | ||
293 | /* And check the crc32 again */ | 449 | /* And check the crc32 again */ |
294 | crc = crc32_le(~0, data, blocksize); | 450 | crc = crc32_le(~0, data, blocksize); |
295 | if (crc == check.bc_crc32e) | 451 | if (crc == check.bc_crc32e) { |
452 | ocfs2_blockcheck_inc_recover(stats); | ||
296 | goto out; | 453 | goto out; |
454 | } | ||
297 | 455 | ||
298 | mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", | 456 | mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", |
299 | (unsigned int)check.bc_crc32e, (unsigned int)crc); | 457 | (unsigned int)check.bc_crc32e, (unsigned int)crc); |
@@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, | |||
366 | * Again, the data passed in should be the on-disk endian. | 524 | * Again, the data passed in should be the on-disk endian. |
367 | */ | 525 | */ |
368 | int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, | 526 | int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, |
369 | struct ocfs2_block_check *bc) | 527 | struct ocfs2_block_check *bc, |
528 | struct ocfs2_blockcheck_stats *stats) | ||
370 | { | 529 | { |
371 | int i, rc = 0; | 530 | int i, rc = 0; |
372 | struct ocfs2_block_check check; | 531 | struct ocfs2_block_check check; |
@@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, | |||
377 | if (!nr) | 536 | if (!nr) |
378 | return 0; | 537 | return 0; |
379 | 538 | ||
539 | ocfs2_blockcheck_inc_check(stats); | ||
540 | |||
380 | check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); | 541 | check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); |
381 | check.bc_ecc = le16_to_cpu(bc->bc_ecc); | 542 | check.bc_ecc = le16_to_cpu(bc->bc_ecc); |
382 | 543 | ||
@@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, | |||
388 | if (crc == check.bc_crc32e) | 549 | if (crc == check.bc_crc32e) |
389 | goto out; | 550 | goto out; |
390 | 551 | ||
552 | ocfs2_blockcheck_inc_failure(stats); | ||
391 | mlog(ML_ERROR, | 553 | mlog(ML_ERROR, |
392 | "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", | 554 | "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", |
393 | (unsigned int)check.bc_crc32e, (unsigned int)crc); | 555 | (unsigned int)check.bc_crc32e, (unsigned int)crc); |
@@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, | |||
416 | /* And check the crc32 again */ | 578 | /* And check the crc32 again */ |
417 | for (i = 0, crc = ~0; i < nr; i++) | 579 | for (i = 0, crc = ~0; i < nr; i++) |
418 | crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); | 580 | crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); |
419 | if (crc == check.bc_crc32e) | 581 | if (crc == check.bc_crc32e) { |
582 | ocfs2_blockcheck_inc_recover(stats); | ||
420 | goto out; | 583 | goto out; |
584 | } | ||
421 | 585 | ||
422 | mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", | 586 | mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", |
423 | (unsigned int)check.bc_crc32e, (unsigned int)crc); | 587 | (unsigned int)check.bc_crc32e, (unsigned int)crc); |
@@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void *data, | |||
448 | struct ocfs2_block_check *bc) | 612 | struct ocfs2_block_check *bc) |
449 | { | 613 | { |
450 | int rc = 0; | 614 | int rc = 0; |
615 | struct ocfs2_super *osb = OCFS2_SB(sb); | ||
451 | 616 | ||
452 | if (ocfs2_meta_ecc(OCFS2_SB(sb))) | 617 | if (ocfs2_meta_ecc(osb)) |
453 | rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc); | 618 | rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc, |
619 | &osb->osb_ecc_stats); | ||
454 | 620 | ||
455 | return rc; | 621 | return rc; |
456 | } | 622 | } |
@@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb, | |||
468 | struct ocfs2_block_check *bc) | 634 | struct ocfs2_block_check *bc) |
469 | { | 635 | { |
470 | int rc = 0; | 636 | int rc = 0; |
637 | struct ocfs2_super *osb = OCFS2_SB(sb); | ||
471 | 638 | ||
472 | if (ocfs2_meta_ecc(OCFS2_SB(sb))) | 639 | if (ocfs2_meta_ecc(osb)) |
473 | rc = ocfs2_block_check_validate_bhs(bhs, nr, bc); | 640 | rc = ocfs2_block_check_validate_bhs(bhs, nr, bc, |
641 | &osb->osb_ecc_stats); | ||
474 | 642 | ||
475 | return rc; | 643 | return rc; |
476 | } | 644 | } |
diff --git a/fs/ocfs2/blockcheck.h b/fs/ocfs2/blockcheck.h index 70ec3feda32f..d4b69febf70a 100644 --- a/fs/ocfs2/blockcheck.h +++ b/fs/ocfs2/blockcheck.h | |||
@@ -21,6 +21,24 @@ | |||
21 | #define OCFS2_BLOCKCHECK_H | 21 | #define OCFS2_BLOCKCHECK_H |
22 | 22 | ||
23 | 23 | ||
24 | /* Count errors and error correction from blockcheck.c */ | ||
25 | struct ocfs2_blockcheck_stats { | ||
26 | spinlock_t b_lock; | ||
27 | u64 b_check_count; /* Number of blocks we've checked */ | ||
28 | u64 b_failure_count; /* Number of failed checksums */ | ||
29 | u64 b_recover_count; /* Number of blocks fixed by ecc */ | ||
30 | |||
31 | /* | ||
32 | * debugfs entries, used if this is passed to | ||
33 | * ocfs2_blockcheck_stats_debugfs_install() | ||
34 | */ | ||
35 | struct dentry *b_debug_dir; /* Parent of the debugfs files */ | ||
36 | struct dentry *b_debug_check; /* Exposes b_check_count */ | ||
37 | struct dentry *b_debug_failure; /* Exposes b_failure_count */ | ||
38 | struct dentry *b_debug_recover; /* Exposes b_recover_count */ | ||
39 | }; | ||
40 | |||
41 | |||
24 | /* High level block API */ | 42 | /* High level block API */ |
25 | void ocfs2_compute_meta_ecc(struct super_block *sb, void *data, | 43 | void ocfs2_compute_meta_ecc(struct super_block *sb, void *data, |
26 | struct ocfs2_block_check *bc); | 44 | struct ocfs2_block_check *bc); |
@@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb, | |||
37 | void ocfs2_block_check_compute(void *data, size_t blocksize, | 55 | void ocfs2_block_check_compute(void *data, size_t blocksize, |
38 | struct ocfs2_block_check *bc); | 56 | struct ocfs2_block_check *bc); |
39 | int ocfs2_block_check_validate(void *data, size_t blocksize, | 57 | int ocfs2_block_check_validate(void *data, size_t blocksize, |
40 | struct ocfs2_block_check *bc); | 58 | struct ocfs2_block_check *bc, |
59 | struct ocfs2_blockcheck_stats *stats); | ||
41 | void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, | 60 | void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, |
42 | struct ocfs2_block_check *bc); | 61 | struct ocfs2_block_check *bc); |
43 | int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, | 62 | int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, |
44 | struct ocfs2_block_check *bc); | 63 | struct ocfs2_block_check *bc, |
64 | struct ocfs2_blockcheck_stats *stats); | ||
65 | |||
66 | /* Debug Initialization */ | ||
67 | int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats, | ||
68 | struct dentry *parent); | ||
69 | void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats); | ||
45 | 70 | ||
46 | /* | 71 | /* |
47 | * Hamming code functions | 72 | * Hamming code functions |
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index 7e72a81bc2d4..696c32e50716 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h | |||
@@ -48,34 +48,33 @@ | |||
48 | * only emit the appropriage printk() when the caller passes in a constant | 48 | * only emit the appropriage printk() when the caller passes in a constant |
49 | * mask, as is almost always the case. | 49 | * mask, as is almost always the case. |
50 | * | 50 | * |
51 | * All this bitmask nonsense is hidden from the /proc interface so that Joel | 51 | * All this bitmask nonsense is managed from the files under |
52 | * doesn't have an aneurism. Reading the file gives a straight forward | 52 | * /sys/fs/o2cb/logmask/. Reading the files gives a straightforward |
53 | * indication of which bits are on or off: | 53 | * indication of which bits are allowed (allow) or denied (off/deny). |
54 | * ENTRY off | 54 | * ENTRY deny |
55 | * EXIT off | 55 | * EXIT deny |
56 | * TCP off | 56 | * TCP off |
57 | * MSG off | 57 | * MSG off |
58 | * SOCKET off | 58 | * SOCKET off |
59 | * ERROR off | 59 | * ERROR allow |
60 | * NOTICE on | 60 | * NOTICE allow |
61 | * | 61 | * |
62 | * Writing changes the state of a given bit and requires a strictly formatted | 62 | * Writing changes the state of a given bit and requires a strictly formatted |
63 | * single write() call: | 63 | * single write() call: |
64 | * | 64 | * |
65 | * write(fd, "ENTRY on", 8); | 65 | * write(fd, "allow", 5); |
66 | * | 66 | * |
67 | * would turn the entry bit on. "1" is also accepted in the place of "on", and | 67 | * Echoing allow/deny/off string into the logmask files can flip the bits |
68 | * "off" and "0" behave as expected. | 68 | * on or off as expected; here is the bash script for example: |
69 | * | 69 | * |
70 | * Some trivial shell can flip all the bits on or off: | 70 | * log_mask="/sys/fs/o2cb/log_mask" |
71 | * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do | ||
72 | * echo allow >"$log_mask"/"$node" | ||
73 | * done | ||
71 | * | 74 | * |
72 | * log_mask="/proc/fs/ocfs2_nodemanager/log_mask" | 75 | * The debugfs.ocfs2 tool can also flip the bits with the -l option: |
73 | * cat $log_mask | ( | 76 | * |
74 | * while read bit status; do | 77 | * debugfs.ocfs2 -l TCP allow |
75 | * # $1 is "on" or "off", say | ||
76 | * echo "$bit $1" > $log_mask | ||
77 | * done | ||
78 | * ) | ||
79 | */ | 78 | */ |
80 | 79 | ||
81 | /* for task_struct */ | 80 | /* for task_struct */ |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 9fbe849f6344..334f231a422c 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
@@ -974,7 +974,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn, | |||
974 | int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | 974 | int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, |
975 | size_t caller_veclen, u8 target_node, int *status) | 975 | size_t caller_veclen, u8 target_node, int *status) |
976 | { | 976 | { |
977 | int ret, error = 0; | 977 | int ret; |
978 | struct o2net_msg *msg = NULL; | 978 | struct o2net_msg *msg = NULL; |
979 | size_t veclen, caller_bytes = 0; | 979 | size_t veclen, caller_bytes = 0; |
980 | struct kvec *vec = NULL; | 980 | struct kvec *vec = NULL; |
@@ -1015,10 +1015,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, | |||
1015 | 1015 | ||
1016 | o2net_set_nst_sock_time(&nst); | 1016 | o2net_set_nst_sock_time(&nst); |
1017 | 1017 | ||
1018 | ret = wait_event_interruptible(nn->nn_sc_wq, | 1018 | wait_event(nn->nn_sc_wq, o2net_tx_can_proceed(nn, &sc, &ret)); |
1019 | o2net_tx_can_proceed(nn, &sc, &error)); | ||
1020 | if (!ret && error) | ||
1021 | ret = error; | ||
1022 | if (ret) | 1019 | if (ret) |
1023 | goto out; | 1020 | goto out; |
1024 | 1021 | ||
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index c5752305627c..b358f3bf896d 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -2900,6 +2900,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2900 | alloc = ocfs2_clusters_for_bytes(sb, bytes); | 2900 | alloc = ocfs2_clusters_for_bytes(sb, bytes); |
2901 | dx_alloc = 0; | 2901 | dx_alloc = 0; |
2902 | 2902 | ||
2903 | down_write(&oi->ip_alloc_sem); | ||
2904 | |||
2903 | if (ocfs2_supports_indexed_dirs(osb)) { | 2905 | if (ocfs2_supports_indexed_dirs(osb)) { |
2904 | credits += ocfs2_add_dir_index_credits(sb); | 2906 | credits += ocfs2_add_dir_index_credits(sb); |
2905 | 2907 | ||
@@ -2940,8 +2942,6 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2940 | goto out; | 2942 | goto out; |
2941 | } | 2943 | } |
2942 | 2944 | ||
2943 | down_write(&oi->ip_alloc_sem); | ||
2944 | |||
2945 | /* | 2945 | /* |
2946 | * Prepare for worst case allocation scenario of two separate | 2946 | * Prepare for worst case allocation scenario of two separate |
2947 | * extents in the unindexed tree. | 2947 | * extents in the unindexed tree. |
@@ -2953,7 +2953,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
2953 | if (IS_ERR(handle)) { | 2953 | if (IS_ERR(handle)) { |
2954 | ret = PTR_ERR(handle); | 2954 | ret = PTR_ERR(handle); |
2955 | mlog_errno(ret); | 2955 | mlog_errno(ret); |
2956 | goto out_sem; | 2956 | goto out; |
2957 | } | 2957 | } |
2958 | 2958 | ||
2959 | if (vfs_dq_alloc_space_nodirty(dir, | 2959 | if (vfs_dq_alloc_space_nodirty(dir, |
@@ -3172,10 +3172,8 @@ out_commit: | |||
3172 | 3172 | ||
3173 | ocfs2_commit_trans(osb, handle); | 3173 | ocfs2_commit_trans(osb, handle); |
3174 | 3174 | ||
3175 | out_sem: | ||
3176 | up_write(&oi->ip_alloc_sem); | ||
3177 | |||
3178 | out: | 3175 | out: |
3176 | up_write(&oi->ip_alloc_sem); | ||
3179 | if (data_ac) | 3177 | if (data_ac) |
3180 | ocfs2_free_alloc_context(data_ac); | 3178 | ocfs2_free_alloc_context(data_ac); |
3181 | if (meta_ac) | 3179 | if (meta_ac) |
@@ -3322,11 +3320,15 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb, | |||
3322 | brelse(new_bh); | 3320 | brelse(new_bh); |
3323 | new_bh = NULL; | 3321 | new_bh = NULL; |
3324 | 3322 | ||
3323 | down_write(&OCFS2_I(dir)->ip_alloc_sem); | ||
3324 | drop_alloc_sem = 1; | ||
3325 | dir_i_size = i_size_read(dir); | 3325 | dir_i_size = i_size_read(dir); |
3326 | credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; | 3326 | credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; |
3327 | goto do_extend; | 3327 | goto do_extend; |
3328 | } | 3328 | } |
3329 | 3329 | ||
3330 | down_write(&OCFS2_I(dir)->ip_alloc_sem); | ||
3331 | drop_alloc_sem = 1; | ||
3330 | dir_i_size = i_size_read(dir); | 3332 | dir_i_size = i_size_read(dir); |
3331 | mlog(0, "extending dir %llu (i_size = %lld)\n", | 3333 | mlog(0, "extending dir %llu (i_size = %lld)\n", |
3332 | (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size); | 3334 | (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size); |
@@ -3370,9 +3372,6 @@ do_extend: | |||
3370 | credits++; /* For attaching the new dirent block to the | 3372 | credits++; /* For attaching the new dirent block to the |
3371 | * dx_root */ | 3373 | * dx_root */ |
3372 | 3374 | ||
3373 | down_write(&OCFS2_I(dir)->ip_alloc_sem); | ||
3374 | drop_alloc_sem = 1; | ||
3375 | |||
3376 | handle = ocfs2_start_trans(osb, credits); | 3375 | handle = ocfs2_start_trans(osb, credits); |
3377 | if (IS_ERR(handle)) { | 3376 | if (IS_ERR(handle)) { |
3378 | status = PTR_ERR(handle); | 3377 | status = PTR_ERR(handle); |
@@ -3435,10 +3434,10 @@ bail_bh: | |||
3435 | *new_de_bh = new_bh; | 3434 | *new_de_bh = new_bh; |
3436 | get_bh(*new_de_bh); | 3435 | get_bh(*new_de_bh); |
3437 | bail: | 3436 | bail: |
3438 | if (drop_alloc_sem) | ||
3439 | up_write(&OCFS2_I(dir)->ip_alloc_sem); | ||
3440 | if (handle) | 3437 | if (handle) |
3441 | ocfs2_commit_trans(osb, handle); | 3438 | ocfs2_commit_trans(osb, handle); |
3439 | if (drop_alloc_sem) | ||
3440 | up_write(&OCFS2_I(dir)->ip_alloc_sem); | ||
3442 | 3441 | ||
3443 | if (data_ac) | 3442 | if (data_ac) |
3444 | ocfs2_free_alloc_context(data_ac); | 3443 | ocfs2_free_alloc_context(data_ac); |
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index e15fc7d50827..110bb57c46ab 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c | |||
@@ -92,6 +92,9 @@ struct ocfs2_unblock_ctl { | |||
92 | enum ocfs2_unblock_action unblock_action; | 92 | enum ocfs2_unblock_action unblock_action; |
93 | }; | 93 | }; |
94 | 94 | ||
95 | /* Lockdep class keys */ | ||
96 | struct lock_class_key lockdep_keys[OCFS2_NUM_LOCK_TYPES]; | ||
97 | |||
95 | static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, | 98 | static int ocfs2_check_meta_downconvert(struct ocfs2_lock_res *lockres, |
96 | int new_level); | 99 | int new_level); |
97 | static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres); | 100 | static void ocfs2_set_meta_lvb(struct ocfs2_lock_res *lockres); |
@@ -248,6 +251,10 @@ static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = { | |||
248 | .flags = 0, | 251 | .flags = 0, |
249 | }; | 252 | }; |
250 | 253 | ||
254 | static struct ocfs2_lock_res_ops ocfs2_orphan_scan_lops = { | ||
255 | .flags = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB, | ||
256 | }; | ||
257 | |||
251 | static struct ocfs2_lock_res_ops ocfs2_dentry_lops = { | 258 | static struct ocfs2_lock_res_ops ocfs2_dentry_lops = { |
252 | .get_osb = ocfs2_get_dentry_osb, | 259 | .get_osb = ocfs2_get_dentry_osb, |
253 | .post_unlock = ocfs2_dentry_post_unlock, | 260 | .post_unlock = ocfs2_dentry_post_unlock, |
@@ -313,9 +320,16 @@ static int ocfs2_lock_create(struct ocfs2_super *osb, | |||
313 | u32 dlm_flags); | 320 | u32 dlm_flags); |
314 | static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, | 321 | static inline int ocfs2_may_continue_on_blocked_lock(struct ocfs2_lock_res *lockres, |
315 | int wanted); | 322 | int wanted); |
316 | static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | 323 | static void __ocfs2_cluster_unlock(struct ocfs2_super *osb, |
317 | struct ocfs2_lock_res *lockres, | 324 | struct ocfs2_lock_res *lockres, |
318 | int level); | 325 | int level, unsigned long caller_ip); |
326 | static inline void ocfs2_cluster_unlock(struct ocfs2_super *osb, | ||
327 | struct ocfs2_lock_res *lockres, | ||
328 | int level) | ||
329 | { | ||
330 | __ocfs2_cluster_unlock(osb, lockres, level, _RET_IP_); | ||
331 | } | ||
332 | |||
319 | static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres); | 333 | static inline void ocfs2_generic_handle_downconvert_action(struct ocfs2_lock_res *lockres); |
320 | static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres); | 334 | static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lockres); |
321 | static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres); | 335 | static inline void ocfs2_generic_handle_attach_action(struct ocfs2_lock_res *lockres); |
@@ -485,6 +499,13 @@ static void ocfs2_lock_res_init_common(struct ocfs2_super *osb, | |||
485 | ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); | 499 | ocfs2_add_lockres_tracking(res, osb->osb_dlm_debug); |
486 | 500 | ||
487 | ocfs2_init_lock_stats(res); | 501 | ocfs2_init_lock_stats(res); |
502 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
503 | if (type != OCFS2_LOCK_TYPE_OPEN) | ||
504 | lockdep_init_map(&res->l_lockdep_map, ocfs2_lock_type_strings[type], | ||
505 | &lockdep_keys[type], 0); | ||
506 | else | ||
507 | res->l_lockdep_map.key = NULL; | ||
508 | #endif | ||
488 | } | 509 | } |
489 | 510 | ||
490 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res) | 511 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res) |
@@ -637,6 +658,15 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res, | |||
637 | &ocfs2_nfs_sync_lops, osb); | 658 | &ocfs2_nfs_sync_lops, osb); |
638 | } | 659 | } |
639 | 660 | ||
661 | static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res, | ||
662 | struct ocfs2_super *osb) | ||
663 | { | ||
664 | ocfs2_lock_res_init_once(res); | ||
665 | ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name); | ||
666 | ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN, | ||
667 | &ocfs2_orphan_scan_lops, osb); | ||
668 | } | ||
669 | |||
640 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, | 670 | void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres, |
641 | struct ocfs2_file_private *fp) | 671 | struct ocfs2_file_private *fp) |
642 | { | 672 | { |
@@ -1239,11 +1269,13 @@ static int ocfs2_wait_for_mask_interruptible(struct ocfs2_mask_waiter *mw, | |||
1239 | return ret; | 1269 | return ret; |
1240 | } | 1270 | } |
1241 | 1271 | ||
1242 | static int ocfs2_cluster_lock(struct ocfs2_super *osb, | 1272 | static int __ocfs2_cluster_lock(struct ocfs2_super *osb, |
1243 | struct ocfs2_lock_res *lockres, | 1273 | struct ocfs2_lock_res *lockres, |
1244 | int level, | 1274 | int level, |
1245 | u32 lkm_flags, | 1275 | u32 lkm_flags, |
1246 | int arg_flags) | 1276 | int arg_flags, |
1277 | int l_subclass, | ||
1278 | unsigned long caller_ip) | ||
1247 | { | 1279 | { |
1248 | struct ocfs2_mask_waiter mw; | 1280 | struct ocfs2_mask_waiter mw; |
1249 | int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); | 1281 | int wait, catch_signals = !(osb->s_mount_opt & OCFS2_MOUNT_NOINTR); |
@@ -1386,13 +1418,37 @@ out: | |||
1386 | } | 1418 | } |
1387 | ocfs2_update_lock_stats(lockres, level, &mw, ret); | 1419 | ocfs2_update_lock_stats(lockres, level, &mw, ret); |
1388 | 1420 | ||
1421 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
1422 | if (!ret && lockres->l_lockdep_map.key != NULL) { | ||
1423 | if (level == DLM_LOCK_PR) | ||
1424 | rwsem_acquire_read(&lockres->l_lockdep_map, l_subclass, | ||
1425 | !!(arg_flags & OCFS2_META_LOCK_NOQUEUE), | ||
1426 | caller_ip); | ||
1427 | else | ||
1428 | rwsem_acquire(&lockres->l_lockdep_map, l_subclass, | ||
1429 | !!(arg_flags & OCFS2_META_LOCK_NOQUEUE), | ||
1430 | caller_ip); | ||
1431 | } | ||
1432 | #endif | ||
1389 | mlog_exit(ret); | 1433 | mlog_exit(ret); |
1390 | return ret; | 1434 | return ret; |
1391 | } | 1435 | } |
1392 | 1436 | ||
1393 | static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | 1437 | static inline int ocfs2_cluster_lock(struct ocfs2_super *osb, |
1394 | struct ocfs2_lock_res *lockres, | 1438 | struct ocfs2_lock_res *lockres, |
1395 | int level) | 1439 | int level, |
1440 | u32 lkm_flags, | ||
1441 | int arg_flags) | ||
1442 | { | ||
1443 | return __ocfs2_cluster_lock(osb, lockres, level, lkm_flags, arg_flags, | ||
1444 | 0, _RET_IP_); | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | static void __ocfs2_cluster_unlock(struct ocfs2_super *osb, | ||
1449 | struct ocfs2_lock_res *lockres, | ||
1450 | int level, | ||
1451 | unsigned long caller_ip) | ||
1396 | { | 1452 | { |
1397 | unsigned long flags; | 1453 | unsigned long flags; |
1398 | 1454 | ||
@@ -1401,6 +1457,10 @@ static void ocfs2_cluster_unlock(struct ocfs2_super *osb, | |||
1401 | ocfs2_dec_holders(lockres, level); | 1457 | ocfs2_dec_holders(lockres, level); |
1402 | ocfs2_downconvert_on_unlock(osb, lockres); | 1458 | ocfs2_downconvert_on_unlock(osb, lockres); |
1403 | spin_unlock_irqrestore(&lockres->l_lock, flags); | 1459 | spin_unlock_irqrestore(&lockres->l_lock, flags); |
1460 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
1461 | if (lockres->l_lockdep_map.key != NULL) | ||
1462 | rwsem_release(&lockres->l_lockdep_map, 1, caller_ip); | ||
1463 | #endif | ||
1404 | mlog_exit_void(); | 1464 | mlog_exit_void(); |
1405 | } | 1465 | } |
1406 | 1466 | ||
@@ -1972,7 +2032,8 @@ static inline int ocfs2_meta_lvb_is_trustable(struct inode *inode, | |||
1972 | { | 2032 | { |
1973 | struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | 2033 | struct ocfs2_meta_lvb *lvb = ocfs2_dlm_lvb(&lockres->l_lksb); |
1974 | 2034 | ||
1975 | if (lvb->lvb_version == OCFS2_LVB_VERSION | 2035 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) |
2036 | && lvb->lvb_version == OCFS2_LVB_VERSION | ||
1976 | && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation) | 2037 | && be32_to_cpu(lvb->lvb_igeneration) == inode->i_generation) |
1977 | return 1; | 2038 | return 1; |
1978 | return 0; | 2039 | return 0; |
@@ -2145,10 +2206,11 @@ static int ocfs2_assign_bh(struct inode *inode, | |||
2145 | * returns < 0 error if the callback will never be called, otherwise | 2206 | * returns < 0 error if the callback will never be called, otherwise |
2146 | * the result of the lock will be communicated via the callback. | 2207 | * the result of the lock will be communicated via the callback. |
2147 | */ | 2208 | */ |
2148 | int ocfs2_inode_lock_full(struct inode *inode, | 2209 | int ocfs2_inode_lock_full_nested(struct inode *inode, |
2149 | struct buffer_head **ret_bh, | 2210 | struct buffer_head **ret_bh, |
2150 | int ex, | 2211 | int ex, |
2151 | int arg_flags) | 2212 | int arg_flags, |
2213 | int subclass) | ||
2152 | { | 2214 | { |
2153 | int status, level, acquired; | 2215 | int status, level, acquired; |
2154 | u32 dlm_flags; | 2216 | u32 dlm_flags; |
@@ -2186,7 +2248,8 @@ int ocfs2_inode_lock_full(struct inode *inode, | |||
2186 | if (arg_flags & OCFS2_META_LOCK_NOQUEUE) | 2248 | if (arg_flags & OCFS2_META_LOCK_NOQUEUE) |
2187 | dlm_flags |= DLM_LKF_NOQUEUE; | 2249 | dlm_flags |= DLM_LKF_NOQUEUE; |
2188 | 2250 | ||
2189 | status = ocfs2_cluster_lock(osb, lockres, level, dlm_flags, arg_flags); | 2251 | status = __ocfs2_cluster_lock(osb, lockres, level, dlm_flags, |
2252 | arg_flags, subclass, _RET_IP_); | ||
2190 | if (status < 0) { | 2253 | if (status < 0) { |
2191 | if (status != -EAGAIN && status != -EIOCBRETRY) | 2254 | if (status != -EAGAIN && status != -EIOCBRETRY) |
2192 | mlog_errno(status); | 2255 | mlog_errno(status); |
@@ -2352,6 +2415,47 @@ void ocfs2_inode_unlock(struct inode *inode, | |||
2352 | mlog_exit_void(); | 2415 | mlog_exit_void(); |
2353 | } | 2416 | } |
2354 | 2417 | ||
2418 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno) | ||
2419 | { | ||
2420 | struct ocfs2_lock_res *lockres; | ||
2421 | struct ocfs2_orphan_scan_lvb *lvb; | ||
2422 | int status = 0; | ||
2423 | |||
2424 | if (ocfs2_is_hard_readonly(osb)) | ||
2425 | return -EROFS; | ||
2426 | |||
2427 | if (ocfs2_mount_local(osb)) | ||
2428 | return 0; | ||
2429 | |||
2430 | lockres = &osb->osb_orphan_scan.os_lockres; | ||
2431 | status = ocfs2_cluster_lock(osb, lockres, DLM_LOCK_EX, 0, 0); | ||
2432 | if (status < 0) | ||
2433 | return status; | ||
2434 | |||
2435 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | ||
2436 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) && | ||
2437 | lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION) | ||
2438 | *seqno = be32_to_cpu(lvb->lvb_os_seqno); | ||
2439 | else | ||
2440 | *seqno = osb->osb_orphan_scan.os_seqno + 1; | ||
2441 | |||
2442 | return status; | ||
2443 | } | ||
2444 | |||
2445 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno) | ||
2446 | { | ||
2447 | struct ocfs2_lock_res *lockres; | ||
2448 | struct ocfs2_orphan_scan_lvb *lvb; | ||
2449 | |||
2450 | if (!ocfs2_is_hard_readonly(osb) && !ocfs2_mount_local(osb)) { | ||
2451 | lockres = &osb->osb_orphan_scan.os_lockres; | ||
2452 | lvb = ocfs2_dlm_lvb(&lockres->l_lksb); | ||
2453 | lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION; | ||
2454 | lvb->lvb_os_seqno = cpu_to_be32(seqno); | ||
2455 | ocfs2_cluster_unlock(osb, lockres, DLM_LOCK_EX); | ||
2456 | } | ||
2457 | } | ||
2458 | |||
2355 | int ocfs2_super_lock(struct ocfs2_super *osb, | 2459 | int ocfs2_super_lock(struct ocfs2_super *osb, |
2356 | int ex) | 2460 | int ex) |
2357 | { | 2461 | { |
@@ -2842,6 +2946,7 @@ local: | |||
2842 | ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb); | 2946 | ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb); |
2843 | ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb); | 2947 | ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb); |
2844 | ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb); | 2948 | ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb); |
2949 | ocfs2_orphan_scan_lock_res_init(&osb->osb_orphan_scan.os_lockres, osb); | ||
2845 | 2950 | ||
2846 | osb->cconn = conn; | 2951 | osb->cconn = conn; |
2847 | 2952 | ||
@@ -2878,6 +2983,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb, | |||
2878 | ocfs2_lock_res_free(&osb->osb_super_lockres); | 2983 | ocfs2_lock_res_free(&osb->osb_super_lockres); |
2879 | ocfs2_lock_res_free(&osb->osb_rename_lockres); | 2984 | ocfs2_lock_res_free(&osb->osb_rename_lockres); |
2880 | ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres); | 2985 | ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres); |
2986 | ocfs2_lock_res_free(&osb->osb_orphan_scan.os_lockres); | ||
2881 | 2987 | ||
2882 | ocfs2_cluster_disconnect(osb->cconn, hangup_pending); | 2988 | ocfs2_cluster_disconnect(osb->cconn, hangup_pending); |
2883 | osb->cconn = NULL; | 2989 | osb->cconn = NULL; |
@@ -3061,6 +3167,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb) | |||
3061 | ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres); | 3167 | ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres); |
3062 | ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres); | 3168 | ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres); |
3063 | ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres); | 3169 | ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres); |
3170 | ocfs2_simple_drop_lockres(osb, &osb->osb_orphan_scan.os_lockres); | ||
3064 | } | 3171 | } |
3065 | 3172 | ||
3066 | int ocfs2_drop_inode_locks(struct inode *inode) | 3173 | int ocfs2_drop_inode_locks(struct inode *inode) |
@@ -3576,7 +3683,8 @@ static int ocfs2_refresh_qinfo(struct ocfs2_mem_dqinfo *oinfo) | |||
3576 | struct ocfs2_global_disk_dqinfo *gdinfo; | 3683 | struct ocfs2_global_disk_dqinfo *gdinfo; |
3577 | int status = 0; | 3684 | int status = 0; |
3578 | 3685 | ||
3579 | if (lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) { | 3686 | if (ocfs2_dlm_lvb_valid(&lockres->l_lksb) && |
3687 | lvb->lvb_version == OCFS2_QINFO_LVB_VERSION) { | ||
3580 | info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); | 3688 | info->dqi_bgrace = be32_to_cpu(lvb->lvb_bgrace); |
3581 | info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); | 3689 | info->dqi_igrace = be32_to_cpu(lvb->lvb_igrace); |
3582 | oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); | 3690 | oinfo->dqi_syncms = be32_to_cpu(lvb->lvb_syncms); |
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index e1fd5721cd7f..7553836931de 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h | |||
@@ -62,6 +62,14 @@ struct ocfs2_qinfo_lvb { | |||
62 | __be32 lvb_free_entry; | 62 | __be32 lvb_free_entry; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | #define OCFS2_ORPHAN_LVB_VERSION 1 | ||
66 | |||
67 | struct ocfs2_orphan_scan_lvb { | ||
68 | __u8 lvb_version; | ||
69 | __u8 lvb_reserved[3]; | ||
70 | __be32 lvb_os_seqno; | ||
71 | }; | ||
72 | |||
65 | /* ocfs2_inode_lock_full() 'arg_flags' flags */ | 73 | /* ocfs2_inode_lock_full() 'arg_flags' flags */ |
66 | /* don't wait on recovery. */ | 74 | /* don't wait on recovery. */ |
67 | #define OCFS2_META_LOCK_RECOVERY (0x01) | 75 | #define OCFS2_META_LOCK_RECOVERY (0x01) |
@@ -70,6 +78,14 @@ struct ocfs2_qinfo_lvb { | |||
70 | /* don't block waiting for the downconvert thread, instead return -EAGAIN */ | 78 | /* don't block waiting for the downconvert thread, instead return -EAGAIN */ |
71 | #define OCFS2_LOCK_NONBLOCK (0x04) | 79 | #define OCFS2_LOCK_NONBLOCK (0x04) |
72 | 80 | ||
81 | /* Locking subclasses of inode cluster lock */ | ||
82 | enum { | ||
83 | OI_LS_NORMAL = 0, | ||
84 | OI_LS_PARENT, | ||
85 | OI_LS_RENAME1, | ||
86 | OI_LS_RENAME2, | ||
87 | }; | ||
88 | |||
73 | int ocfs2_dlm_init(struct ocfs2_super *osb); | 89 | int ocfs2_dlm_init(struct ocfs2_super *osb); |
74 | void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending); | 90 | void ocfs2_dlm_shutdown(struct ocfs2_super *osb, int hangup_pending); |
75 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res); | 91 | void ocfs2_lock_res_init_once(struct ocfs2_lock_res *res); |
@@ -96,23 +112,32 @@ void ocfs2_open_unlock(struct inode *inode); | |||
96 | int ocfs2_inode_lock_atime(struct inode *inode, | 112 | int ocfs2_inode_lock_atime(struct inode *inode, |
97 | struct vfsmount *vfsmnt, | 113 | struct vfsmount *vfsmnt, |
98 | int *level); | 114 | int *level); |
99 | int ocfs2_inode_lock_full(struct inode *inode, | 115 | int ocfs2_inode_lock_full_nested(struct inode *inode, |
100 | struct buffer_head **ret_bh, | 116 | struct buffer_head **ret_bh, |
101 | int ex, | 117 | int ex, |
102 | int arg_flags); | 118 | int arg_flags, |
119 | int subclass); | ||
103 | int ocfs2_inode_lock_with_page(struct inode *inode, | 120 | int ocfs2_inode_lock_with_page(struct inode *inode, |
104 | struct buffer_head **ret_bh, | 121 | struct buffer_head **ret_bh, |
105 | int ex, | 122 | int ex, |
106 | struct page *page); | 123 | struct page *page); |
124 | /* Variants without special locking class or flags */ | ||
125 | #define ocfs2_inode_lock_full(i, r, e, f)\ | ||
126 | ocfs2_inode_lock_full_nested(i, r, e, f, OI_LS_NORMAL) | ||
127 | #define ocfs2_inode_lock_nested(i, b, e, s)\ | ||
128 | ocfs2_inode_lock_full_nested(i, b, e, 0, s) | ||
107 | /* 99% of the time we don't want to supply any additional flags -- | 129 | /* 99% of the time we don't want to supply any additional flags -- |
108 | * those are for very specific cases only. */ | 130 | * those are for very specific cases only. */ |
109 | #define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full(i, b, e, 0) | 131 | #define ocfs2_inode_lock(i, b, e) ocfs2_inode_lock_full_nested(i, b, e, 0, OI_LS_NORMAL) |
110 | void ocfs2_inode_unlock(struct inode *inode, | 132 | void ocfs2_inode_unlock(struct inode *inode, |
111 | int ex); | 133 | int ex); |
112 | int ocfs2_super_lock(struct ocfs2_super *osb, | 134 | int ocfs2_super_lock(struct ocfs2_super *osb, |
113 | int ex); | 135 | int ex); |
114 | void ocfs2_super_unlock(struct ocfs2_super *osb, | 136 | void ocfs2_super_unlock(struct ocfs2_super *osb, |
115 | int ex); | 137 | int ex); |
138 | int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno); | ||
139 | void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno); | ||
140 | |||
116 | int ocfs2_rename_lock(struct ocfs2_super *osb); | 141 | int ocfs2_rename_lock(struct ocfs2_super *osb); |
117 | void ocfs2_rename_unlock(struct ocfs2_super *osb); | 142 | void ocfs2_rename_unlock(struct ocfs2_super *osb); |
118 | int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex); | 143 | int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex); |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index c2a87c885b73..62442e413a00 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -187,6 +187,9 @@ static int ocfs2_sync_file(struct file *file, | |||
187 | if (err) | 187 | if (err) |
188 | goto bail; | 188 | goto bail; |
189 | 189 | ||
190 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
191 | goto bail; | ||
192 | |||
190 | journal = osb->journal->j_journal; | 193 | journal = osb->journal->j_journal; |
191 | err = jbd2_journal_force_commit(journal); | 194 | err = jbd2_journal_force_commit(journal); |
192 | 195 | ||
@@ -894,9 +897,9 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
894 | struct ocfs2_super *osb = OCFS2_SB(sb); | 897 | struct ocfs2_super *osb = OCFS2_SB(sb); |
895 | struct buffer_head *bh = NULL; | 898 | struct buffer_head *bh = NULL; |
896 | handle_t *handle = NULL; | 899 | handle_t *handle = NULL; |
897 | int locked[MAXQUOTAS] = {0, 0}; | 900 | int qtype; |
898 | int credits, qtype; | 901 | struct dquot *transfer_from[MAXQUOTAS] = { }; |
899 | struct ocfs2_mem_dqinfo *oinfo; | 902 | struct dquot *transfer_to[MAXQUOTAS] = { }; |
900 | 903 | ||
901 | mlog_entry("(0x%p, '%.*s')\n", dentry, | 904 | mlog_entry("(0x%p, '%.*s')\n", dentry, |
902 | dentry->d_name.len, dentry->d_name.name); | 905 | dentry->d_name.len, dentry->d_name.name); |
@@ -969,30 +972,37 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
969 | 972 | ||
970 | if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | 973 | if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || |
971 | (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | 974 | (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { |
972 | credits = OCFS2_INODE_UPDATE_CREDITS; | 975 | /* |
976 | * Gather pointers to quota structures so that allocation / | ||
977 | * freeing of quota structures happens here and not inside | ||
978 | * vfs_dq_transfer() where we have problems with lock ordering | ||
979 | */ | ||
973 | if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid | 980 | if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid |
974 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, | 981 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, |
975 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | 982 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { |
976 | oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv; | 983 | transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, |
977 | status = ocfs2_lock_global_qf(oinfo, 1); | 984 | USRQUOTA); |
978 | if (status < 0) | 985 | transfer_from[USRQUOTA] = dqget(sb, inode->i_uid, |
986 | USRQUOTA); | ||
987 | if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) { | ||
988 | status = -ESRCH; | ||
979 | goto bail_unlock; | 989 | goto bail_unlock; |
980 | credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) + | 990 | } |
981 | ocfs2_calc_qdel_credits(sb, USRQUOTA); | ||
982 | locked[USRQUOTA] = 1; | ||
983 | } | 991 | } |
984 | if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid | 992 | if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid |
985 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, | 993 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, |
986 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | 994 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { |
987 | oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv; | 995 | transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, |
988 | status = ocfs2_lock_global_qf(oinfo, 1); | 996 | GRPQUOTA); |
989 | if (status < 0) | 997 | transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid, |
998 | GRPQUOTA); | ||
999 | if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) { | ||
1000 | status = -ESRCH; | ||
990 | goto bail_unlock; | 1001 | goto bail_unlock; |
991 | credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) + | 1002 | } |
992 | ocfs2_calc_qdel_credits(sb, GRPQUOTA); | ||
993 | locked[GRPQUOTA] = 1; | ||
994 | } | 1003 | } |
995 | handle = ocfs2_start_trans(osb, credits); | 1004 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS + |
1005 | 2 * ocfs2_quota_trans_credits(sb)); | ||
996 | if (IS_ERR(handle)) { | 1006 | if (IS_ERR(handle)) { |
997 | status = PTR_ERR(handle); | 1007 | status = PTR_ERR(handle); |
998 | mlog_errno(status); | 1008 | mlog_errno(status); |
@@ -1030,12 +1040,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1030 | bail_commit: | 1040 | bail_commit: |
1031 | ocfs2_commit_trans(osb, handle); | 1041 | ocfs2_commit_trans(osb, handle); |
1032 | bail_unlock: | 1042 | bail_unlock: |
1033 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | ||
1034 | if (!locked[qtype]) | ||
1035 | continue; | ||
1036 | oinfo = sb_dqinfo(sb, qtype)->dqi_priv; | ||
1037 | ocfs2_unlock_global_qf(oinfo, 1); | ||
1038 | } | ||
1039 | ocfs2_inode_unlock(inode, 1); | 1043 | ocfs2_inode_unlock(inode, 1); |
1040 | bail_unlock_rw: | 1044 | bail_unlock_rw: |
1041 | if (size_change) | 1045 | if (size_change) |
@@ -1043,6 +1047,12 @@ bail_unlock_rw: | |||
1043 | bail: | 1047 | bail: |
1044 | brelse(bh); | 1048 | brelse(bh); |
1045 | 1049 | ||
1050 | /* Release quota pointers in case we acquired them */ | ||
1051 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | ||
1052 | dqput(transfer_to[qtype]); | ||
1053 | dqput(transfer_from[qtype]); | ||
1054 | } | ||
1055 | |||
1046 | if (!status && attr->ia_valid & ATTR_MODE) { | 1056 | if (!status && attr->ia_valid & ATTR_MODE) { |
1047 | status = ocfs2_acl_chmod(inode); | 1057 | status = ocfs2_acl_chmod(inode); |
1048 | if (status < 0) | 1058 | if (status < 0) |
@@ -2016,7 +2026,7 @@ static ssize_t ocfs2_file_splice_read(struct file *in, | |||
2016 | size_t len, | 2026 | size_t len, |
2017 | unsigned int flags) | 2027 | unsigned int flags) |
2018 | { | 2028 | { |
2019 | int ret = 0; | 2029 | int ret = 0, lock_level = 0; |
2020 | struct inode *inode = in->f_path.dentry->d_inode; | 2030 | struct inode *inode = in->f_path.dentry->d_inode; |
2021 | 2031 | ||
2022 | mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, | 2032 | mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, |
@@ -2027,12 +2037,12 @@ static ssize_t ocfs2_file_splice_read(struct file *in, | |||
2027 | /* | 2037 | /* |
2028 | * See the comment in ocfs2_file_aio_read() | 2038 | * See the comment in ocfs2_file_aio_read() |
2029 | */ | 2039 | */ |
2030 | ret = ocfs2_inode_lock(inode, NULL, 0); | 2040 | ret = ocfs2_inode_lock_atime(inode, in->f_vfsmnt, &lock_level); |
2031 | if (ret < 0) { | 2041 | if (ret < 0) { |
2032 | mlog_errno(ret); | 2042 | mlog_errno(ret); |
2033 | goto bail; | 2043 | goto bail; |
2034 | } | 2044 | } |
2035 | ocfs2_inode_unlock(inode, 0); | 2045 | ocfs2_inode_unlock(inode, lock_level); |
2036 | 2046 | ||
2037 | ret = generic_file_splice_read(in, ppos, pipe, len, flags); | 2047 | ret = generic_file_splice_read(in, ppos, pipe, len, flags); |
2038 | 2048 | ||
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 10e1fa87396a..4dc8890ba316 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -215,6 +215,8 @@ bail: | |||
215 | static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) | 215 | static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) |
216 | { | 216 | { |
217 | struct ocfs2_find_inode_args *args = opaque; | 217 | struct ocfs2_find_inode_args *args = opaque; |
218 | static struct lock_class_key ocfs2_quota_ip_alloc_sem_key, | ||
219 | ocfs2_file_ip_alloc_sem_key; | ||
218 | 220 | ||
219 | mlog_entry("inode = %p, opaque = %p\n", inode, opaque); | 221 | mlog_entry("inode = %p, opaque = %p\n", inode, opaque); |
220 | 222 | ||
@@ -223,6 +225,15 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque) | |||
223 | if (args->fi_sysfile_type != 0) | 225 | if (args->fi_sysfile_type != 0) |
224 | lockdep_set_class(&inode->i_mutex, | 226 | lockdep_set_class(&inode->i_mutex, |
225 | &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); | 227 | &ocfs2_sysfile_lock_key[args->fi_sysfile_type]); |
228 | if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE || | ||
229 | args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE || | ||
230 | args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE || | ||
231 | args->fi_sysfile_type == LOCAL_GROUP_QUOTA_SYSTEM_INODE) | ||
232 | lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, | ||
233 | &ocfs2_quota_ip_alloc_sem_key); | ||
234 | else | ||
235 | lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem, | ||
236 | &ocfs2_file_ip_alloc_sem_key); | ||
226 | 237 | ||
227 | mlog_exit(0); | 238 | mlog_exit(0); |
228 | return 0; | 239 | return 0; |
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 9fcd36dcc9a0..467b413bec21 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c | |||
@@ -7,7 +7,6 @@ | |||
7 | 7 | ||
8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
9 | #include <linux/mount.h> | 9 | #include <linux/mount.h> |
10 | #include <linux/smp_lock.h> | ||
11 | 10 | ||
12 | #define MLOG_MASK_PREFIX ML_INODE | 11 | #define MLOG_MASK_PREFIX ML_INODE |
13 | #include <cluster/masklog.h> | 12 | #include <cluster/masklog.h> |
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index a20a0f1e37fd..f033760ecbea 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | #include <linux/highmem.h> | 29 | #include <linux/highmem.h> |
30 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
31 | #include <linux/time.h> | ||
32 | #include <linux/random.h> | ||
31 | 33 | ||
32 | #define MLOG_MASK_PREFIX ML_JOURNAL | 34 | #define MLOG_MASK_PREFIX ML_JOURNAL |
33 | #include <cluster/masklog.h> | 35 | #include <cluster/masklog.h> |
@@ -52,6 +54,8 @@ | |||
52 | 54 | ||
53 | DEFINE_SPINLOCK(trans_inc_lock); | 55 | DEFINE_SPINLOCK(trans_inc_lock); |
54 | 56 | ||
57 | #define ORPHAN_SCAN_SCHEDULE_TIMEOUT 300000 | ||
58 | |||
55 | static int ocfs2_force_read_journal(struct inode *inode); | 59 | static int ocfs2_force_read_journal(struct inode *inode); |
56 | static int ocfs2_recover_node(struct ocfs2_super *osb, | 60 | static int ocfs2_recover_node(struct ocfs2_super *osb, |
57 | int node_num, int slot_num); | 61 | int node_num, int slot_num); |
@@ -1841,6 +1845,128 @@ bail: | |||
1841 | return status; | 1845 | return status; |
1842 | } | 1846 | } |
1843 | 1847 | ||
1848 | /* | ||
1849 | * Scan timer should get fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT. Add some | ||
1850 | * randomness to the timeout to minimize multple nodes firing the timer at the | ||
1851 | * same time. | ||
1852 | */ | ||
1853 | static inline unsigned long ocfs2_orphan_scan_timeout(void) | ||
1854 | { | ||
1855 | unsigned long time; | ||
1856 | |||
1857 | get_random_bytes(&time, sizeof(time)); | ||
1858 | time = ORPHAN_SCAN_SCHEDULE_TIMEOUT + (time % 5000); | ||
1859 | return msecs_to_jiffies(time); | ||
1860 | } | ||
1861 | |||
1862 | /* | ||
1863 | * ocfs2_queue_orphan_scan calls ocfs2_queue_recovery_completion for | ||
1864 | * every slot, queuing a recovery of the slot on the ocfs2_wq thread. This | ||
1865 | * is done to catch any orphans that are left over in orphan directories. | ||
1866 | * | ||
1867 | * ocfs2_queue_orphan_scan gets called every ORPHAN_SCAN_SCHEDULE_TIMEOUT | ||
1868 | * seconds. It gets an EX lock on os_lockres and checks sequence number | ||
1869 | * stored in LVB. If the sequence number has changed, it means some other | ||
1870 | * node has done the scan. This node skips the scan and tracks the | ||
1871 | * sequence number. If the sequence number didn't change, it means a scan | ||
1872 | * hasn't happened. The node queues a scan and increments the | ||
1873 | * sequence number in the LVB. | ||
1874 | */ | ||
1875 | void ocfs2_queue_orphan_scan(struct ocfs2_super *osb) | ||
1876 | { | ||
1877 | struct ocfs2_orphan_scan *os; | ||
1878 | int status, i; | ||
1879 | u32 seqno = 0; | ||
1880 | |||
1881 | os = &osb->osb_orphan_scan; | ||
1882 | |||
1883 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
1884 | goto out; | ||
1885 | |||
1886 | status = ocfs2_orphan_scan_lock(osb, &seqno); | ||
1887 | if (status < 0) { | ||
1888 | if (status != -EAGAIN) | ||
1889 | mlog_errno(status); | ||
1890 | goto out; | ||
1891 | } | ||
1892 | |||
1893 | /* Do no queue the tasks if the volume is being umounted */ | ||
1894 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
1895 | goto unlock; | ||
1896 | |||
1897 | if (os->os_seqno != seqno) { | ||
1898 | os->os_seqno = seqno; | ||
1899 | goto unlock; | ||
1900 | } | ||
1901 | |||
1902 | for (i = 0; i < osb->max_slots; i++) | ||
1903 | ocfs2_queue_recovery_completion(osb->journal, i, NULL, NULL, | ||
1904 | NULL); | ||
1905 | /* | ||
1906 | * We queued a recovery on orphan slots, increment the sequence | ||
1907 | * number and update LVB so other node will skip the scan for a while | ||
1908 | */ | ||
1909 | seqno++; | ||
1910 | os->os_count++; | ||
1911 | os->os_scantime = CURRENT_TIME; | ||
1912 | unlock: | ||
1913 | ocfs2_orphan_scan_unlock(osb, seqno); | ||
1914 | out: | ||
1915 | return; | ||
1916 | } | ||
1917 | |||
1918 | /* Worker task that gets fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT millsec */ | ||
1919 | void ocfs2_orphan_scan_work(struct work_struct *work) | ||
1920 | { | ||
1921 | struct ocfs2_orphan_scan *os; | ||
1922 | struct ocfs2_super *osb; | ||
1923 | |||
1924 | os = container_of(work, struct ocfs2_orphan_scan, | ||
1925 | os_orphan_scan_work.work); | ||
1926 | osb = os->os_osb; | ||
1927 | |||
1928 | mutex_lock(&os->os_lock); | ||
1929 | ocfs2_queue_orphan_scan(osb); | ||
1930 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) | ||
1931 | schedule_delayed_work(&os->os_orphan_scan_work, | ||
1932 | ocfs2_orphan_scan_timeout()); | ||
1933 | mutex_unlock(&os->os_lock); | ||
1934 | } | ||
1935 | |||
1936 | void ocfs2_orphan_scan_stop(struct ocfs2_super *osb) | ||
1937 | { | ||
1938 | struct ocfs2_orphan_scan *os; | ||
1939 | |||
1940 | os = &osb->osb_orphan_scan; | ||
1941 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE) { | ||
1942 | atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); | ||
1943 | mutex_lock(&os->os_lock); | ||
1944 | cancel_delayed_work(&os->os_orphan_scan_work); | ||
1945 | mutex_unlock(&os->os_lock); | ||
1946 | } | ||
1947 | } | ||
1948 | |||
1949 | void ocfs2_orphan_scan_init(struct ocfs2_super *osb) | ||
1950 | { | ||
1951 | struct ocfs2_orphan_scan *os; | ||
1952 | |||
1953 | os = &osb->osb_orphan_scan; | ||
1954 | os->os_osb = osb; | ||
1955 | os->os_count = 0; | ||
1956 | os->os_seqno = 0; | ||
1957 | os->os_scantime = CURRENT_TIME; | ||
1958 | mutex_init(&os->os_lock); | ||
1959 | INIT_DELAYED_WORK(&os->os_orphan_scan_work, ocfs2_orphan_scan_work); | ||
1960 | |||
1961 | if (ocfs2_is_hard_readonly(osb) || ocfs2_mount_local(osb)) | ||
1962 | atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE); | ||
1963 | else { | ||
1964 | atomic_set(&os->os_state, ORPHAN_SCAN_ACTIVE); | ||
1965 | schedule_delayed_work(&os->os_orphan_scan_work, | ||
1966 | ocfs2_orphan_scan_timeout()); | ||
1967 | } | ||
1968 | } | ||
1969 | |||
1844 | struct ocfs2_orphan_filldir_priv { | 1970 | struct ocfs2_orphan_filldir_priv { |
1845 | struct inode *head; | 1971 | struct inode *head; |
1846 | struct ocfs2_super *osb; | 1972 | struct ocfs2_super *osb; |
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index eb7b76331eb7..5432c7f79cc6 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h | |||
@@ -144,6 +144,10 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb, | |||
144 | } | 144 | } |
145 | 145 | ||
146 | /* Exported only for the journal struct init code in super.c. Do not call. */ | 146 | /* Exported only for the journal struct init code in super.c. Do not call. */ |
147 | void ocfs2_orphan_scan_init(struct ocfs2_super *osb); | ||
148 | void ocfs2_orphan_scan_stop(struct ocfs2_super *osb); | ||
149 | void ocfs2_orphan_scan_exit(struct ocfs2_super *osb); | ||
150 | |||
147 | void ocfs2_complete_recovery(struct work_struct *work); | 151 | void ocfs2_complete_recovery(struct work_struct *work); |
148 | void ocfs2_wait_for_recovery(struct ocfs2_super *osb); | 152 | void ocfs2_wait_for_recovery(struct ocfs2_super *osb); |
149 | 153 | ||
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 33464c6b60a2..8601f934010b 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -118,7 +118,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, | |||
118 | mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, | 118 | mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, |
119 | dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); | 119 | dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); |
120 | 120 | ||
121 | status = ocfs2_inode_lock(dir, NULL, 0); | 121 | status = ocfs2_inode_lock_nested(dir, NULL, 0, OI_LS_PARENT); |
122 | if (status < 0) { | 122 | if (status < 0) { |
123 | if (status != -ENOENT) | 123 | if (status != -ENOENT) |
124 | mlog_errno(status); | 124 | mlog_errno(status); |
@@ -636,7 +636,7 @@ static int ocfs2_link(struct dentry *old_dentry, | |||
636 | if (S_ISDIR(inode->i_mode)) | 636 | if (S_ISDIR(inode->i_mode)) |
637 | return -EPERM; | 637 | return -EPERM; |
638 | 638 | ||
639 | err = ocfs2_inode_lock(dir, &parent_fe_bh, 1); | 639 | err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT); |
640 | if (err < 0) { | 640 | if (err < 0) { |
641 | if (err != -ENOENT) | 641 | if (err != -ENOENT) |
642 | mlog_errno(err); | 642 | mlog_errno(err); |
@@ -800,7 +800,8 @@ static int ocfs2_unlink(struct inode *dir, | |||
800 | return -EPERM; | 800 | return -EPERM; |
801 | } | 801 | } |
802 | 802 | ||
803 | status = ocfs2_inode_lock(dir, &parent_node_bh, 1); | 803 | status = ocfs2_inode_lock_nested(dir, &parent_node_bh, 1, |
804 | OI_LS_PARENT); | ||
804 | if (status < 0) { | 805 | if (status < 0) { |
805 | if (status != -ENOENT) | 806 | if (status != -ENOENT) |
806 | mlog_errno(status); | 807 | mlog_errno(status); |
@@ -978,7 +979,8 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
978 | inode1 = tmpinode; | 979 | inode1 = tmpinode; |
979 | } | 980 | } |
980 | /* lock id2 */ | 981 | /* lock id2 */ |
981 | status = ocfs2_inode_lock(inode2, bh2, 1); | 982 | status = ocfs2_inode_lock_nested(inode2, bh2, 1, |
983 | OI_LS_RENAME1); | ||
982 | if (status < 0) { | 984 | if (status < 0) { |
983 | if (status != -ENOENT) | 985 | if (status != -ENOENT) |
984 | mlog_errno(status); | 986 | mlog_errno(status); |
@@ -987,7 +989,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb, | |||
987 | } | 989 | } |
988 | 990 | ||
989 | /* lock id1 */ | 991 | /* lock id1 */ |
990 | status = ocfs2_inode_lock(inode1, bh1, 1); | 992 | status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2); |
991 | if (status < 0) { | 993 | if (status < 0) { |
992 | /* | 994 | /* |
993 | * An error return must mean that no cluster locks | 995 | * An error return must mean that no cluster locks |
@@ -1103,7 +1105,8 @@ static int ocfs2_rename(struct inode *old_dir, | |||
1103 | * won't have to concurrently downconvert the inode and the | 1105 | * won't have to concurrently downconvert the inode and the |
1104 | * dentry locks. | 1106 | * dentry locks. |
1105 | */ | 1107 | */ |
1106 | status = ocfs2_inode_lock(old_inode, &old_inode_bh, 1); | 1108 | status = ocfs2_inode_lock_nested(old_inode, &old_inode_bh, 1, |
1109 | OI_LS_PARENT); | ||
1107 | if (status < 0) { | 1110 | if (status < 0) { |
1108 | if (status != -ENOENT) | 1111 | if (status != -ENOENT) |
1109 | mlog_errno(status); | 1112 | mlog_errno(status); |
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 1386281950db..c9345ebb8493 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/workqueue.h> | 34 | #include <linux/workqueue.h> |
35 | #include <linux/kref.h> | 35 | #include <linux/kref.h> |
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <linux/lockdep.h> | ||
37 | #ifndef CONFIG_OCFS2_COMPAT_JBD | 38 | #ifndef CONFIG_OCFS2_COMPAT_JBD |
38 | # include <linux/jbd2.h> | 39 | # include <linux/jbd2.h> |
39 | #else | 40 | #else |
@@ -47,6 +48,9 @@ | |||
47 | #include "ocfs2_fs.h" | 48 | #include "ocfs2_fs.h" |
48 | #include "ocfs2_lockid.h" | 49 | #include "ocfs2_lockid.h" |
49 | 50 | ||
51 | /* For struct ocfs2_blockcheck_stats */ | ||
52 | #include "blockcheck.h" | ||
53 | |||
50 | /* Most user visible OCFS2 inodes will have very few pieces of | 54 | /* Most user visible OCFS2 inodes will have very few pieces of |
51 | * metadata, but larger files (including bitmaps, etc) must be taken | 55 | * metadata, but larger files (including bitmaps, etc) must be taken |
52 | * into account when designing an access scheme. We allow a small | 56 | * into account when designing an access scheme. We allow a small |
@@ -149,6 +153,25 @@ struct ocfs2_lock_res { | |||
149 | unsigned int l_lock_max_exmode; /* Max wait for EX */ | 153 | unsigned int l_lock_max_exmode; /* Max wait for EX */ |
150 | unsigned int l_lock_refresh; /* Disk refreshes */ | 154 | unsigned int l_lock_refresh; /* Disk refreshes */ |
151 | #endif | 155 | #endif |
156 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
157 | struct lockdep_map l_lockdep_map; | ||
158 | #endif | ||
159 | }; | ||
160 | |||
161 | enum ocfs2_orphan_scan_state { | ||
162 | ORPHAN_SCAN_ACTIVE, | ||
163 | ORPHAN_SCAN_INACTIVE | ||
164 | }; | ||
165 | |||
166 | struct ocfs2_orphan_scan { | ||
167 | struct mutex os_lock; | ||
168 | struct ocfs2_super *os_osb; | ||
169 | struct ocfs2_lock_res os_lockres; /* lock to synchronize scans */ | ||
170 | struct delayed_work os_orphan_scan_work; | ||
171 | struct timespec os_scantime; /* time this node ran the scan */ | ||
172 | u32 os_count; /* tracks node specific scans */ | ||
173 | u32 os_seqno; /* tracks cluster wide scans */ | ||
174 | atomic_t os_state; /* ACTIVE or INACTIVE */ | ||
152 | }; | 175 | }; |
153 | 176 | ||
154 | struct ocfs2_dlm_debug { | 177 | struct ocfs2_dlm_debug { |
@@ -295,6 +318,7 @@ struct ocfs2_super | |||
295 | struct ocfs2_dinode *local_alloc_copy; | 318 | struct ocfs2_dinode *local_alloc_copy; |
296 | struct ocfs2_quota_recovery *quota_rec; | 319 | struct ocfs2_quota_recovery *quota_rec; |
297 | 320 | ||
321 | struct ocfs2_blockcheck_stats osb_ecc_stats; | ||
298 | struct ocfs2_alloc_stats alloc_stats; | 322 | struct ocfs2_alloc_stats alloc_stats; |
299 | char dev_str[20]; /* "major,minor" of the device */ | 323 | char dev_str[20]; /* "major,minor" of the device */ |
300 | 324 | ||
@@ -341,6 +365,8 @@ struct ocfs2_super | |||
341 | unsigned int *osb_orphan_wipes; | 365 | unsigned int *osb_orphan_wipes; |
342 | wait_queue_head_t osb_wipe_event; | 366 | wait_queue_head_t osb_wipe_event; |
343 | 367 | ||
368 | struct ocfs2_orphan_scan osb_orphan_scan; | ||
369 | |||
344 | /* used to protect metaecc calculation check of xattr. */ | 370 | /* used to protect metaecc calculation check of xattr. */ |
345 | spinlock_t osb_xattr_lock; | 371 | spinlock_t osb_xattr_lock; |
346 | 372 | ||
diff --git a/fs/ocfs2/ocfs2_lockid.h b/fs/ocfs2/ocfs2_lockid.h index a53ce87481bf..fcdba091af3d 100644 --- a/fs/ocfs2/ocfs2_lockid.h +++ b/fs/ocfs2/ocfs2_lockid.h | |||
@@ -48,6 +48,7 @@ enum ocfs2_lock_type { | |||
48 | OCFS2_LOCK_TYPE_FLOCK, | 48 | OCFS2_LOCK_TYPE_FLOCK, |
49 | OCFS2_LOCK_TYPE_QINFO, | 49 | OCFS2_LOCK_TYPE_QINFO, |
50 | OCFS2_LOCK_TYPE_NFS_SYNC, | 50 | OCFS2_LOCK_TYPE_NFS_SYNC, |
51 | OCFS2_LOCK_TYPE_ORPHAN_SCAN, | ||
51 | OCFS2_NUM_LOCK_TYPES | 52 | OCFS2_NUM_LOCK_TYPES |
52 | }; | 53 | }; |
53 | 54 | ||
@@ -85,6 +86,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type) | |||
85 | case OCFS2_LOCK_TYPE_NFS_SYNC: | 86 | case OCFS2_LOCK_TYPE_NFS_SYNC: |
86 | c = 'Y'; | 87 | c = 'Y'; |
87 | break; | 88 | break; |
89 | case OCFS2_LOCK_TYPE_ORPHAN_SCAN: | ||
90 | c = 'P'; | ||
91 | break; | ||
88 | default: | 92 | default: |
89 | c = '\0'; | 93 | c = '\0'; |
90 | } | 94 | } |
@@ -104,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = { | |||
104 | [OCFS2_LOCK_TYPE_OPEN] = "Open", | 108 | [OCFS2_LOCK_TYPE_OPEN] = "Open", |
105 | [OCFS2_LOCK_TYPE_FLOCK] = "Flock", | 109 | [OCFS2_LOCK_TYPE_FLOCK] = "Flock", |
106 | [OCFS2_LOCK_TYPE_QINFO] = "Quota", | 110 | [OCFS2_LOCK_TYPE_QINFO] = "Quota", |
111 | [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan", | ||
107 | }; | 112 | }; |
108 | 113 | ||
109 | static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) | 114 | static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type) |
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index 1ed0f7c86869..edfa60cd155c 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
@@ -421,6 +421,7 @@ int ocfs2_global_read_dquot(struct dquot *dquot) | |||
421 | OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; | 421 | OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes; |
422 | if (!dquot->dq_off) { /* No real quota entry? */ | 422 | if (!dquot->dq_off) { /* No real quota entry? */ |
423 | /* Upgrade to exclusive lock for allocation */ | 423 | /* Upgrade to exclusive lock for allocation */ |
424 | ocfs2_qinfo_unlock(info, 0); | ||
424 | err = ocfs2_qinfo_lock(info, 1); | 425 | err = ocfs2_qinfo_lock(info, 1); |
425 | if (err < 0) | 426 | if (err < 0) |
426 | goto out_qlock; | 427 | goto out_qlock; |
@@ -435,7 +436,8 @@ int ocfs2_global_read_dquot(struct dquot *dquot) | |||
435 | out_qlock: | 436 | out_qlock: |
436 | if (ex) | 437 | if (ex) |
437 | ocfs2_qinfo_unlock(info, 1); | 438 | ocfs2_qinfo_unlock(info, 1); |
438 | ocfs2_qinfo_unlock(info, 0); | 439 | else |
440 | ocfs2_qinfo_unlock(info, 0); | ||
439 | out: | 441 | out: |
440 | if (err < 0) | 442 | if (err < 0) |
441 | mlog_errno(err); | 443 | mlog_errno(err); |
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 07deec5e9721..5a460fa82553 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c | |||
@@ -444,10 +444,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, | |||
444 | 444 | ||
445 | mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type); | 445 | mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type); |
446 | 446 | ||
447 | status = ocfs2_lock_global_qf(oinfo, 1); | ||
448 | if (status < 0) | ||
449 | goto out; | ||
450 | |||
451 | list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) { | 447 | list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) { |
452 | chunk = rchunk->rc_chunk; | 448 | chunk = rchunk->rc_chunk; |
453 | hbh = NULL; | 449 | hbh = NULL; |
@@ -480,12 +476,18 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, | |||
480 | type); | 476 | type); |
481 | goto out_put_bh; | 477 | goto out_put_bh; |
482 | } | 478 | } |
479 | status = ocfs2_lock_global_qf(oinfo, 1); | ||
480 | if (status < 0) { | ||
481 | mlog_errno(status); | ||
482 | goto out_put_dquot; | ||
483 | } | ||
484 | |||
483 | handle = ocfs2_start_trans(OCFS2_SB(sb), | 485 | handle = ocfs2_start_trans(OCFS2_SB(sb), |
484 | OCFS2_QSYNC_CREDITS); | 486 | OCFS2_QSYNC_CREDITS); |
485 | if (IS_ERR(handle)) { | 487 | if (IS_ERR(handle)) { |
486 | status = PTR_ERR(handle); | 488 | status = PTR_ERR(handle); |
487 | mlog_errno(status); | 489 | mlog_errno(status); |
488 | goto out_put_dquot; | 490 | goto out_drop_lock; |
489 | } | 491 | } |
490 | mutex_lock(&sb_dqopt(sb)->dqio_mutex); | 492 | mutex_lock(&sb_dqopt(sb)->dqio_mutex); |
491 | spin_lock(&dq_data_lock); | 493 | spin_lock(&dq_data_lock); |
@@ -523,6 +525,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, | |||
523 | out_commit: | 525 | out_commit: |
524 | mutex_unlock(&sb_dqopt(sb)->dqio_mutex); | 526 | mutex_unlock(&sb_dqopt(sb)->dqio_mutex); |
525 | ocfs2_commit_trans(OCFS2_SB(sb), handle); | 527 | ocfs2_commit_trans(OCFS2_SB(sb), handle); |
528 | out_drop_lock: | ||
529 | ocfs2_unlock_global_qf(oinfo, 1); | ||
526 | out_put_dquot: | 530 | out_put_dquot: |
527 | dqput(dquot); | 531 | dqput(dquot); |
528 | out_put_bh: | 532 | out_put_bh: |
@@ -537,8 +541,6 @@ out_put_bh: | |||
537 | if (status < 0) | 541 | if (status < 0) |
538 | break; | 542 | break; |
539 | } | 543 | } |
540 | ocfs2_unlock_global_qf(oinfo, 1); | ||
541 | out: | ||
542 | if (status < 0) | 544 | if (status < 0) |
543 | free_recovery_list(&(rec->r_list[type])); | 545 | free_recovery_list(&(rec->r_list[type])); |
544 | mlog_exit(status); | 546 | mlog_exit(status); |
@@ -655,6 +657,9 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) | |||
655 | struct ocfs2_quota_recovery *rec; | 657 | struct ocfs2_quota_recovery *rec; |
656 | int locked = 0; | 658 | int locked = 0; |
657 | 659 | ||
660 | /* We don't need the lock and we have to acquire quota file locks | ||
661 | * which will later depend on this lock */ | ||
662 | mutex_unlock(&sb_dqopt(sb)->dqio_mutex); | ||
658 | info->dqi_maxblimit = 0x7fffffffffffffffLL; | 663 | info->dqi_maxblimit = 0x7fffffffffffffffLL; |
659 | info->dqi_maxilimit = 0x7fffffffffffffffLL; | 664 | info->dqi_maxilimit = 0x7fffffffffffffffLL; |
660 | oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); | 665 | oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS); |
@@ -733,6 +738,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type) | |||
733 | goto out_err; | 738 | goto out_err; |
734 | } | 739 | } |
735 | 740 | ||
741 | mutex_lock(&sb_dqopt(sb)->dqio_mutex); | ||
736 | return 0; | 742 | return 0; |
737 | out_err: | 743 | out_err: |
738 | if (oinfo) { | 744 | if (oinfo) { |
@@ -746,6 +752,7 @@ out_err: | |||
746 | kfree(oinfo); | 752 | kfree(oinfo); |
747 | } | 753 | } |
748 | brelse(bh); | 754 | brelse(bh); |
755 | mutex_lock(&sb_dqopt(sb)->dqio_mutex); | ||
749 | return -1; | 756 | return -1; |
750 | } | 757 | } |
751 | 758 | ||
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c index fcd120f1493a..3f661376a2de 100644 --- a/fs/ocfs2/stack_o2cb.c +++ b/fs/ocfs2/stack_o2cb.c | |||
@@ -236,6 +236,16 @@ static int o2cb_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
236 | return dlm_status_to_errno(lksb->lksb_o2dlm.status); | 236 | return dlm_status_to_errno(lksb->lksb_o2dlm.status); |
237 | } | 237 | } |
238 | 238 | ||
239 | /* | ||
240 | * o2dlm aways has a "valid" LVB. If the dlm loses track of the LVB | ||
241 | * contents, it will zero out the LVB. Thus the caller can always trust | ||
242 | * the contents. | ||
243 | */ | ||
244 | static int o2cb_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) | ||
245 | { | ||
246 | return 1; | ||
247 | } | ||
248 | |||
239 | static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 249 | static void *o2cb_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
240 | { | 250 | { |
241 | return (void *)(lksb->lksb_o2dlm.lvb); | 251 | return (void *)(lksb->lksb_o2dlm.lvb); |
@@ -354,6 +364,7 @@ static struct ocfs2_stack_operations o2cb_stack_ops = { | |||
354 | .dlm_lock = o2cb_dlm_lock, | 364 | .dlm_lock = o2cb_dlm_lock, |
355 | .dlm_unlock = o2cb_dlm_unlock, | 365 | .dlm_unlock = o2cb_dlm_unlock, |
356 | .lock_status = o2cb_dlm_lock_status, | 366 | .lock_status = o2cb_dlm_lock_status, |
367 | .lvb_valid = o2cb_dlm_lvb_valid, | ||
357 | .lock_lvb = o2cb_dlm_lvb, | 368 | .lock_lvb = o2cb_dlm_lvb, |
358 | .dump_lksb = o2cb_dump_lksb, | 369 | .dump_lksb = o2cb_dump_lksb, |
359 | }; | 370 | }; |
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 9b76d41a8ac6..ff4c798a5635 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -738,6 +738,13 @@ static int user_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
738 | return lksb->lksb_fsdlm.sb_status; | 738 | return lksb->lksb_fsdlm.sb_status; |
739 | } | 739 | } |
740 | 740 | ||
741 | static int user_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) | ||
742 | { | ||
743 | int invalid = lksb->lksb_fsdlm.sb_flags & DLM_SBF_VALNOTVALID; | ||
744 | |||
745 | return !invalid; | ||
746 | } | ||
747 | |||
741 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 748 | static void *user_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
742 | { | 749 | { |
743 | if (!lksb->lksb_fsdlm.sb_lvbptr) | 750 | if (!lksb->lksb_fsdlm.sb_lvbptr) |
@@ -873,6 +880,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = { | |||
873 | .dlm_lock = user_dlm_lock, | 880 | .dlm_lock = user_dlm_lock, |
874 | .dlm_unlock = user_dlm_unlock, | 881 | .dlm_unlock = user_dlm_unlock, |
875 | .lock_status = user_dlm_lock_status, | 882 | .lock_status = user_dlm_lock_status, |
883 | .lvb_valid = user_dlm_lvb_valid, | ||
876 | .lock_lvb = user_dlm_lvb, | 884 | .lock_lvb = user_dlm_lvb, |
877 | .plock = user_plock, | 885 | .plock = user_plock, |
878 | .dump_lksb = user_dlm_dump_lksb, | 886 | .dump_lksb = user_dlm_dump_lksb, |
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 68b668b0e60a..3f2f1c45b7b6 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * Code which implements an OCFS2 specific interface to underlying | 6 | * Code which implements an OCFS2 specific interface to underlying |
7 | * cluster stacks. | 7 | * cluster stacks. |
8 | * | 8 | * |
9 | * Copyright (C) 2007 Oracle. All rights reserved. | 9 | * Copyright (C) 2007, 2009 Oracle. All rights reserved. |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or | 11 | * This program is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public | 12 | * modify it under the terms of the GNU General Public |
@@ -271,11 +271,12 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb) | |||
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); | 272 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lock_status); |
273 | 273 | ||
274 | /* | 274 | int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb) |
275 | * Why don't we cast to ocfs2_meta_lvb? The "clean" answer is that we | 275 | { |
276 | * don't cast at the glue level. The real answer is that the header | 276 | return active_stack->sp_ops->lvb_valid(lksb); |
277 | * ordering is nigh impossible. | 277 | } |
278 | */ | 278 | EXPORT_SYMBOL_GPL(ocfs2_dlm_lvb_valid); |
279 | |||
279 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) | 280 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb) |
280 | { | 281 | { |
281 | return active_stack->sp_ops->lock_lvb(lksb); | 282 | return active_stack->sp_ops->lock_lvb(lksb); |
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h index c571af375ef8..03a44d60eac9 100644 --- a/fs/ocfs2/stackglue.h +++ b/fs/ocfs2/stackglue.h | |||
@@ -186,6 +186,11 @@ struct ocfs2_stack_operations { | |||
186 | int (*lock_status)(union ocfs2_dlm_lksb *lksb); | 186 | int (*lock_status)(union ocfs2_dlm_lksb *lksb); |
187 | 187 | ||
188 | /* | 188 | /* |
189 | * Return non-zero if the LVB is valid. | ||
190 | */ | ||
191 | int (*lvb_valid)(union ocfs2_dlm_lksb *lksb); | ||
192 | |||
193 | /* | ||
189 | * Pull the lvb pointer off of the stack-specific lksb. | 194 | * Pull the lvb pointer off of the stack-specific lksb. |
190 | */ | 195 | */ |
191 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); | 196 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); |
@@ -252,6 +257,7 @@ int ocfs2_dlm_unlock(struct ocfs2_cluster_connection *conn, | |||
252 | struct ocfs2_lock_res *astarg); | 257 | struct ocfs2_lock_res *astarg); |
253 | 258 | ||
254 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); | 259 | int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); |
260 | int ocfs2_dlm_lvb_valid(union ocfs2_dlm_lksb *lksb); | ||
255 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); | 261 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); |
256 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); | 262 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); |
257 | 263 | ||
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 8439f6b324b9..73a16d4666dc 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c | |||
@@ -923,14 +923,23 @@ static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, | |||
923 | int nr) | 923 | int nr) |
924 | { | 924 | { |
925 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; | 925 | struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data; |
926 | int ret; | ||
926 | 927 | ||
927 | if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap)) | 928 | if (ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap)) |
928 | return 0; | 929 | return 0; |
929 | if (!buffer_jbd(bg_bh) || !bh2jh(bg_bh)->b_committed_data) | 930 | |
931 | if (!buffer_jbd(bg_bh)) | ||
930 | return 1; | 932 | return 1; |
931 | 933 | ||
934 | jbd_lock_bh_state(bg_bh); | ||
932 | bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data; | 935 | bg = (struct ocfs2_group_desc *) bh2jh(bg_bh)->b_committed_data; |
933 | return !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap); | 936 | if (bg) |
937 | ret = !ocfs2_test_bit(nr, (unsigned long *)bg->bg_bitmap); | ||
938 | else | ||
939 | ret = 1; | ||
940 | jbd_unlock_bh_state(bg_bh); | ||
941 | |||
942 | return ret; | ||
934 | } | 943 | } |
935 | 944 | ||
936 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, | 945 | static int ocfs2_block_group_find_clear_bits(struct ocfs2_super *osb, |
@@ -1885,6 +1894,7 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, | |||
1885 | unsigned int tmp; | 1894 | unsigned int tmp; |
1886 | int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; | 1895 | int journal_type = OCFS2_JOURNAL_ACCESS_WRITE; |
1887 | struct ocfs2_group_desc *undo_bg = NULL; | 1896 | struct ocfs2_group_desc *undo_bg = NULL; |
1897 | int cluster_bitmap = 0; | ||
1888 | 1898 | ||
1889 | mlog_entry_void(); | 1899 | mlog_entry_void(); |
1890 | 1900 | ||
@@ -1905,18 +1915,28 @@ static inline int ocfs2_block_group_clear_bits(handle_t *handle, | |||
1905 | } | 1915 | } |
1906 | 1916 | ||
1907 | if (ocfs2_is_cluster_bitmap(alloc_inode)) | 1917 | if (ocfs2_is_cluster_bitmap(alloc_inode)) |
1908 | undo_bg = (struct ocfs2_group_desc *) bh2jh(group_bh)->b_committed_data; | 1918 | cluster_bitmap = 1; |
1919 | |||
1920 | if (cluster_bitmap) { | ||
1921 | jbd_lock_bh_state(group_bh); | ||
1922 | undo_bg = (struct ocfs2_group_desc *) | ||
1923 | bh2jh(group_bh)->b_committed_data; | ||
1924 | BUG_ON(!undo_bg); | ||
1925 | } | ||
1909 | 1926 | ||
1910 | tmp = num_bits; | 1927 | tmp = num_bits; |
1911 | while(tmp--) { | 1928 | while(tmp--) { |
1912 | ocfs2_clear_bit((bit_off + tmp), | 1929 | ocfs2_clear_bit((bit_off + tmp), |
1913 | (unsigned long *) bg->bg_bitmap); | 1930 | (unsigned long *) bg->bg_bitmap); |
1914 | if (ocfs2_is_cluster_bitmap(alloc_inode)) | 1931 | if (cluster_bitmap) |
1915 | ocfs2_set_bit(bit_off + tmp, | 1932 | ocfs2_set_bit(bit_off + tmp, |
1916 | (unsigned long *) undo_bg->bg_bitmap); | 1933 | (unsigned long *) undo_bg->bg_bitmap); |
1917 | } | 1934 | } |
1918 | le16_add_cpu(&bg->bg_free_bits_count, num_bits); | 1935 | le16_add_cpu(&bg->bg_free_bits_count, num_bits); |
1919 | 1936 | ||
1937 | if (cluster_bitmap) | ||
1938 | jbd_unlock_bh_state(group_bh); | ||
1939 | |||
1920 | status = ocfs2_journal_dirty(handle, group_bh); | 1940 | status = ocfs2_journal_dirty(handle, group_bh); |
1921 | if (status < 0) | 1941 | if (status < 0) |
1922 | mlog_errno(status); | 1942 | mlog_errno(status); |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 201b40a441fe..7efb349fb9bd 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -119,10 +119,12 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb); | |||
119 | static int ocfs2_check_volume(struct ocfs2_super *osb); | 119 | static int ocfs2_check_volume(struct ocfs2_super *osb); |
120 | static int ocfs2_verify_volume(struct ocfs2_dinode *di, | 120 | static int ocfs2_verify_volume(struct ocfs2_dinode *di, |
121 | struct buffer_head *bh, | 121 | struct buffer_head *bh, |
122 | u32 sectsize); | 122 | u32 sectsize, |
123 | struct ocfs2_blockcheck_stats *stats); | ||
123 | static int ocfs2_initialize_super(struct super_block *sb, | 124 | static int ocfs2_initialize_super(struct super_block *sb, |
124 | struct buffer_head *bh, | 125 | struct buffer_head *bh, |
125 | int sector_size); | 126 | int sector_size, |
127 | struct ocfs2_blockcheck_stats *stats); | ||
126 | static int ocfs2_get_sector(struct super_block *sb, | 128 | static int ocfs2_get_sector(struct super_block *sb, |
127 | struct buffer_head **bh, | 129 | struct buffer_head **bh, |
128 | int block, | 130 | int block, |
@@ -203,10 +205,10 @@ static const match_table_t tokens = { | |||
203 | #ifdef CONFIG_DEBUG_FS | 205 | #ifdef CONFIG_DEBUG_FS |
204 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | 206 | static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) |
205 | { | 207 | { |
206 | int out = 0; | ||
207 | int i; | ||
208 | struct ocfs2_cluster_connection *cconn = osb->cconn; | 208 | struct ocfs2_cluster_connection *cconn = osb->cconn; |
209 | struct ocfs2_recovery_map *rm = osb->recovery_map; | 209 | struct ocfs2_recovery_map *rm = osb->recovery_map; |
210 | struct ocfs2_orphan_scan *os = &osb->osb_orphan_scan; | ||
211 | int i, out = 0; | ||
210 | 212 | ||
211 | out += snprintf(buf + out, len - out, | 213 | out += snprintf(buf + out, len - out, |
212 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", | 214 | "%10s => Id: %-s Uuid: %-s Gen: 0x%X Label: %-s\n", |
@@ -231,20 +233,24 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
231 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", | 233 | "%10s => Opts: 0x%lX AtimeQuanta: %u\n", "Mount", |
232 | osb->s_mount_opt, osb->s_atime_quantum); | 234 | osb->s_mount_opt, osb->s_atime_quantum); |
233 | 235 | ||
234 | out += snprintf(buf + out, len - out, | 236 | if (cconn) { |
235 | "%10s => Stack: %s Name: %*s Version: %d.%d\n", | 237 | out += snprintf(buf + out, len - out, |
236 | "Cluster", | 238 | "%10s => Stack: %s Name: %*s " |
237 | (*osb->osb_cluster_stack == '\0' ? | 239 | "Version: %d.%d\n", "Cluster", |
238 | "o2cb" : osb->osb_cluster_stack), | 240 | (*osb->osb_cluster_stack == '\0' ? |
239 | cconn->cc_namelen, cconn->cc_name, | 241 | "o2cb" : osb->osb_cluster_stack), |
240 | cconn->cc_version.pv_major, cconn->cc_version.pv_minor); | 242 | cconn->cc_namelen, cconn->cc_name, |
243 | cconn->cc_version.pv_major, | ||
244 | cconn->cc_version.pv_minor); | ||
245 | } | ||
241 | 246 | ||
242 | spin_lock(&osb->dc_task_lock); | 247 | spin_lock(&osb->dc_task_lock); |
243 | out += snprintf(buf + out, len - out, | 248 | out += snprintf(buf + out, len - out, |
244 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " | 249 | "%10s => Pid: %d Count: %lu WakeSeq: %lu " |
245 | "WorkSeq: %lu\n", "DownCnvt", | 250 | "WorkSeq: %lu\n", "DownCnvt", |
246 | task_pid_nr(osb->dc_task), osb->blocked_lock_count, | 251 | (osb->dc_task ? task_pid_nr(osb->dc_task) : -1), |
247 | osb->dc_wake_sequence, osb->dc_work_sequence); | 252 | osb->blocked_lock_count, osb->dc_wake_sequence, |
253 | osb->dc_work_sequence); | ||
248 | spin_unlock(&osb->dc_task_lock); | 254 | spin_unlock(&osb->dc_task_lock); |
249 | 255 | ||
250 | spin_lock(&osb->osb_lock); | 256 | spin_lock(&osb->osb_lock); |
@@ -264,14 +270,15 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
264 | 270 | ||
265 | out += snprintf(buf + out, len - out, | 271 | out += snprintf(buf + out, len - out, |
266 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", | 272 | "%10s => Pid: %d Interval: %lu Needs: %d\n", "Commit", |
267 | task_pid_nr(osb->commit_task), osb->osb_commit_interval, | 273 | (osb->commit_task ? task_pid_nr(osb->commit_task) : -1), |
274 | osb->osb_commit_interval, | ||
268 | atomic_read(&osb->needs_checkpoint)); | 275 | atomic_read(&osb->needs_checkpoint)); |
269 | 276 | ||
270 | out += snprintf(buf + out, len - out, | 277 | out += snprintf(buf + out, len - out, |
271 | "%10s => State: %d NumTxns: %d TxnId: %lu\n", | 278 | "%10s => State: %d TxnId: %lu NumTxns: %d\n", |
272 | "Journal", osb->journal->j_state, | 279 | "Journal", osb->journal->j_state, |
273 | atomic_read(&osb->journal->j_num_trans), | 280 | osb->journal->j_trans_id, |
274 | osb->journal->j_trans_id); | 281 | atomic_read(&osb->journal->j_num_trans)); |
275 | 282 | ||
276 | out += snprintf(buf + out, len - out, | 283 | out += snprintf(buf + out, len - out, |
277 | "%10s => GlobalAllocs: %d LocalAllocs: %d " | 284 | "%10s => GlobalAllocs: %d LocalAllocs: %d " |
@@ -297,9 +304,18 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len) | |||
297 | atomic_read(&osb->s_num_inodes_stolen)); | 304 | atomic_read(&osb->s_num_inodes_stolen)); |
298 | spin_unlock(&osb->osb_lock); | 305 | spin_unlock(&osb->osb_lock); |
299 | 306 | ||
307 | out += snprintf(buf + out, len - out, "OrphanScan => "); | ||
308 | out += snprintf(buf + out, len - out, "Local: %u Global: %u ", | ||
309 | os->os_count, os->os_seqno); | ||
310 | out += snprintf(buf + out, len - out, " Last Scan: "); | ||
311 | if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE) | ||
312 | out += snprintf(buf + out, len - out, "Disabled\n"); | ||
313 | else | ||
314 | out += snprintf(buf + out, len - out, "%lu seconds ago\n", | ||
315 | (get_seconds() - os->os_scantime.tv_sec)); | ||
316 | |||
300 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", | 317 | out += snprintf(buf + out, len - out, "%10s => %3s %10s\n", |
301 | "Slots", "Num", "RecoGen"); | 318 | "Slots", "Num", "RecoGen"); |
302 | |||
303 | for (i = 0; i < osb->max_slots; ++i) { | 319 | for (i = 0; i < osb->max_slots; ++i) { |
304 | out += snprintf(buf + out, len - out, | 320 | out += snprintf(buf + out, len - out, |
305 | "%10s %c %3d %10d\n", | 321 | "%10s %c %3d %10d\n", |
@@ -542,7 +558,7 @@ static unsigned long long ocfs2_max_file_offset(unsigned int bbits, | |||
542 | */ | 558 | */ |
543 | 559 | ||
544 | #if BITS_PER_LONG == 32 | 560 | #if BITS_PER_LONG == 32 |
545 | # if defined(CONFIG_LBD) | 561 | # if defined(CONFIG_LBDAF) |
546 | BUILD_BUG_ON(sizeof(sector_t) != 8); | 562 | BUILD_BUG_ON(sizeof(sector_t) != 8); |
547 | /* | 563 | /* |
548 | * We might be limited by page cache size. | 564 | * We might be limited by page cache size. |
@@ -693,7 +709,8 @@ out: | |||
693 | 709 | ||
694 | static int ocfs2_sb_probe(struct super_block *sb, | 710 | static int ocfs2_sb_probe(struct super_block *sb, |
695 | struct buffer_head **bh, | 711 | struct buffer_head **bh, |
696 | int *sector_size) | 712 | int *sector_size, |
713 | struct ocfs2_blockcheck_stats *stats) | ||
697 | { | 714 | { |
698 | int status, tmpstat; | 715 | int status, tmpstat; |
699 | struct ocfs1_vol_disk_hdr *hdr; | 716 | struct ocfs1_vol_disk_hdr *hdr; |
@@ -759,7 +776,8 @@ static int ocfs2_sb_probe(struct super_block *sb, | |||
759 | goto bail; | 776 | goto bail; |
760 | } | 777 | } |
761 | di = (struct ocfs2_dinode *) (*bh)->b_data; | 778 | di = (struct ocfs2_dinode *) (*bh)->b_data; |
762 | status = ocfs2_verify_volume(di, *bh, blksize); | 779 | memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats)); |
780 | status = ocfs2_verify_volume(di, *bh, blksize, stats); | ||
763 | if (status >= 0) | 781 | if (status >= 0) |
764 | goto bail; | 782 | goto bail; |
765 | brelse(*bh); | 783 | brelse(*bh); |
@@ -965,6 +983,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
965 | struct ocfs2_super *osb = NULL; | 983 | struct ocfs2_super *osb = NULL; |
966 | struct buffer_head *bh = NULL; | 984 | struct buffer_head *bh = NULL; |
967 | char nodestr[8]; | 985 | char nodestr[8]; |
986 | struct ocfs2_blockcheck_stats stats; | ||
968 | 987 | ||
969 | mlog_entry("%p, %p, %i", sb, data, silent); | 988 | mlog_entry("%p, %p, %i", sb, data, silent); |
970 | 989 | ||
@@ -974,13 +993,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
974 | } | 993 | } |
975 | 994 | ||
976 | /* probe for superblock */ | 995 | /* probe for superblock */ |
977 | status = ocfs2_sb_probe(sb, &bh, §or_size); | 996 | status = ocfs2_sb_probe(sb, &bh, §or_size, &stats); |
978 | if (status < 0) { | 997 | if (status < 0) { |
979 | mlog(ML_ERROR, "superblock probe failed!\n"); | 998 | mlog(ML_ERROR, "superblock probe failed!\n"); |
980 | goto read_super_error; | 999 | goto read_super_error; |
981 | } | 1000 | } |
982 | 1001 | ||
983 | status = ocfs2_initialize_super(sb, bh, sector_size); | 1002 | status = ocfs2_initialize_super(sb, bh, sector_size, &stats); |
984 | osb = OCFS2_SB(sb); | 1003 | osb = OCFS2_SB(sb); |
985 | if (status < 0) { | 1004 | if (status < 0) { |
986 | mlog_errno(status); | 1005 | mlog_errno(status); |
@@ -1090,6 +1109,18 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
1090 | goto read_super_error; | 1109 | goto read_super_error; |
1091 | } | 1110 | } |
1092 | 1111 | ||
1112 | if (ocfs2_meta_ecc(osb)) { | ||
1113 | status = ocfs2_blockcheck_stats_debugfs_install( | ||
1114 | &osb->osb_ecc_stats, | ||
1115 | osb->osb_debug_root); | ||
1116 | if (status) { | ||
1117 | mlog(ML_ERROR, | ||
1118 | "Unable to create blockcheck statistics " | ||
1119 | "files\n"); | ||
1120 | goto read_super_error; | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1093 | status = ocfs2_mount_volume(sb); | 1124 | status = ocfs2_mount_volume(sb); |
1094 | if (osb->root_inode) | 1125 | if (osb->root_inode) |
1095 | inode = igrab(osb->root_inode); | 1126 | inode = igrab(osb->root_inode); |
@@ -1150,6 +1181,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
1150 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); | 1181 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); |
1151 | wake_up(&osb->osb_mount_event); | 1182 | wake_up(&osb->osb_mount_event); |
1152 | 1183 | ||
1184 | /* Start this when the mount is almost sure of being successful */ | ||
1185 | ocfs2_orphan_scan_init(osb); | ||
1186 | |||
1153 | mlog_exit(status); | 1187 | mlog_exit(status); |
1154 | return status; | 1188 | return status; |
1155 | 1189 | ||
@@ -1760,13 +1794,8 @@ static int ocfs2_mount_volume(struct super_block *sb) | |||
1760 | } | 1794 | } |
1761 | 1795 | ||
1762 | status = ocfs2_truncate_log_init(osb); | 1796 | status = ocfs2_truncate_log_init(osb); |
1763 | if (status < 0) { | 1797 | if (status < 0) |
1764 | mlog_errno(status); | 1798 | mlog_errno(status); |
1765 | goto leave; | ||
1766 | } | ||
1767 | |||
1768 | if (ocfs2_mount_local(osb)) | ||
1769 | goto leave; | ||
1770 | 1799 | ||
1771 | leave: | 1800 | leave: |
1772 | if (unlock_super) | 1801 | if (unlock_super) |
@@ -1790,6 +1819,9 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) | |||
1790 | 1819 | ||
1791 | debugfs_remove(osb->osb_ctxt); | 1820 | debugfs_remove(osb->osb_ctxt); |
1792 | 1821 | ||
1822 | /* Orphan scan should be stopped as early as possible */ | ||
1823 | ocfs2_orphan_scan_stop(osb); | ||
1824 | |||
1793 | ocfs2_disable_quotas(osb); | 1825 | ocfs2_disable_quotas(osb); |
1794 | 1826 | ||
1795 | ocfs2_shutdown_local_alloc(osb); | 1827 | ocfs2_shutdown_local_alloc(osb); |
@@ -1833,6 +1865,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) | |||
1833 | if (osb->cconn) | 1865 | if (osb->cconn) |
1834 | ocfs2_dlm_shutdown(osb, hangup_needed); | 1866 | ocfs2_dlm_shutdown(osb, hangup_needed); |
1835 | 1867 | ||
1868 | ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats); | ||
1836 | debugfs_remove(osb->osb_debug_root); | 1869 | debugfs_remove(osb->osb_debug_root); |
1837 | 1870 | ||
1838 | if (hangup_needed) | 1871 | if (hangup_needed) |
@@ -1880,7 +1913,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu | |||
1880 | 1913 | ||
1881 | static int ocfs2_initialize_super(struct super_block *sb, | 1914 | static int ocfs2_initialize_super(struct super_block *sb, |
1882 | struct buffer_head *bh, | 1915 | struct buffer_head *bh, |
1883 | int sector_size) | 1916 | int sector_size, |
1917 | struct ocfs2_blockcheck_stats *stats) | ||
1884 | { | 1918 | { |
1885 | int status; | 1919 | int status; |
1886 | int i, cbits, bbits; | 1920 | int i, cbits, bbits; |
@@ -1939,6 +1973,9 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
1939 | atomic_set(&osb->alloc_stats.bg_allocs, 0); | 1973 | atomic_set(&osb->alloc_stats.bg_allocs, 0); |
1940 | atomic_set(&osb->alloc_stats.bg_extends, 0); | 1974 | atomic_set(&osb->alloc_stats.bg_extends, 0); |
1941 | 1975 | ||
1976 | /* Copy the blockcheck stats from the superblock probe */ | ||
1977 | osb->osb_ecc_stats = *stats; | ||
1978 | |||
1942 | ocfs2_init_node_maps(osb); | 1979 | ocfs2_init_node_maps(osb); |
1943 | 1980 | ||
1944 | snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u", | 1981 | snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u", |
@@ -2169,7 +2206,8 @@ bail: | |||
2169 | */ | 2206 | */ |
2170 | static int ocfs2_verify_volume(struct ocfs2_dinode *di, | 2207 | static int ocfs2_verify_volume(struct ocfs2_dinode *di, |
2171 | struct buffer_head *bh, | 2208 | struct buffer_head *bh, |
2172 | u32 blksz) | 2209 | u32 blksz, |
2210 | struct ocfs2_blockcheck_stats *stats) | ||
2173 | { | 2211 | { |
2174 | int status = -EAGAIN; | 2212 | int status = -EAGAIN; |
2175 | 2213 | ||
@@ -2182,7 +2220,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di, | |||
2182 | OCFS2_FEATURE_INCOMPAT_META_ECC) { | 2220 | OCFS2_FEATURE_INCOMPAT_META_ECC) { |
2183 | status = ocfs2_block_check_validate(bh->b_data, | 2221 | status = ocfs2_block_check_validate(bh->b_data, |
2184 | bh->b_size, | 2222 | bh->b_size, |
2185 | &di->i_check); | 2223 | &di->i_check, |
2224 | stats); | ||
2186 | if (status) | 2225 | if (status) |
2187 | goto out; | 2226 | goto out; |
2188 | } | 2227 | } |
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c index ab713ebdd546..40e53702948c 100644 --- a/fs/ocfs2/sysfile.c +++ b/fs/ocfs2/sysfile.c | |||
@@ -50,6 +50,10 @@ static inline int is_in_system_inode_array(struct ocfs2_super *osb, | |||
50 | int type, | 50 | int type, |
51 | u32 slot); | 51 | u32 slot); |
52 | 52 | ||
53 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
54 | static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES]; | ||
55 | #endif | ||
56 | |||
53 | static inline int is_global_system_inode(int type) | 57 | static inline int is_global_system_inode(int type) |
54 | { | 58 | { |
55 | return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE && | 59 | return type >= OCFS2_FIRST_ONLINE_SYSTEM_INODE && |
@@ -118,6 +122,21 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, | |||
118 | inode = NULL; | 122 | inode = NULL; |
119 | goto bail; | 123 | goto bail; |
120 | } | 124 | } |
125 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
126 | if (type == LOCAL_USER_QUOTA_SYSTEM_INODE || | ||
127 | type == LOCAL_GROUP_QUOTA_SYSTEM_INODE || | ||
128 | type == JOURNAL_SYSTEM_INODE) { | ||
129 | /* Ignore inode lock on these inodes as the lock does not | ||
130 | * really belong to any process and lockdep cannot handle | ||
131 | * that */ | ||
132 | OCFS2_I(inode)->ip_inode_lockres.l_lockdep_map.key = NULL; | ||
133 | } else { | ||
134 | lockdep_init_map(&OCFS2_I(inode)->ip_inode_lockres. | ||
135 | l_lockdep_map, | ||
136 | ocfs2_system_inodes[type].si_name, | ||
137 | &ocfs2_sysfile_cluster_lock_key[type], 0); | ||
138 | } | ||
139 | #endif | ||
121 | bail: | 140 | bail: |
122 | 141 | ||
123 | return inode; | 142 | return inode; |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 15631019dc63..ba320e250747 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -3154,7 +3154,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode, | |||
3154 | le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash)); | 3154 | le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash)); |
3155 | if (func) { | 3155 | if (func) { |
3156 | ret = func(inode, bucket, para); | 3156 | ret = func(inode, bucket, para); |
3157 | if (ret) | 3157 | if (ret && ret != -ERANGE) |
3158 | mlog_errno(ret); | 3158 | mlog_errno(ret); |
3159 | /* Fall through to bucket_relse() */ | 3159 | /* Fall through to bucket_relse() */ |
3160 | } | 3160 | } |
@@ -3261,7 +3261,8 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode, | |||
3261 | ocfs2_list_xattr_bucket, | 3261 | ocfs2_list_xattr_bucket, |
3262 | &xl); | 3262 | &xl); |
3263 | if (ret) { | 3263 | if (ret) { |
3264 | mlog_errno(ret); | 3264 | if (ret != -ERANGE) |
3265 | mlog_errno(ret); | ||
3265 | goto out; | 3266 | goto out; |
3266 | } | 3267 | } |
3267 | 3268 | ||
@@ -378,63 +378,63 @@ SYSCALL_ALIAS(sys_ftruncate64, SyS_ftruncate64); | |||
378 | #endif | 378 | #endif |
379 | #endif /* BITS_PER_LONG == 32 */ | 379 | #endif /* BITS_PER_LONG == 32 */ |
380 | 380 | ||
381 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | 381 | |
382 | int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) | ||
382 | { | 383 | { |
383 | struct file *file; | 384 | struct inode *inode = file->f_path.dentry->d_inode; |
384 | struct inode *inode; | 385 | long ret; |
385 | long ret = -EINVAL; | ||
386 | 386 | ||
387 | if (offset < 0 || len <= 0) | 387 | if (offset < 0 || len <= 0) |
388 | goto out; | 388 | return -EINVAL; |
389 | 389 | ||
390 | /* Return error if mode is not supported */ | 390 | /* Return error if mode is not supported */ |
391 | ret = -EOPNOTSUPP; | ||
392 | if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) | 391 | if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) |
393 | goto out; | 392 | return -EOPNOTSUPP; |
394 | 393 | ||
395 | ret = -EBADF; | ||
396 | file = fget(fd); | ||
397 | if (!file) | ||
398 | goto out; | ||
399 | if (!(file->f_mode & FMODE_WRITE)) | 394 | if (!(file->f_mode & FMODE_WRITE)) |
400 | goto out_fput; | 395 | return -EBADF; |
401 | /* | 396 | /* |
402 | * Revalidate the write permissions, in case security policy has | 397 | * Revalidate the write permissions, in case security policy has |
403 | * changed since the files were opened. | 398 | * changed since the files were opened. |
404 | */ | 399 | */ |
405 | ret = security_file_permission(file, MAY_WRITE); | 400 | ret = security_file_permission(file, MAY_WRITE); |
406 | if (ret) | 401 | if (ret) |
407 | goto out_fput; | 402 | return ret; |
408 | 403 | ||
409 | inode = file->f_path.dentry->d_inode; | ||
410 | |||
411 | ret = -ESPIPE; | ||
412 | if (S_ISFIFO(inode->i_mode)) | 404 | if (S_ISFIFO(inode->i_mode)) |
413 | goto out_fput; | 405 | return -ESPIPE; |
414 | 406 | ||
415 | ret = -ENODEV; | ||
416 | /* | 407 | /* |
417 | * Let individual file system decide if it supports preallocation | 408 | * Let individual file system decide if it supports preallocation |
418 | * for directories or not. | 409 | * for directories or not. |
419 | */ | 410 | */ |
420 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) | 411 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
421 | goto out_fput; | 412 | return -ENODEV; |
422 | 413 | ||
423 | ret = -EFBIG; | ||
424 | /* Check for wrap through zero too */ | 414 | /* Check for wrap through zero too */ |
425 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) | 415 | if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) |
426 | goto out_fput; | 416 | return -EFBIG; |
427 | 417 | ||
428 | if (inode->i_op->fallocate) | 418 | if (!inode->i_op->fallocate) |
429 | ret = inode->i_op->fallocate(inode, mode, offset, len); | 419 | return -EOPNOTSUPP; |
430 | else | ||
431 | ret = -EOPNOTSUPP; | ||
432 | 420 | ||
433 | out_fput: | 421 | return inode->i_op->fallocate(inode, mode, offset, len); |
434 | fput(file); | ||
435 | out: | ||
436 | return ret; | ||
437 | } | 422 | } |
423 | |||
424 | SYSCALL_DEFINE(fallocate)(int fd, int mode, loff_t offset, loff_t len) | ||
425 | { | ||
426 | struct file *file; | ||
427 | int error = -EBADF; | ||
428 | |||
429 | file = fget(fd); | ||
430 | if (file) { | ||
431 | error = do_fallocate(file, mode, offset, len); | ||
432 | fput(file); | ||
433 | } | ||
434 | |||
435 | return error; | ||
436 | } | ||
437 | |||
438 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS | 438 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS |
439 | asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) | 439 | asmlinkage long SyS_fallocate(long fd, long mode, loff_t offset, loff_t len) |
440 | { | 440 | { |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 1a9c7878f864..ea4e6cb29e13 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -436,7 +436,7 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, | |||
436 | rcu_assign_pointer(ptbl->part[partno], p); | 436 | rcu_assign_pointer(ptbl->part[partno], p); |
437 | 437 | ||
438 | /* suppress uevent if the disk supresses it */ | 438 | /* suppress uevent if the disk supresses it */ |
439 | if (!dev_get_uevent_suppress(pdev)) | 439 | if (!dev_get_uevent_suppress(ddev)) |
440 | kobject_uevent(&pdev->kobj, KOBJ_ADD); | 440 | kobject_uevent(&pdev->kobj, KOBJ_ADD); |
441 | 441 | ||
442 | return p; | 442 | return p; |
@@ -68,8 +68,8 @@ void pipe_double_lock(struct pipe_inode_info *pipe1, | |||
68 | pipe_lock_nested(pipe1, I_MUTEX_PARENT); | 68 | pipe_lock_nested(pipe1, I_MUTEX_PARENT); |
69 | pipe_lock_nested(pipe2, I_MUTEX_CHILD); | 69 | pipe_lock_nested(pipe2, I_MUTEX_CHILD); |
70 | } else { | 70 | } else { |
71 | pipe_lock_nested(pipe2, I_MUTEX_CHILD); | 71 | pipe_lock_nested(pipe2, I_MUTEX_PARENT); |
72 | pipe_lock_nested(pipe1, I_MUTEX_PARENT); | 72 | pipe_lock_nested(pipe1, I_MUTEX_CHILD); |
73 | } | 73 | } |
74 | } | 74 | } |
75 | 75 | ||
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 63d965193b22..11a7b5c68153 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
@@ -18,6 +18,7 @@ proc-y += meminfo.o | |||
18 | proc-y += stat.o | 18 | proc-y += stat.o |
19 | proc-y += uptime.o | 19 | proc-y += uptime.o |
20 | proc-y += version.o | 20 | proc-y += version.o |
21 | proc-y += softirqs.o | ||
21 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o | 22 | proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o |
22 | proc-$(CONFIG_NET) += proc_net.o | 23 | proc-$(CONFIG_NET) += proc_net.o |
23 | proc-$(CONFIG_PROC_KCORE) += kcore.o | 24 | proc-$(CONFIG_PROC_KCORE) += kcore.o |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 1539e630c47d..175db258942f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -234,23 +234,20 @@ static int check_mem_permission(struct task_struct *task) | |||
234 | 234 | ||
235 | struct mm_struct *mm_for_maps(struct task_struct *task) | 235 | struct mm_struct *mm_for_maps(struct task_struct *task) |
236 | { | 236 | { |
237 | struct mm_struct *mm = get_task_mm(task); | 237 | struct mm_struct *mm; |
238 | if (!mm) | 238 | |
239 | if (mutex_lock_killable(&task->cred_guard_mutex)) | ||
239 | return NULL; | 240 | return NULL; |
240 | down_read(&mm->mmap_sem); | 241 | |
241 | task_lock(task); | 242 | mm = get_task_mm(task); |
242 | if (task->mm != mm) | 243 | if (mm && mm != current->mm && |
243 | goto out; | 244 | !ptrace_may_access(task, PTRACE_MODE_READ)) { |
244 | if (task->mm != current->mm && | 245 | mmput(mm); |
245 | __ptrace_may_access(task, PTRACE_MODE_READ) < 0) | 246 | mm = NULL; |
246 | goto out; | 247 | } |
247 | task_unlock(task); | 248 | mutex_unlock(&task->cred_guard_mutex); |
249 | |||
248 | return mm; | 250 | return mm; |
249 | out: | ||
250 | task_unlock(task); | ||
251 | up_read(&mm->mmap_sem); | ||
252 | mmput(mm); | ||
253 | return NULL; | ||
254 | } | 251 | } |
255 | 252 | ||
256 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) | 253 | static int proc_pid_cmdline(struct task_struct *task, char * buffer) |
@@ -1006,7 +1003,12 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf, | |||
1006 | 1003 | ||
1007 | if (!task) | 1004 | if (!task) |
1008 | return -ESRCH; | 1005 | return -ESRCH; |
1009 | oom_adjust = task->oomkilladj; | 1006 | task_lock(task); |
1007 | if (task->mm) | ||
1008 | oom_adjust = task->mm->oom_adj; | ||
1009 | else | ||
1010 | oom_adjust = OOM_DISABLE; | ||
1011 | task_unlock(task); | ||
1010 | put_task_struct(task); | 1012 | put_task_struct(task); |
1011 | 1013 | ||
1012 | len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); | 1014 | len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); |
@@ -1035,11 +1037,19 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1035 | task = get_proc_task(file->f_path.dentry->d_inode); | 1037 | task = get_proc_task(file->f_path.dentry->d_inode); |
1036 | if (!task) | 1038 | if (!task) |
1037 | return -ESRCH; | 1039 | return -ESRCH; |
1038 | if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) { | 1040 | task_lock(task); |
1041 | if (!task->mm) { | ||
1042 | task_unlock(task); | ||
1043 | put_task_struct(task); | ||
1044 | return -EINVAL; | ||
1045 | } | ||
1046 | if (oom_adjust < task->mm->oom_adj && !capable(CAP_SYS_RESOURCE)) { | ||
1047 | task_unlock(task); | ||
1039 | put_task_struct(task); | 1048 | put_task_struct(task); |
1040 | return -EACCES; | 1049 | return -EACCES; |
1041 | } | 1050 | } |
1042 | task->oomkilladj = oom_adjust; | 1051 | task->mm->oom_adj = oom_adjust; |
1052 | task_unlock(task); | ||
1043 | put_task_struct(task); | 1053 | put_task_struct(task); |
1044 | if (end - buffer == 0) | 1054 | if (end - buffer == 0) |
1045 | return -EIO; | 1055 | return -EIO; |
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index c6b0302af4c4..d5c410d47fae 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c | |||
@@ -64,10 +64,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
64 | "Inactive(anon): %8lu kB\n" | 64 | "Inactive(anon): %8lu kB\n" |
65 | "Active(file): %8lu kB\n" | 65 | "Active(file): %8lu kB\n" |
66 | "Inactive(file): %8lu kB\n" | 66 | "Inactive(file): %8lu kB\n" |
67 | #ifdef CONFIG_UNEVICTABLE_LRU | ||
68 | "Unevictable: %8lu kB\n" | 67 | "Unevictable: %8lu kB\n" |
69 | "Mlocked: %8lu kB\n" | 68 | "Mlocked: %8lu kB\n" |
70 | #endif | ||
71 | #ifdef CONFIG_HIGHMEM | 69 | #ifdef CONFIG_HIGHMEM |
72 | "HighTotal: %8lu kB\n" | 70 | "HighTotal: %8lu kB\n" |
73 | "HighFree: %8lu kB\n" | 71 | "HighFree: %8lu kB\n" |
@@ -109,10 +107,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
109 | K(pages[LRU_INACTIVE_ANON]), | 107 | K(pages[LRU_INACTIVE_ANON]), |
110 | K(pages[LRU_ACTIVE_FILE]), | 108 | K(pages[LRU_ACTIVE_FILE]), |
111 | K(pages[LRU_INACTIVE_FILE]), | 109 | K(pages[LRU_INACTIVE_FILE]), |
112 | #ifdef CONFIG_UNEVICTABLE_LRU | ||
113 | K(pages[LRU_UNEVICTABLE]), | 110 | K(pages[LRU_UNEVICTABLE]), |
114 | K(global_page_state(NR_MLOCK)), | 111 | K(global_page_state(NR_MLOCK)), |
115 | #endif | ||
116 | #ifdef CONFIG_HIGHMEM | 112 | #ifdef CONFIG_HIGHMEM |
117 | K(i.totalhigh), | 113 | K(i.totalhigh), |
118 | K(i.freehigh), | 114 | K(i.freehigh), |
diff --git a/fs/proc/page.c b/fs/proc/page.c index e9983837d08d..2707c6c7a20f 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c | |||
@@ -6,11 +6,13 @@ | |||
6 | #include <linux/mmzone.h> | 6 | #include <linux/mmzone.h> |
7 | #include <linux/proc_fs.h> | 7 | #include <linux/proc_fs.h> |
8 | #include <linux/seq_file.h> | 8 | #include <linux/seq_file.h> |
9 | #include <linux/hugetlb.h> | ||
9 | #include <asm/uaccess.h> | 10 | #include <asm/uaccess.h> |
10 | #include "internal.h" | 11 | #include "internal.h" |
11 | 12 | ||
12 | #define KPMSIZE sizeof(u64) | 13 | #define KPMSIZE sizeof(u64) |
13 | #define KPMMASK (KPMSIZE - 1) | 14 | #define KPMMASK (KPMSIZE - 1) |
15 | |||
14 | /* /proc/kpagecount - an array exposing page counts | 16 | /* /proc/kpagecount - an array exposing page counts |
15 | * | 17 | * |
16 | * Each entry is a u64 representing the corresponding | 18 | * Each entry is a u64 representing the corresponding |
@@ -32,20 +34,22 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, | |||
32 | return -EINVAL; | 34 | return -EINVAL; |
33 | 35 | ||
34 | while (count > 0) { | 36 | while (count > 0) { |
35 | ppage = NULL; | ||
36 | if (pfn_valid(pfn)) | 37 | if (pfn_valid(pfn)) |
37 | ppage = pfn_to_page(pfn); | 38 | ppage = pfn_to_page(pfn); |
38 | pfn++; | 39 | else |
40 | ppage = NULL; | ||
39 | if (!ppage) | 41 | if (!ppage) |
40 | pcount = 0; | 42 | pcount = 0; |
41 | else | 43 | else |
42 | pcount = page_mapcount(ppage); | 44 | pcount = page_mapcount(ppage); |
43 | 45 | ||
44 | if (put_user(pcount, out++)) { | 46 | if (put_user(pcount, out)) { |
45 | ret = -EFAULT; | 47 | ret = -EFAULT; |
46 | break; | 48 | break; |
47 | } | 49 | } |
48 | 50 | ||
51 | pfn++; | ||
52 | out++; | ||
49 | count -= KPMSIZE; | 53 | count -= KPMSIZE; |
50 | } | 54 | } |
51 | 55 | ||
@@ -68,19 +72,122 @@ static const struct file_operations proc_kpagecount_operations = { | |||
68 | 72 | ||
69 | /* These macros are used to decouple internal flags from exported ones */ | 73 | /* These macros are used to decouple internal flags from exported ones */ |
70 | 74 | ||
71 | #define KPF_LOCKED 0 | 75 | #define KPF_LOCKED 0 |
72 | #define KPF_ERROR 1 | 76 | #define KPF_ERROR 1 |
73 | #define KPF_REFERENCED 2 | 77 | #define KPF_REFERENCED 2 |
74 | #define KPF_UPTODATE 3 | 78 | #define KPF_UPTODATE 3 |
75 | #define KPF_DIRTY 4 | 79 | #define KPF_DIRTY 4 |
76 | #define KPF_LRU 5 | 80 | #define KPF_LRU 5 |
77 | #define KPF_ACTIVE 6 | 81 | #define KPF_ACTIVE 6 |
78 | #define KPF_SLAB 7 | 82 | #define KPF_SLAB 7 |
79 | #define KPF_WRITEBACK 8 | 83 | #define KPF_WRITEBACK 8 |
80 | #define KPF_RECLAIM 9 | 84 | #define KPF_RECLAIM 9 |
81 | #define KPF_BUDDY 10 | 85 | #define KPF_BUDDY 10 |
86 | |||
87 | /* 11-20: new additions in 2.6.31 */ | ||
88 | #define KPF_MMAP 11 | ||
89 | #define KPF_ANON 12 | ||
90 | #define KPF_SWAPCACHE 13 | ||
91 | #define KPF_SWAPBACKED 14 | ||
92 | #define KPF_COMPOUND_HEAD 15 | ||
93 | #define KPF_COMPOUND_TAIL 16 | ||
94 | #define KPF_HUGE 17 | ||
95 | #define KPF_UNEVICTABLE 18 | ||
96 | #define KPF_NOPAGE 20 | ||
97 | |||
98 | /* kernel hacking assistances | ||
99 | * WARNING: subject to change, never rely on them! | ||
100 | */ | ||
101 | #define KPF_RESERVED 32 | ||
102 | #define KPF_MLOCKED 33 | ||
103 | #define KPF_MAPPEDTODISK 34 | ||
104 | #define KPF_PRIVATE 35 | ||
105 | #define KPF_PRIVATE_2 36 | ||
106 | #define KPF_OWNER_PRIVATE 37 | ||
107 | #define KPF_ARCH 38 | ||
108 | #define KPF_UNCACHED 39 | ||
109 | |||
110 | static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) | ||
111 | { | ||
112 | return ((kflags >> kbit) & 1) << ubit; | ||
113 | } | ||
82 | 114 | ||
83 | #define kpf_copy_bit(flags, dstpos, srcpos) (((flags >> srcpos) & 1) << dstpos) | 115 | static u64 get_uflags(struct page *page) |
116 | { | ||
117 | u64 k; | ||
118 | u64 u; | ||
119 | |||
120 | /* | ||
121 | * pseudo flag: KPF_NOPAGE | ||
122 | * it differentiates a memory hole from a page with no flags | ||
123 | */ | ||
124 | if (!page) | ||
125 | return 1 << KPF_NOPAGE; | ||
126 | |||
127 | k = page->flags; | ||
128 | u = 0; | ||
129 | |||
130 | /* | ||
131 | * pseudo flags for the well known (anonymous) memory mapped pages | ||
132 | * | ||
133 | * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the | ||
134 | * simple test in page_mapped() is not enough. | ||
135 | */ | ||
136 | if (!PageSlab(page) && page_mapped(page)) | ||
137 | u |= 1 << KPF_MMAP; | ||
138 | if (PageAnon(page)) | ||
139 | u |= 1 << KPF_ANON; | ||
140 | |||
141 | /* | ||
142 | * compound pages: export both head/tail info | ||
143 | * they together define a compound page's start/end pos and order | ||
144 | */ | ||
145 | if (PageHead(page)) | ||
146 | u |= 1 << KPF_COMPOUND_HEAD; | ||
147 | if (PageTail(page)) | ||
148 | u |= 1 << KPF_COMPOUND_TAIL; | ||
149 | if (PageHuge(page)) | ||
150 | u |= 1 << KPF_HUGE; | ||
151 | |||
152 | u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked); | ||
153 | |||
154 | /* | ||
155 | * Caveats on high order pages: | ||
156 | * PG_buddy will only be set on the head page; SLUB/SLQB do the same | ||
157 | * for PG_slab; SLOB won't set PG_slab at all on compound pages. | ||
158 | */ | ||
159 | u |= kpf_copy_bit(k, KPF_SLAB, PG_slab); | ||
160 | u |= kpf_copy_bit(k, KPF_BUDDY, PG_buddy); | ||
161 | |||
162 | u |= kpf_copy_bit(k, KPF_ERROR, PG_error); | ||
163 | u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty); | ||
164 | u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate); | ||
165 | u |= kpf_copy_bit(k, KPF_WRITEBACK, PG_writeback); | ||
166 | |||
167 | u |= kpf_copy_bit(k, KPF_LRU, PG_lru); | ||
168 | u |= kpf_copy_bit(k, KPF_REFERENCED, PG_referenced); | ||
169 | u |= kpf_copy_bit(k, KPF_ACTIVE, PG_active); | ||
170 | u |= kpf_copy_bit(k, KPF_RECLAIM, PG_reclaim); | ||
171 | |||
172 | u |= kpf_copy_bit(k, KPF_SWAPCACHE, PG_swapcache); | ||
173 | u |= kpf_copy_bit(k, KPF_SWAPBACKED, PG_swapbacked); | ||
174 | |||
175 | u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable); | ||
176 | u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked); | ||
177 | |||
178 | #ifdef CONFIG_IA64_UNCACHED_ALLOCATOR | ||
179 | u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached); | ||
180 | #endif | ||
181 | |||
182 | u |= kpf_copy_bit(k, KPF_RESERVED, PG_reserved); | ||
183 | u |= kpf_copy_bit(k, KPF_MAPPEDTODISK, PG_mappedtodisk); | ||
184 | u |= kpf_copy_bit(k, KPF_PRIVATE, PG_private); | ||
185 | u |= kpf_copy_bit(k, KPF_PRIVATE_2, PG_private_2); | ||
186 | u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1); | ||
187 | u |= kpf_copy_bit(k, KPF_ARCH, PG_arch_1); | ||
188 | |||
189 | return u; | ||
190 | }; | ||
84 | 191 | ||
85 | static ssize_t kpageflags_read(struct file *file, char __user *buf, | 192 | static ssize_t kpageflags_read(struct file *file, char __user *buf, |
86 | size_t count, loff_t *ppos) | 193 | size_t count, loff_t *ppos) |
@@ -90,7 +197,6 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, | |||
90 | unsigned long src = *ppos; | 197 | unsigned long src = *ppos; |
91 | unsigned long pfn; | 198 | unsigned long pfn; |
92 | ssize_t ret = 0; | 199 | ssize_t ret = 0; |
93 | u64 kflags, uflags; | ||
94 | 200 | ||
95 | pfn = src / KPMSIZE; | 201 | pfn = src / KPMSIZE; |
96 | count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); | 202 | count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); |
@@ -98,32 +204,18 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, | |||
98 | return -EINVAL; | 204 | return -EINVAL; |
99 | 205 | ||
100 | while (count > 0) { | 206 | while (count > 0) { |
101 | ppage = NULL; | ||
102 | if (pfn_valid(pfn)) | 207 | if (pfn_valid(pfn)) |
103 | ppage = pfn_to_page(pfn); | 208 | ppage = pfn_to_page(pfn); |
104 | pfn++; | ||
105 | if (!ppage) | ||
106 | kflags = 0; | ||
107 | else | 209 | else |
108 | kflags = ppage->flags; | 210 | ppage = NULL; |
109 | 211 | ||
110 | uflags = kpf_copy_bit(kflags, KPF_LOCKED, PG_locked) | | 212 | if (put_user(get_uflags(ppage), out)) { |
111 | kpf_copy_bit(kflags, KPF_ERROR, PG_error) | | ||
112 | kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) | | ||
113 | kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) | | ||
114 | kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) | | ||
115 | kpf_copy_bit(kflags, KPF_LRU, PG_lru) | | ||
116 | kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) | | ||
117 | kpf_copy_bit(kflags, KPF_SLAB, PG_slab) | | ||
118 | kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) | | ||
119 | kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) | | ||
120 | kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy); | ||
121 | |||
122 | if (put_user(uflags, out++)) { | ||
123 | ret = -EFAULT; | 213 | ret = -EFAULT; |
124 | break; | 214 | break; |
125 | } | 215 | } |
126 | 216 | ||
217 | pfn++; | ||
218 | out++; | ||
127 | count -= KPMSIZE; | 219 | count -= KPMSIZE; |
128 | } | 220 | } |
129 | 221 | ||
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index fc6c3025befd..7ba79a54948c 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -195,20 +195,20 @@ void proc_device_tree_add_node(struct device_node *np, | |||
195 | p = fixup_name(np, de, p); | 195 | p = fixup_name(np, de, p); |
196 | 196 | ||
197 | ent = proc_mkdir(p, de); | 197 | ent = proc_mkdir(p, de); |
198 | if (ent == 0) | 198 | if (ent == NULL) |
199 | break; | 199 | break; |
200 | proc_device_tree_add_node(child, ent); | 200 | proc_device_tree_add_node(child, ent); |
201 | } | 201 | } |
202 | of_node_put(child); | 202 | of_node_put(child); |
203 | 203 | ||
204 | for (pp = np->properties; pp != 0; pp = pp->next) { | 204 | for (pp = np->properties; pp != NULL; pp = pp->next) { |
205 | p = pp->name; | 205 | p = pp->name; |
206 | 206 | ||
207 | if (duplicate_name(de, p)) | 207 | if (duplicate_name(de, p)) |
208 | p = fixup_name(np, de, p); | 208 | p = fixup_name(np, de, p); |
209 | 209 | ||
210 | ent = __proc_device_tree_add_prop(de, pp, p); | 210 | ent = __proc_device_tree_add_prop(de, pp, p); |
211 | if (ent == 0) | 211 | if (ent == NULL) |
212 | break; | 212 | break; |
213 | } | 213 | } |
214 | } | 214 | } |
@@ -221,10 +221,10 @@ void __init proc_device_tree_init(void) | |||
221 | struct device_node *root; | 221 | struct device_node *root; |
222 | 222 | ||
223 | proc_device_tree = proc_mkdir("device-tree", NULL); | 223 | proc_device_tree = proc_mkdir("device-tree", NULL); |
224 | if (proc_device_tree == 0) | 224 | if (proc_device_tree == NULL) |
225 | return; | 225 | return; |
226 | root = of_find_node_by_path("/"); | 226 | root = of_find_node_by_path("/"); |
227 | if (root == 0) { | 227 | if (root == NULL) { |
228 | printk(KERN_ERR "/proc/device-tree: can't find root\n"); | 228 | printk(KERN_ERR "/proc/device-tree: can't find root\n"); |
229 | return; | 229 | return; |
230 | } | 230 | } |
diff --git a/fs/proc/softirqs.c b/fs/proc/softirqs.c new file mode 100644 index 000000000000..1807c2419f17 --- /dev/null +++ b/fs/proc/softirqs.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/kernel_stat.h> | ||
3 | #include <linux/proc_fs.h> | ||
4 | #include <linux/seq_file.h> | ||
5 | |||
6 | /* | ||
7 | * /proc/softirqs ... display the number of softirqs | ||
8 | */ | ||
9 | static int show_softirqs(struct seq_file *p, void *v) | ||
10 | { | ||
11 | int i, j; | ||
12 | |||
13 | seq_printf(p, " "); | ||
14 | for_each_possible_cpu(i) | ||
15 | seq_printf(p, "CPU%-8d", i); | ||
16 | seq_printf(p, "\n"); | ||
17 | |||
18 | for (i = 0; i < NR_SOFTIRQS; i++) { | ||
19 | seq_printf(p, "%8s:", softirq_to_name[i]); | ||
20 | for_each_possible_cpu(j) | ||
21 | seq_printf(p, " %10u", kstat_softirqs_cpu(i, j)); | ||
22 | seq_printf(p, "\n"); | ||
23 | } | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | static int softirqs_open(struct inode *inode, struct file *file) | ||
28 | { | ||
29 | return single_open(file, show_softirqs, NULL); | ||
30 | } | ||
31 | |||
32 | static const struct file_operations proc_softirqs_operations = { | ||
33 | .open = softirqs_open, | ||
34 | .read = seq_read, | ||
35 | .llseek = seq_lseek, | ||
36 | .release = single_release, | ||
37 | }; | ||
38 | |||
39 | static int __init proc_softirqs_init(void) | ||
40 | { | ||
41 | proc_create("softirqs", 0, NULL, &proc_softirqs_operations); | ||
42 | return 0; | ||
43 | } | ||
44 | module_init(proc_softirqs_init); | ||
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 81e4eb60972e..7cc726c6d70a 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
@@ -29,6 +29,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
30 | cputime64_t guest; | 30 | cputime64_t guest; |
31 | u64 sum = 0; | 31 | u64 sum = 0; |
32 | u64 sum_softirq = 0; | ||
33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; | ||
32 | struct timespec boottime; | 34 | struct timespec boottime; |
33 | unsigned int per_irq_sum; | 35 | unsigned int per_irq_sum; |
34 | 36 | ||
@@ -53,6 +55,13 @@ static int show_stat(struct seq_file *p, void *v) | |||
53 | sum += kstat_irqs_cpu(j, i); | 55 | sum += kstat_irqs_cpu(j, i); |
54 | } | 56 | } |
55 | sum += arch_irq_stat_cpu(i); | 57 | sum += arch_irq_stat_cpu(i); |
58 | |||
59 | for (j = 0; j < NR_SOFTIRQS; j++) { | ||
60 | unsigned int softirq_stat = kstat_softirqs_cpu(j, i); | ||
61 | |||
62 | per_softirq_sums[j] += softirq_stat; | ||
63 | sum_softirq += softirq_stat; | ||
64 | } | ||
56 | } | 65 | } |
57 | sum += arch_irq_stat(); | 66 | sum += arch_irq_stat(); |
58 | 67 | ||
@@ -115,6 +124,12 @@ static int show_stat(struct seq_file *p, void *v) | |||
115 | nr_running(), | 124 | nr_running(), |
116 | nr_iowait()); | 125 | nr_iowait()); |
117 | 126 | ||
127 | seq_printf(p, "softirq %llu", (unsigned long long)sum_softirq); | ||
128 | |||
129 | for (i = 0; i < NR_SOFTIRQS; i++) | ||
130 | seq_printf(p, " %u", per_softirq_sums[i]); | ||
131 | seq_printf(p, "\n"); | ||
132 | |||
118 | return 0; | 133 | return 0; |
119 | } | 134 | } |
120 | 135 | ||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 6f61b7cc32e0..9bd8be1d235c 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -119,6 +119,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
119 | mm = mm_for_maps(priv->task); | 119 | mm = mm_for_maps(priv->task); |
120 | if (!mm) | 120 | if (!mm) |
121 | return NULL; | 121 | return NULL; |
122 | down_read(&mm->mmap_sem); | ||
122 | 123 | ||
123 | tail_vma = get_gate_vma(priv->task); | 124 | tail_vma = get_gate_vma(priv->task); |
124 | priv->tail_vma = tail_vma; | 125 | priv->tail_vma = tail_vma; |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 64a72e2e7650..8f5c05d3dbd3 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -189,6 +189,7 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
189 | priv->task = NULL; | 189 | priv->task = NULL; |
190 | return NULL; | 190 | return NULL; |
191 | } | 191 | } |
192 | down_read(&mm->mmap_sem); | ||
192 | 193 | ||
193 | /* start from the Nth VMA */ | 194 | /* start from the Nth VMA */ |
194 | for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) | 195 | for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 5edcc3f92ba7..0872afa58d39 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -166,12 +166,7 @@ static const struct file_operations proc_vmcore_operations = { | |||
166 | 166 | ||
167 | static struct vmcore* __init get_new_element(void) | 167 | static struct vmcore* __init get_new_element(void) |
168 | { | 168 | { |
169 | struct vmcore *p; | 169 | return kzalloc(sizeof(struct vmcore), GFP_KERNEL); |
170 | |||
171 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
172 | if (p) | ||
173 | memset(p, 0, sizeof(*p)); | ||
174 | return p; | ||
175 | } | 170 | } |
176 | 171 | ||
177 | static u64 __init get_vmcore_size_elf64(char *elfptr) | 172 | static u64 __init get_vmcore_size_elf64(char *elfptr) |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 607c579e5eca..38f7bd559f35 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -2042,7 +2042,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, | |||
2042 | * changes */ | 2042 | * changes */ |
2043 | invalidate_bdev(sb->s_bdev); | 2043 | invalidate_bdev(sb->s_bdev); |
2044 | } | 2044 | } |
2045 | mutex_lock(&inode->i_mutex); | ||
2046 | mutex_lock(&dqopt->dqonoff_mutex); | 2045 | mutex_lock(&dqopt->dqonoff_mutex); |
2047 | if (sb_has_quota_loaded(sb, type)) { | 2046 | if (sb_has_quota_loaded(sb, type)) { |
2048 | error = -EBUSY; | 2047 | error = -EBUSY; |
@@ -2054,9 +2053,11 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, | |||
2054 | * possible) Also nobody should write to the file - we use | 2053 | * possible) Also nobody should write to the file - we use |
2055 | * special IO operations which ignore the immutable bit. */ | 2054 | * special IO operations which ignore the immutable bit. */ |
2056 | down_write(&dqopt->dqptr_sem); | 2055 | down_write(&dqopt->dqptr_sem); |
2056 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); | ||
2057 | oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | | 2057 | oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | |
2058 | S_NOQUOTA); | 2058 | S_NOQUOTA); |
2059 | inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; | 2059 | inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; |
2060 | mutex_unlock(&inode->i_mutex); | ||
2060 | up_write(&dqopt->dqptr_sem); | 2061 | up_write(&dqopt->dqptr_sem); |
2061 | sb->dq_op->drop(inode); | 2062 | sb->dq_op->drop(inode); |
2062 | } | 2063 | } |
@@ -2080,7 +2081,6 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, | |||
2080 | goto out_file_init; | 2081 | goto out_file_init; |
2081 | } | 2082 | } |
2082 | mutex_unlock(&dqopt->dqio_mutex); | 2083 | mutex_unlock(&dqopt->dqio_mutex); |
2083 | mutex_unlock(&inode->i_mutex); | ||
2084 | spin_lock(&dq_state_lock); | 2084 | spin_lock(&dq_state_lock); |
2085 | dqopt->flags |= dquot_state_flag(flags, type); | 2085 | dqopt->flags |= dquot_state_flag(flags, type); |
2086 | spin_unlock(&dq_state_lock); | 2086 | spin_unlock(&dq_state_lock); |
@@ -2094,16 +2094,17 @@ out_file_init: | |||
2094 | dqopt->files[type] = NULL; | 2094 | dqopt->files[type] = NULL; |
2095 | iput(inode); | 2095 | iput(inode); |
2096 | out_lock: | 2096 | out_lock: |
2097 | mutex_unlock(&dqopt->dqonoff_mutex); | ||
2098 | if (oldflags != -1) { | 2097 | if (oldflags != -1) { |
2099 | down_write(&dqopt->dqptr_sem); | 2098 | down_write(&dqopt->dqptr_sem); |
2099 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA); | ||
2100 | /* Set the flags back (in the case of accidental quotaon() | 2100 | /* Set the flags back (in the case of accidental quotaon() |
2101 | * on a wrong file we don't want to mess up the flags) */ | 2101 | * on a wrong file we don't want to mess up the flags) */ |
2102 | inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE); | 2102 | inode->i_flags &= ~(S_NOATIME | S_NOQUOTA | S_IMMUTABLE); |
2103 | inode->i_flags |= oldflags; | 2103 | inode->i_flags |= oldflags; |
2104 | mutex_unlock(&inode->i_mutex); | ||
2104 | up_write(&dqopt->dqptr_sem); | 2105 | up_write(&dqopt->dqptr_sem); |
2105 | } | 2106 | } |
2106 | mutex_unlock(&inode->i_mutex); | 2107 | mutex_unlock(&dqopt->dqonoff_mutex); |
2107 | out_fmt: | 2108 | out_fmt: |
2108 | put_quota_format(fmt); | 2109 | put_quota_format(fmt); |
2109 | 2110 | ||
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index ebb2c417912c..11f0c06316de 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/ramfs.h> | 20 | #include <linux/ramfs.h> |
21 | #include <linux/pagevec.h> | 21 | #include <linux/pagevec.h> |
22 | #include <linux/mman.h> | 22 | #include <linux/mman.h> |
23 | #include <linux/sched.h> | ||
23 | 24 | ||
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | #include "internal.h" | 26 | #include "internal.h" |
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 3a6b193d8444..0ff7566c767c 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c | |||
@@ -202,9 +202,12 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) | |||
202 | return -EINVAL; | 202 | return -EINVAL; |
203 | opts->mode = option & S_IALLUGO; | 203 | opts->mode = option & S_IALLUGO; |
204 | break; | 204 | break; |
205 | default: | 205 | /* |
206 | printk(KERN_ERR "ramfs: bad mount option: %s\n", p); | 206 | * We might like to report bad mount options here; |
207 | return -EINVAL; | 207 | * but traditionally ramfs has ignored all mount options, |
208 | * and as it is used as a !CONFIG_SHMEM simple substitute | ||
209 | * for tmpfs, better continue to ignore other mount options. | ||
210 | */ | ||
208 | } | 211 | } |
209 | } | 212 | } |
210 | 213 | ||
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 4beb964a2a3e..128d3f7c8aa5 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c | |||
@@ -1270,9 +1270,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h | |||
1270 | 1270 | ||
1271 | RFALSE(ih, "PAP-12210: ih must be 0"); | 1271 | RFALSE(ih, "PAP-12210: ih must be 0"); |
1272 | 1272 | ||
1273 | if (is_direntry_le_ih | 1273 | aux_ih = B_N_PITEM_HEAD(tbS0, item_pos); |
1274 | (aux_ih = | 1274 | if (is_direntry_le_ih(aux_ih)) { |
1275 | B_N_PITEM_HEAD(tbS0, item_pos))) { | ||
1276 | /* we append to directory item */ | 1275 | /* we append to directory item */ |
1277 | 1276 | ||
1278 | int entry_count; | 1277 | int entry_count; |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 6fd0f47e45db..a14d6cd9eeda 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -1131,8 +1131,6 @@ static void init_inode(struct inode *inode, struct treepath *path) | |||
1131 | REISERFS_I(inode)->i_trans_id = 0; | 1131 | REISERFS_I(inode)->i_trans_id = 0; |
1132 | REISERFS_I(inode)->i_jl = NULL; | 1132 | REISERFS_I(inode)->i_jl = NULL; |
1133 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | 1133 | mutex_init(&(REISERFS_I(inode)->i_mmap)); |
1134 | reiserfs_init_acl_access(inode); | ||
1135 | reiserfs_init_acl_default(inode); | ||
1136 | reiserfs_init_xattr_rwsem(inode); | 1134 | reiserfs_init_xattr_rwsem(inode); |
1137 | 1135 | ||
1138 | if (stat_data_v1(ih)) { | 1136 | if (stat_data_v1(ih)) { |
@@ -1834,8 +1832,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, | |||
1834 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; | 1832 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; |
1835 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); | 1833 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); |
1836 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | 1834 | mutex_init(&(REISERFS_I(inode)->i_mmap)); |
1837 | reiserfs_init_acl_access(inode); | ||
1838 | reiserfs_init_acl_default(inode); | ||
1839 | reiserfs_init_xattr_rwsem(inode); | 1835 | reiserfs_init_xattr_rwsem(inode); |
1840 | 1836 | ||
1841 | /* key to search for correct place for new stat data */ | 1837 | /* key to search for correct place for new stat data */ |
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 77f5bb746bf0..90622200b39c 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
@@ -997,7 +997,7 @@ static int reiserfs_async_progress_wait(struct super_block *s) | |||
997 | DEFINE_WAIT(wait); | 997 | DEFINE_WAIT(wait); |
998 | struct reiserfs_journal *j = SB_JOURNAL(s); | 998 | struct reiserfs_journal *j = SB_JOURNAL(s); |
999 | if (atomic_read(&j->j_async_throttle)) | 999 | if (atomic_read(&j->j_async_throttle)) |
1000 | congestion_wait(WRITE, HZ / 10); | 1000 | congestion_wait(BLK_RW_ASYNC, HZ / 10); |
1001 | return 0; | 1001 | return 0; |
1002 | } | 1002 | } |
1003 | 1003 | ||
diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c index 381750a155f6..03d85cbf90bf 100644 --- a/fs/reiserfs/lbalance.c +++ b/fs/reiserfs/lbalance.c | |||
@@ -390,7 +390,8 @@ static void leaf_item_bottle(struct buffer_info *dest_bi, | |||
390 | 390 | ||
391 | if (last_first == FIRST_TO_LAST) { | 391 | if (last_first == FIRST_TO_LAST) { |
392 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ | 392 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ |
393 | if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num))) | 393 | ih = B_N_PITEM_HEAD(src, item_num); |
394 | if (is_direntry_le_ih(ih)) | ||
394 | leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, | 395 | leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, |
395 | item_num, 0, cpy_bytes); | 396 | item_num, 0, cpy_bytes); |
396 | else { | 397 | else { |
@@ -418,7 +419,8 @@ static void leaf_item_bottle(struct buffer_info *dest_bi, | |||
418 | } | 419 | } |
419 | } else { | 420 | } else { |
420 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ | 421 | /* if ( if item in position item_num in buffer SOURCE is directory item ) */ |
421 | if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num))) | 422 | ih = B_N_PITEM_HEAD(src, item_num); |
423 | if (is_direntry_le_ih(ih)) | ||
422 | leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST, | 424 | leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST, |
423 | item_num, | 425 | item_num, |
424 | I_ENTRY_COUNT(ih) - cpy_bytes, | 426 | I_ENTRY_COUNT(ih) - cpy_bytes, |
@@ -774,8 +776,8 @@ void leaf_delete_items(struct buffer_info *cur_bi, int last_first, | |||
774 | leaf_delete_items_entirely(cur_bi, first + 1, | 776 | leaf_delete_items_entirely(cur_bi, first + 1, |
775 | del_num - 1); | 777 | del_num - 1); |
776 | 778 | ||
777 | if (is_direntry_le_ih | 779 | ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh) - 1); |
778 | (ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh) - 1))) | 780 | if (is_direntry_le_ih(ih)) |
779 | /* the last item is directory */ | 781 | /* the last item is directory */ |
780 | /* len = numbers of directory entries in this item */ | 782 | /* len = numbers of directory entries in this item */ |
781 | len = ih_entry_count(ih); | 783 | len = ih_entry_count(ih); |
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 238e9d9b31e0..18b315d3d104 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c | |||
@@ -82,7 +82,6 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new) | |||
82 | if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { | 82 | if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) { |
83 | printk | 83 | printk |
84 | ("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); | 84 | ("reiserfs_resize: unable to allocate memory for journal bitmaps\n"); |
85 | unlock_super(s); | ||
86 | return -ENOMEM; | 85 | return -ENOMEM; |
87 | } | 86 | } |
88 | /* the new journal bitmaps are zero filled, now we copy in the bitmap | 87 | /* the new journal bitmaps are zero filled, now we copy in the bitmap |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 2969773cfc22..7adea74d6a8a 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/exportfs.h> | 24 | #include <linux/exportfs.h> |
25 | #include <linux/quotaops.h> | 25 | #include <linux/quotaops.h> |
26 | #include <linux/vfs.h> | 26 | #include <linux/vfs.h> |
27 | #include <linux/mnt_namespace.h> | ||
28 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
29 | #include <linux/namei.h> | 28 | #include <linux/namei.h> |
30 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
@@ -529,10 +528,6 @@ static void init_once(void *foo) | |||
529 | 528 | ||
530 | INIT_LIST_HEAD(&ei->i_prealloc_list); | 529 | INIT_LIST_HEAD(&ei->i_prealloc_list); |
531 | inode_init_once(&ei->vfs_inode); | 530 | inode_init_once(&ei->vfs_inode); |
532 | #ifdef CONFIG_REISERFS_FS_POSIX_ACL | ||
533 | ei->i_acl_access = NULL; | ||
534 | ei->i_acl_default = NULL; | ||
535 | #endif | ||
536 | } | 531 | } |
537 | 532 | ||
538 | static int init_inodecache(void) | 533 | static int init_inodecache(void) |
@@ -580,25 +575,6 @@ static void reiserfs_dirty_inode(struct inode *inode) | |||
580 | reiserfs_write_unlock(inode->i_sb); | 575 | reiserfs_write_unlock(inode->i_sb); |
581 | } | 576 | } |
582 | 577 | ||
583 | #ifdef CONFIG_REISERFS_FS_POSIX_ACL | ||
584 | static void reiserfs_clear_inode(struct inode *inode) | ||
585 | { | ||
586 | struct posix_acl *acl; | ||
587 | |||
588 | acl = REISERFS_I(inode)->i_acl_access; | ||
589 | if (acl && !IS_ERR(acl)) | ||
590 | posix_acl_release(acl); | ||
591 | REISERFS_I(inode)->i_acl_access = NULL; | ||
592 | |||
593 | acl = REISERFS_I(inode)->i_acl_default; | ||
594 | if (acl && !IS_ERR(acl)) | ||
595 | posix_acl_release(acl); | ||
596 | REISERFS_I(inode)->i_acl_default = NULL; | ||
597 | } | ||
598 | #else | ||
599 | #define reiserfs_clear_inode NULL | ||
600 | #endif | ||
601 | |||
602 | #ifdef CONFIG_QUOTA | 578 | #ifdef CONFIG_QUOTA |
603 | static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, | 579 | static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, |
604 | size_t, loff_t); | 580 | size_t, loff_t); |
@@ -612,7 +588,6 @@ static const struct super_operations reiserfs_sops = { | |||
612 | .write_inode = reiserfs_write_inode, | 588 | .write_inode = reiserfs_write_inode, |
613 | .dirty_inode = reiserfs_dirty_inode, | 589 | .dirty_inode = reiserfs_dirty_inode, |
614 | .delete_inode = reiserfs_delete_inode, | 590 | .delete_inode = reiserfs_delete_inode, |
615 | .clear_inode = reiserfs_clear_inode, | ||
616 | .put_super = reiserfs_put_super, | 591 | .put_super = reiserfs_put_super, |
617 | .write_super = reiserfs_write_super, | 592 | .write_super = reiserfs_write_super, |
618 | .sync_fs = reiserfs_sync_fs, | 593 | .sync_fs = reiserfs_sync_fs, |
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index f3d47d856848..6925b835a43b 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <linux/reiserfs_acl.h> | 46 | #include <linux/reiserfs_acl.h> |
47 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
48 | #include <net/checksum.h> | 48 | #include <net/checksum.h> |
49 | #include <linux/smp_lock.h> | ||
50 | #include <linux/stat.h> | 49 | #include <linux/stat.h> |
51 | #include <linux/quotaops.h> | 50 | #include <linux/quotaops.h> |
52 | 51 | ||
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index c303c426fe2b..35d6e672a279 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c | |||
@@ -188,29 +188,6 @@ static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size) | |||
188 | return ERR_PTR(-EINVAL); | 188 | return ERR_PTR(-EINVAL); |
189 | } | 189 | } |
190 | 190 | ||
191 | static inline void iset_acl(struct inode *inode, struct posix_acl **i_acl, | ||
192 | struct posix_acl *acl) | ||
193 | { | ||
194 | spin_lock(&inode->i_lock); | ||
195 | if (*i_acl != ERR_PTR(-ENODATA)) | ||
196 | posix_acl_release(*i_acl); | ||
197 | *i_acl = posix_acl_dup(acl); | ||
198 | spin_unlock(&inode->i_lock); | ||
199 | } | ||
200 | |||
201 | static inline struct posix_acl *iget_acl(struct inode *inode, | ||
202 | struct posix_acl **i_acl) | ||
203 | { | ||
204 | struct posix_acl *acl = ERR_PTR(-ENODATA); | ||
205 | |||
206 | spin_lock(&inode->i_lock); | ||
207 | if (*i_acl != ERR_PTR(-ENODATA)) | ||
208 | acl = posix_acl_dup(*i_acl); | ||
209 | spin_unlock(&inode->i_lock); | ||
210 | |||
211 | return acl; | ||
212 | } | ||
213 | |||
214 | /* | 191 | /* |
215 | * Inode operation get_posix_acl(). | 192 | * Inode operation get_posix_acl(). |
216 | * | 193 | * |
@@ -220,34 +197,29 @@ static inline struct posix_acl *iget_acl(struct inode *inode, | |||
220 | struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | 197 | struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) |
221 | { | 198 | { |
222 | char *name, *value; | 199 | char *name, *value; |
223 | struct posix_acl *acl, **p_acl; | 200 | struct posix_acl *acl; |
224 | int size; | 201 | int size; |
225 | int retval; | 202 | int retval; |
226 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | 203 | |
204 | acl = get_cached_acl(inode, type); | ||
205 | if (acl != ACL_NOT_CACHED) | ||
206 | return acl; | ||
227 | 207 | ||
228 | switch (type) { | 208 | switch (type) { |
229 | case ACL_TYPE_ACCESS: | 209 | case ACL_TYPE_ACCESS: |
230 | name = POSIX_ACL_XATTR_ACCESS; | 210 | name = POSIX_ACL_XATTR_ACCESS; |
231 | p_acl = &reiserfs_i->i_acl_access; | ||
232 | break; | 211 | break; |
233 | case ACL_TYPE_DEFAULT: | 212 | case ACL_TYPE_DEFAULT: |
234 | name = POSIX_ACL_XATTR_DEFAULT; | 213 | name = POSIX_ACL_XATTR_DEFAULT; |
235 | p_acl = &reiserfs_i->i_acl_default; | ||
236 | break; | 214 | break; |
237 | default: | 215 | default: |
238 | return ERR_PTR(-EINVAL); | 216 | BUG(); |
239 | } | 217 | } |
240 | 218 | ||
241 | acl = iget_acl(inode, p_acl); | ||
242 | if (acl && !IS_ERR(acl)) | ||
243 | return acl; | ||
244 | else if (PTR_ERR(acl) == -ENODATA) | ||
245 | return NULL; | ||
246 | |||
247 | size = reiserfs_xattr_get(inode, name, NULL, 0); | 219 | size = reiserfs_xattr_get(inode, name, NULL, 0); |
248 | if (size < 0) { | 220 | if (size < 0) { |
249 | if (size == -ENODATA || size == -ENOSYS) { | 221 | if (size == -ENODATA || size == -ENOSYS) { |
250 | *p_acl = ERR_PTR(-ENODATA); | 222 | set_cached_acl(inode, type, NULL); |
251 | return NULL; | 223 | return NULL; |
252 | } | 224 | } |
253 | return ERR_PTR(size); | 225 | return ERR_PTR(size); |
@@ -262,14 +234,13 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type) | |||
262 | /* This shouldn't actually happen as it should have | 234 | /* This shouldn't actually happen as it should have |
263 | been caught above.. but just in case */ | 235 | been caught above.. but just in case */ |
264 | acl = NULL; | 236 | acl = NULL; |
265 | *p_acl = ERR_PTR(-ENODATA); | ||
266 | } else if (retval < 0) { | 237 | } else if (retval < 0) { |
267 | acl = ERR_PTR(retval); | 238 | acl = ERR_PTR(retval); |
268 | } else { | 239 | } else { |
269 | acl = posix_acl_from_disk(value, retval); | 240 | acl = posix_acl_from_disk(value, retval); |
270 | if (!IS_ERR(acl)) | ||
271 | iset_acl(inode, p_acl, acl); | ||
272 | } | 241 | } |
242 | if (!IS_ERR(acl)) | ||
243 | set_cached_acl(inode, type, acl); | ||
273 | 244 | ||
274 | kfree(value); | 245 | kfree(value); |
275 | return acl; | 246 | return acl; |
@@ -287,10 +258,8 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
287 | { | 258 | { |
288 | char *name; | 259 | char *name; |
289 | void *value = NULL; | 260 | void *value = NULL; |
290 | struct posix_acl **p_acl; | ||
291 | size_t size = 0; | 261 | size_t size = 0; |
292 | int error; | 262 | int error; |
293 | struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode); | ||
294 | 263 | ||
295 | if (S_ISLNK(inode->i_mode)) | 264 | if (S_ISLNK(inode->i_mode)) |
296 | return -EOPNOTSUPP; | 265 | return -EOPNOTSUPP; |
@@ -298,7 +267,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
298 | switch (type) { | 267 | switch (type) { |
299 | case ACL_TYPE_ACCESS: | 268 | case ACL_TYPE_ACCESS: |
300 | name = POSIX_ACL_XATTR_ACCESS; | 269 | name = POSIX_ACL_XATTR_ACCESS; |
301 | p_acl = &reiserfs_i->i_acl_access; | ||
302 | if (acl) { | 270 | if (acl) { |
303 | mode_t mode = inode->i_mode; | 271 | mode_t mode = inode->i_mode; |
304 | error = posix_acl_equiv_mode(acl, &mode); | 272 | error = posix_acl_equiv_mode(acl, &mode); |
@@ -313,7 +281,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
313 | break; | 281 | break; |
314 | case ACL_TYPE_DEFAULT: | 282 | case ACL_TYPE_DEFAULT: |
315 | name = POSIX_ACL_XATTR_DEFAULT; | 283 | name = POSIX_ACL_XATTR_DEFAULT; |
316 | p_acl = &reiserfs_i->i_acl_default; | ||
317 | if (!S_ISDIR(inode->i_mode)) | 284 | if (!S_ISDIR(inode->i_mode)) |
318 | return acl ? -EACCES : 0; | 285 | return acl ? -EACCES : 0; |
319 | break; | 286 | break; |
@@ -346,7 +313,7 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode, | |||
346 | kfree(value); | 313 | kfree(value); |
347 | 314 | ||
348 | if (!error) | 315 | if (!error) |
349 | iset_acl(inode, p_acl, acl); | 316 | set_cached_acl(inode, type, acl); |
350 | 317 | ||
351 | return error; | 318 | return error; |
352 | } | 319 | } |
@@ -379,11 +346,8 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th, | |||
379 | } | 346 | } |
380 | 347 | ||
381 | acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); | 348 | acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT); |
382 | if (IS_ERR(acl)) { | 349 | if (IS_ERR(acl)) |
383 | if (PTR_ERR(acl) == -ENODATA) | ||
384 | goto apply_umask; | ||
385 | return PTR_ERR(acl); | 350 | return PTR_ERR(acl); |
386 | } | ||
387 | 351 | ||
388 | if (acl) { | 352 | if (acl) { |
389 | struct posix_acl *acl_copy; | 353 | struct posix_acl *acl_copy; |
diff --git a/fs/select.c b/fs/select.c index 0fe0e1469df3..d870237e42c7 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -168,7 +168,7 @@ static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p) | |||
168 | return table->entry++; | 168 | return table->entry++; |
169 | } | 169 | } |
170 | 170 | ||
171 | static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | 171 | static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) |
172 | { | 172 | { |
173 | struct poll_wqueues *pwq = wait->private; | 173 | struct poll_wqueues *pwq = wait->private; |
174 | DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); | 174 | DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); |
@@ -194,6 +194,16 @@ static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | |||
194 | return default_wake_function(&dummy_wait, mode, sync, key); | 194 | return default_wake_function(&dummy_wait, mode, sync, key); |
195 | } | 195 | } |
196 | 196 | ||
197 | static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) | ||
198 | { | ||
199 | struct poll_table_entry *entry; | ||
200 | |||
201 | entry = container_of(wait, struct poll_table_entry, wait); | ||
202 | if (key && !((unsigned long)key & entry->key)) | ||
203 | return 0; | ||
204 | return __pollwake(wait, mode, sync, key); | ||
205 | } | ||
206 | |||
197 | /* Add a new entry */ | 207 | /* Add a new entry */ |
198 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | 208 | static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, |
199 | poll_table *p) | 209 | poll_table *p) |
@@ -205,6 +215,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
205 | get_file(filp); | 215 | get_file(filp); |
206 | entry->filp = filp; | 216 | entry->filp = filp; |
207 | entry->wait_address = wait_address; | 217 | entry->wait_address = wait_address; |
218 | entry->key = p->key; | ||
208 | init_waitqueue_func_entry(&entry->wait, pollwake); | 219 | init_waitqueue_func_entry(&entry->wait, pollwake); |
209 | entry->wait.private = pwq; | 220 | entry->wait.private = pwq; |
210 | add_wait_queue(wait_address, &entry->wait); | 221 | add_wait_queue(wait_address, &entry->wait); |
@@ -362,6 +373,18 @@ get_max: | |||
362 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) | 373 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) |
363 | #define POLLEX_SET (POLLPRI) | 374 | #define POLLEX_SET (POLLPRI) |
364 | 375 | ||
376 | static inline void wait_key_set(poll_table *wait, unsigned long in, | ||
377 | unsigned long out, unsigned long bit) | ||
378 | { | ||
379 | if (wait) { | ||
380 | wait->key = POLLEX_SET; | ||
381 | if (in & bit) | ||
382 | wait->key |= POLLIN_SET; | ||
383 | if (out & bit) | ||
384 | wait->key |= POLLOUT_SET; | ||
385 | } | ||
386 | } | ||
387 | |||
365 | int do_select(int n, fd_set_bits *fds, struct timespec *end_time) | 388 | int do_select(int n, fd_set_bits *fds, struct timespec *end_time) |
366 | { | 389 | { |
367 | ktime_t expire, *to = NULL; | 390 | ktime_t expire, *to = NULL; |
@@ -418,20 +441,25 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) | |||
418 | if (file) { | 441 | if (file) { |
419 | f_op = file->f_op; | 442 | f_op = file->f_op; |
420 | mask = DEFAULT_POLLMASK; | 443 | mask = DEFAULT_POLLMASK; |
421 | if (f_op && f_op->poll) | 444 | if (f_op && f_op->poll) { |
422 | mask = (*f_op->poll)(file, retval ? NULL : wait); | 445 | wait_key_set(wait, in, out, bit); |
446 | mask = (*f_op->poll)(file, wait); | ||
447 | } | ||
423 | fput_light(file, fput_needed); | 448 | fput_light(file, fput_needed); |
424 | if ((mask & POLLIN_SET) && (in & bit)) { | 449 | if ((mask & POLLIN_SET) && (in & bit)) { |
425 | res_in |= bit; | 450 | res_in |= bit; |
426 | retval++; | 451 | retval++; |
452 | wait = NULL; | ||
427 | } | 453 | } |
428 | if ((mask & POLLOUT_SET) && (out & bit)) { | 454 | if ((mask & POLLOUT_SET) && (out & bit)) { |
429 | res_out |= bit; | 455 | res_out |= bit; |
430 | retval++; | 456 | retval++; |
457 | wait = NULL; | ||
431 | } | 458 | } |
432 | if ((mask & POLLEX_SET) && (ex & bit)) { | 459 | if ((mask & POLLEX_SET) && (ex & bit)) { |
433 | res_ex |= bit; | 460 | res_ex |= bit; |
434 | retval++; | 461 | retval++; |
462 | wait = NULL; | ||
435 | } | 463 | } |
436 | } | 464 | } |
437 | } | 465 | } |
@@ -685,8 +713,12 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) | |||
685 | mask = POLLNVAL; | 713 | mask = POLLNVAL; |
686 | if (file != NULL) { | 714 | if (file != NULL) { |
687 | mask = DEFAULT_POLLMASK; | 715 | mask = DEFAULT_POLLMASK; |
688 | if (file->f_op && file->f_op->poll) | 716 | if (file->f_op && file->f_op->poll) { |
717 | if (pwait) | ||
718 | pwait->key = pollfd->events | | ||
719 | POLLERR | POLLHUP; | ||
689 | mask = file->f_op->poll(file, pwait); | 720 | mask = file->f_op->poll(file, pwait); |
721 | } | ||
690 | /* Mask out unneeded events. */ | 722 | /* Mask out unneeded events. */ |
691 | mask &= pollfd->events | POLLERR | POLLHUP; | 723 | mask &= pollfd->events | POLLERR | POLLHUP; |
692 | fput_light(file, fput_needed); | 724 | fput_light(file, fput_needed); |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 7f40f30c55c5..6c959275f2d0 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
@@ -640,6 +640,26 @@ int seq_puts(struct seq_file *m, const char *s) | |||
640 | } | 640 | } |
641 | EXPORT_SYMBOL(seq_puts); | 641 | EXPORT_SYMBOL(seq_puts); |
642 | 642 | ||
643 | /** | ||
644 | * seq_write - write arbitrary data to buffer | ||
645 | * @seq: seq_file identifying the buffer to which data should be written | ||
646 | * @data: data address | ||
647 | * @len: number of bytes | ||
648 | * | ||
649 | * Return 0 on success, non-zero otherwise. | ||
650 | */ | ||
651 | int seq_write(struct seq_file *seq, const void *data, size_t len) | ||
652 | { | ||
653 | if (seq->count + len < seq->size) { | ||
654 | memcpy(seq->buf + seq->count, data, len); | ||
655 | seq->count += len; | ||
656 | return 0; | ||
657 | } | ||
658 | seq->count = seq->size; | ||
659 | return -1; | ||
660 | } | ||
661 | EXPORT_SYMBOL(seq_write); | ||
662 | |||
643 | struct list_head *seq_list_start(struct list_head *head, loff_t pos) | 663 | struct list_head *seq_list_start(struct list_head *head, loff_t pos) |
644 | { | 664 | { |
645 | struct list_head *lh; | 665 | struct list_head *lh; |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 3b52770f46ff..cb5fc57e370b 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
31 | #include <linux/vfs.h> | 31 | #include <linux/vfs.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/smp_lock.h> | ||
33 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
34 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
35 | #include <linux/init.h> | 36 | #include <linux/init.h> |
diff --git a/fs/super.c b/fs/super.c index 83b47416d006..2761d3e22ed9 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -545,24 +545,18 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
545 | if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { | 545 | if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { |
546 | if (force) | 546 | if (force) |
547 | mark_files_ro(sb); | 547 | mark_files_ro(sb); |
548 | else if (!fs_may_remount_ro(sb)) { | 548 | else if (!fs_may_remount_ro(sb)) |
549 | unlock_kernel(); | ||
550 | return -EBUSY; | 549 | return -EBUSY; |
551 | } | ||
552 | retval = vfs_dq_off(sb, 1); | 550 | retval = vfs_dq_off(sb, 1); |
553 | if (retval < 0 && retval != -ENOSYS) { | 551 | if (retval < 0 && retval != -ENOSYS) |
554 | unlock_kernel(); | ||
555 | return -EBUSY; | 552 | return -EBUSY; |
556 | } | ||
557 | } | 553 | } |
558 | remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); | 554 | remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); |
559 | 555 | ||
560 | if (sb->s_op->remount_fs) { | 556 | if (sb->s_op->remount_fs) { |
561 | retval = sb->s_op->remount_fs(sb, &flags, data); | 557 | retval = sb->s_op->remount_fs(sb, &flags, data); |
562 | if (retval) { | 558 | if (retval) |
563 | unlock_kernel(); | ||
564 | return retval; | 559 | return retval; |
565 | } | ||
566 | } | 560 | } |
567 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); | 561 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); |
568 | if (remount_rw) | 562 | if (remount_rw) |
@@ -614,6 +608,7 @@ void emergency_remount(void) | |||
614 | 608 | ||
615 | static DEFINE_IDA(unnamed_dev_ida); | 609 | static DEFINE_IDA(unnamed_dev_ida); |
616 | static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ | 610 | static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ |
611 | static int unnamed_dev_start = 0; /* don't bother trying below it */ | ||
617 | 612 | ||
618 | int set_anon_super(struct super_block *s, void *data) | 613 | int set_anon_super(struct super_block *s, void *data) |
619 | { | 614 | { |
@@ -624,7 +619,9 @@ int set_anon_super(struct super_block *s, void *data) | |||
624 | if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0) | 619 | if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0) |
625 | return -ENOMEM; | 620 | return -ENOMEM; |
626 | spin_lock(&unnamed_dev_lock); | 621 | spin_lock(&unnamed_dev_lock); |
627 | error = ida_get_new(&unnamed_dev_ida, &dev); | 622 | error = ida_get_new_above(&unnamed_dev_ida, unnamed_dev_start, &dev); |
623 | if (!error) | ||
624 | unnamed_dev_start = dev + 1; | ||
628 | spin_unlock(&unnamed_dev_lock); | 625 | spin_unlock(&unnamed_dev_lock); |
629 | if (error == -EAGAIN) | 626 | if (error == -EAGAIN) |
630 | /* We raced and lost with another CPU. */ | 627 | /* We raced and lost with another CPU. */ |
@@ -635,6 +632,8 @@ int set_anon_super(struct super_block *s, void *data) | |||
635 | if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { | 632 | if ((dev & MAX_ID_MASK) == (1 << MINORBITS)) { |
636 | spin_lock(&unnamed_dev_lock); | 633 | spin_lock(&unnamed_dev_lock); |
637 | ida_remove(&unnamed_dev_ida, dev); | 634 | ida_remove(&unnamed_dev_ida, dev); |
635 | if (unnamed_dev_start > dev) | ||
636 | unnamed_dev_start = dev; | ||
638 | spin_unlock(&unnamed_dev_lock); | 637 | spin_unlock(&unnamed_dev_lock); |
639 | return -EMFILE; | 638 | return -EMFILE; |
640 | } | 639 | } |
@@ -651,6 +650,8 @@ void kill_anon_super(struct super_block *sb) | |||
651 | generic_shutdown_super(sb); | 650 | generic_shutdown_super(sb); |
652 | spin_lock(&unnamed_dev_lock); | 651 | spin_lock(&unnamed_dev_lock); |
653 | ida_remove(&unnamed_dev_ida, slot); | 652 | ida_remove(&unnamed_dev_ida, slot); |
653 | if (slot < unnamed_dev_start) | ||
654 | unnamed_dev_start = slot; | ||
654 | spin_unlock(&unnamed_dev_lock); | 655 | spin_unlock(&unnamed_dev_lock); |
655 | } | 656 | } |
656 | 657 | ||
@@ -112,8 +112,13 @@ restart: | |||
112 | mutex_unlock(&mutex); | 112 | mutex_unlock(&mutex); |
113 | } | 113 | } |
114 | 114 | ||
115 | /* | ||
116 | * sync everything. Start out by waking pdflush, because that writes back | ||
117 | * all queues in parallel. | ||
118 | */ | ||
115 | SYSCALL_DEFINE0(sync) | 119 | SYSCALL_DEFINE0(sync) |
116 | { | 120 | { |
121 | wakeup_pdflush(0); | ||
117 | sync_filesystems(0); | 122 | sync_filesystems(0); |
118 | sync_filesystems(1); | 123 | sync_filesystems(1); |
119 | if (unlikely(laptop_mode)) | 124 | if (unlikely(laptop_mode)) |
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c index 9345806c8853..2524714bece1 100644 --- a/fs/sysfs/bin.c +++ b/fs/sysfs/bin.c | |||
@@ -171,6 +171,7 @@ static ssize_t write(struct file *file, const char __user *userbuf, | |||
171 | if (count > 0) | 171 | if (count > 0) |
172 | *off = offs + count; | 172 | *off = offs + count; |
173 | 173 | ||
174 | kfree(temp); | ||
174 | return count; | 175 | return count; |
175 | } | 176 | } |
176 | 177 | ||
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index d88d0fac9fa5..14f2d71ea3ce 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -939,8 +939,10 @@ again: | |||
939 | /* Remove from old parent's list and insert into new parent's list. */ | 939 | /* Remove from old parent's list and insert into new parent's list. */ |
940 | sysfs_unlink_sibling(sd); | 940 | sysfs_unlink_sibling(sd); |
941 | sysfs_get(new_parent_sd); | 941 | sysfs_get(new_parent_sd); |
942 | drop_nlink(old_parent->d_inode); | ||
942 | sysfs_put(sd->s_parent); | 943 | sysfs_put(sd->s_parent); |
943 | sd->s_parent = new_parent_sd; | 944 | sd->s_parent = new_parent_sd; |
945 | inc_nlink(new_parent->d_inode); | ||
944 | sysfs_link_sibling(sd); | 946 | sysfs_link_sibling(sd); |
945 | 947 | ||
946 | out_unlock: | 948 | out_unlock: |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index a3ba217fbe74..1d897ad808e0 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -192,8 +192,11 @@ static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
192 | { | 192 | { |
193 | int error = -ENOMEM; | 193 | int error = -ENOMEM; |
194 | unsigned long page = get_zeroed_page(GFP_KERNEL); | 194 | unsigned long page = get_zeroed_page(GFP_KERNEL); |
195 | if (page) | 195 | if (page) { |
196 | error = sysfs_getlink(dentry, (char *) page); | 196 | error = sysfs_getlink(dentry, (char *) page); |
197 | if (error < 0) | ||
198 | free_page((unsigned long)page); | ||
199 | } | ||
197 | nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); | 200 | nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); |
198 | return NULL; | 201 | return NULL; |
199 | } | 202 | } |
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index c7798079e644..4e50286a4cc3 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c | |||
@@ -15,13 +15,13 @@ | |||
15 | 15 | ||
16 | #include <linux/pagemap.h> | 16 | #include <linux/pagemap.h> |
17 | #include <linux/highmem.h> | 17 | #include <linux/highmem.h> |
18 | #include <linux/smp_lock.h> | ||
19 | #include <linux/swap.h> | 18 | #include <linux/swap.h> |
20 | #include "sysv.h" | 19 | #include "sysv.h" |
21 | 20 | ||
22 | static int sysv_readdir(struct file *, void *, filldir_t); | 21 | static int sysv_readdir(struct file *, void *, filldir_t); |
23 | 22 | ||
24 | const struct file_operations sysv_dir_operations = { | 23 | const struct file_operations sysv_dir_operations = { |
24 | .llseek = generic_file_llseek, | ||
25 | .read = generic_read_dir, | 25 | .read = generic_read_dir, |
26 | .readdir = sysv_readdir, | 26 | .readdir = sysv_readdir, |
27 | .fsync = simple_fsync, | 27 | .fsync = simple_fsync, |
@@ -74,8 +74,6 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
74 | unsigned long n = pos >> PAGE_CACHE_SHIFT; | 74 | unsigned long n = pos >> PAGE_CACHE_SHIFT; |
75 | unsigned long npages = dir_pages(inode); | 75 | unsigned long npages = dir_pages(inode); |
76 | 76 | ||
77 | lock_kernel(); | ||
78 | |||
79 | pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1); | 77 | pos = (pos + SYSV_DIRSIZE-1) & ~(SYSV_DIRSIZE-1); |
80 | if (pos >= inode->i_size) | 78 | if (pos >= inode->i_size) |
81 | goto done; | 79 | goto done; |
@@ -113,7 +111,6 @@ static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
113 | 111 | ||
114 | done: | 112 | done: |
115 | filp->f_pos = ((loff_t)n << PAGE_CACHE_SHIFT) | offset; | 113 | filp->f_pos = ((loff_t)n << PAGE_CACHE_SHIFT) | offset; |
116 | unlock_kernel(); | ||
117 | return 0; | 114 | return 0; |
118 | } | 115 | } |
119 | 116 | ||
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 479923456a54..9824743832a7 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c | |||
@@ -21,7 +21,6 @@ | |||
21 | * the superblock. | 21 | * the superblock. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/smp_lock.h> | ||
25 | #include <linux/highuid.h> | 24 | #include <linux/highuid.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -37,7 +36,6 @@ static int sysv_sync_fs(struct super_block *sb, int wait) | |||
37 | unsigned long time = get_seconds(), old_time; | 36 | unsigned long time = get_seconds(), old_time; |
38 | 37 | ||
39 | lock_super(sb); | 38 | lock_super(sb); |
40 | lock_kernel(); | ||
41 | 39 | ||
42 | /* | 40 | /* |
43 | * If we are going to write out the super block, | 41 | * If we are going to write out the super block, |
@@ -52,7 +50,6 @@ static int sysv_sync_fs(struct super_block *sb, int wait) | |||
52 | mark_buffer_dirty(sbi->s_bh2); | 50 | mark_buffer_dirty(sbi->s_bh2); |
53 | } | 51 | } |
54 | 52 | ||
55 | unlock_kernel(); | ||
56 | unlock_super(sb); | 53 | unlock_super(sb); |
57 | 54 | ||
58 | return 0; | 55 | return 0; |
@@ -82,8 +79,6 @@ static void sysv_put_super(struct super_block *sb) | |||
82 | { | 79 | { |
83 | struct sysv_sb_info *sbi = SYSV_SB(sb); | 80 | struct sysv_sb_info *sbi = SYSV_SB(sb); |
84 | 81 | ||
85 | lock_kernel(); | ||
86 | |||
87 | if (sb->s_dirt) | 82 | if (sb->s_dirt) |
88 | sysv_write_super(sb); | 83 | sysv_write_super(sb); |
89 | 84 | ||
@@ -99,8 +94,6 @@ static void sysv_put_super(struct super_block *sb) | |||
99 | brelse(sbi->s_bh2); | 94 | brelse(sbi->s_bh2); |
100 | 95 | ||
101 | kfree(sbi); | 96 | kfree(sbi); |
102 | |||
103 | unlock_kernel(); | ||
104 | } | 97 | } |
105 | 98 | ||
106 | static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf) | 99 | static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf) |
@@ -275,7 +268,6 @@ int sysv_write_inode(struct inode *inode, int wait) | |||
275 | return -EIO; | 268 | return -EIO; |
276 | } | 269 | } |
277 | 270 | ||
278 | lock_kernel(); | ||
279 | raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode); | 271 | raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode); |
280 | raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid)); | 272 | raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid)); |
281 | raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid)); | 273 | raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid)); |
@@ -291,7 +283,6 @@ int sysv_write_inode(struct inode *inode, int wait) | |||
291 | for (block = 0; block < 10+1+1+1; block++) | 283 | for (block = 0; block < 10+1+1+1; block++) |
292 | write3byte(sbi, (u8 *)&si->i_data[block], | 284 | write3byte(sbi, (u8 *)&si->i_data[block], |
293 | &raw_inode->i_data[3*block]); | 285 | &raw_inode->i_data[3*block]); |
294 | unlock_kernel(); | ||
295 | mark_buffer_dirty(bh); | 286 | mark_buffer_dirty(bh); |
296 | if (wait) { | 287 | if (wait) { |
297 | sync_dirty_buffer(bh); | 288 | sync_dirty_buffer(bh); |
@@ -315,9 +306,7 @@ static void sysv_delete_inode(struct inode *inode) | |||
315 | truncate_inode_pages(&inode->i_data, 0); | 306 | truncate_inode_pages(&inode->i_data, 0); |
316 | inode->i_size = 0; | 307 | inode->i_size = 0; |
317 | sysv_truncate(inode); | 308 | sysv_truncate(inode); |
318 | lock_kernel(); | ||
319 | sysv_free_inode(inode); | 309 | sysv_free_inode(inode); |
320 | unlock_kernel(); | ||
321 | } | 310 | } |
322 | 311 | ||
323 | static struct kmem_cache *sysv_inode_cachep; | 312 | static struct kmem_cache *sysv_inode_cachep; |
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c index af1914462f02..eaf6d891d46f 100644 --- a/fs/ubifs/budget.c +++ b/fs/ubifs/budget.c | |||
@@ -91,7 +91,6 @@ static int shrink_liability(struct ubifs_info *c, int nr_to_write) | |||
91 | return nr_written; | 91 | return nr_written; |
92 | } | 92 | } |
93 | 93 | ||
94 | |||
95 | /** | 94 | /** |
96 | * run_gc - run garbage collector. | 95 | * run_gc - run garbage collector. |
97 | * @c: UBIFS file-system description object | 96 | * @c: UBIFS file-system description object |
@@ -628,7 +627,7 @@ void ubifs_convert_page_budget(struct ubifs_info *c) | |||
628 | * | 627 | * |
629 | * This function releases budget corresponding to a dirty inode. It is usually | 628 | * This function releases budget corresponding to a dirty inode. It is usually |
630 | * called when after the inode has been written to the media and marked as | 629 | * called when after the inode has been written to the media and marked as |
631 | * clean. | 630 | * clean. It also causes the "no space" flags to be cleared. |
632 | */ | 631 | */ |
633 | void ubifs_release_dirty_inode_budget(struct ubifs_info *c, | 632 | void ubifs_release_dirty_inode_budget(struct ubifs_info *c, |
634 | struct ubifs_inode *ui) | 633 | struct ubifs_inode *ui) |
@@ -636,6 +635,7 @@ void ubifs_release_dirty_inode_budget(struct ubifs_info *c, | |||
636 | struct ubifs_budget_req req; | 635 | struct ubifs_budget_req req; |
637 | 636 | ||
638 | memset(&req, 0, sizeof(struct ubifs_budget_req)); | 637 | memset(&req, 0, sizeof(struct ubifs_budget_req)); |
638 | /* The "no space" flags will be cleared because dd_growth is > 0 */ | ||
639 | req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8); | 639 | req.dd_growth = c->inode_budget + ALIGN(ui->data_len, 8); |
640 | ubifs_release_budget(c, &req); | 640 | ubifs_release_budget(c, &req); |
641 | } | 641 | } |
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index f55d523c52bb..552fb0111fff 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c | |||
@@ -528,6 +528,25 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, | |||
528 | inode->i_nlink, dir->i_ino); | 528 | inode->i_nlink, dir->i_ino); |
529 | ubifs_assert(mutex_is_locked(&dir->i_mutex)); | 529 | ubifs_assert(mutex_is_locked(&dir->i_mutex)); |
530 | ubifs_assert(mutex_is_locked(&inode->i_mutex)); | 530 | ubifs_assert(mutex_is_locked(&inode->i_mutex)); |
531 | |||
532 | /* | ||
533 | * Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing | ||
534 | * otherwise has the potential to corrupt the orphan inode list. | ||
535 | * | ||
536 | * Indeed, consider a scenario when 'vfs_link(dirA/fileA)' and | ||
537 | * 'vfs_unlink(dirA/fileA, dirB/fileB)' race. 'vfs_link()' does not | ||
538 | * lock 'dirA->i_mutex', so this is possible. Both of the functions | ||
539 | * lock 'fileA->i_mutex' though. Suppose 'vfs_unlink()' wins, and takes | ||
540 | * 'fileA->i_mutex' mutex first. Suppose 'fileA->i_nlink' is 1. In this | ||
541 | * case 'ubifs_unlink()' will drop the last reference, and put 'inodeA' | ||
542 | * to the list of orphans. After this, 'vfs_link()' will link | ||
543 | * 'dirB/fileB' to 'inodeA'. This is a problem because, for example, | ||
544 | * the subsequent 'vfs_unlink(dirB/fileB)' will add the same inode | ||
545 | * to the list of orphans. | ||
546 | */ | ||
547 | if (inode->i_nlink == 0) | ||
548 | return -ENOENT; | ||
549 | |||
531 | err = dbg_check_synced_i_size(inode); | 550 | err = dbg_check_synced_i_size(inode); |
532 | if (err) | 551 | if (err) |
533 | return err; | 552 | return err; |
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c index e8e632a1dcdf..762a7d6cec73 100644 --- a/fs/ubifs/io.c +++ b/fs/ubifs/io.c | |||
@@ -293,13 +293,15 @@ void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last) | |||
293 | * | 293 | * |
294 | * This function is called when the write-buffer timer expires. | 294 | * This function is called when the write-buffer timer expires. |
295 | */ | 295 | */ |
296 | static void wbuf_timer_callback_nolock(unsigned long data) | 296 | static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer) |
297 | { | 297 | { |
298 | struct ubifs_wbuf *wbuf = (struct ubifs_wbuf *)data; | 298 | struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer); |
299 | 299 | ||
300 | dbg_io("jhead %d", wbuf->jhead); | ||
300 | wbuf->need_sync = 1; | 301 | wbuf->need_sync = 1; |
301 | wbuf->c->need_wbuf_sync = 1; | 302 | wbuf->c->need_wbuf_sync = 1; |
302 | ubifs_wake_up_bgt(wbuf->c); | 303 | ubifs_wake_up_bgt(wbuf->c); |
304 | return HRTIMER_NORESTART; | ||
303 | } | 305 | } |
304 | 306 | ||
305 | /** | 307 | /** |
@@ -308,13 +310,16 @@ static void wbuf_timer_callback_nolock(unsigned long data) | |||
308 | */ | 310 | */ |
309 | static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) | 311 | static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) |
310 | { | 312 | { |
311 | ubifs_assert(!timer_pending(&wbuf->timer)); | 313 | ubifs_assert(!hrtimer_active(&wbuf->timer)); |
312 | 314 | ||
313 | if (!wbuf->timeout) | 315 | if (wbuf->no_timer) |
314 | return; | 316 | return; |
315 | 317 | dbg_io("set timer for jhead %d, %llu-%llu millisecs", wbuf->jhead, | |
316 | wbuf->timer.expires = jiffies + wbuf->timeout; | 318 | div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC), |
317 | add_timer(&wbuf->timer); | 319 | div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta, |
320 | USEC_PER_SEC)); | ||
321 | hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta, | ||
322 | HRTIMER_MODE_REL); | ||
318 | } | 323 | } |
319 | 324 | ||
320 | /** | 325 | /** |
@@ -323,13 +328,10 @@ static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) | |||
323 | */ | 328 | */ |
324 | static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) | 329 | static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf) |
325 | { | 330 | { |
326 | /* | 331 | if (wbuf->no_timer) |
327 | * If the syncer is waiting for the lock (from the background thread's | 332 | return; |
328 | * context) and another task is changing write-buffer then the syncing | ||
329 | * should be canceled. | ||
330 | */ | ||
331 | wbuf->need_sync = 0; | 333 | wbuf->need_sync = 0; |
332 | del_timer(&wbuf->timer); | 334 | hrtimer_cancel(&wbuf->timer); |
333 | } | 335 | } |
334 | 336 | ||
335 | /** | 337 | /** |
@@ -349,8 +351,8 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) | |||
349 | /* Write-buffer is empty or not seeked */ | 351 | /* Write-buffer is empty or not seeked */ |
350 | return 0; | 352 | return 0; |
351 | 353 | ||
352 | dbg_io("LEB %d:%d, %d bytes", | 354 | dbg_io("LEB %d:%d, %d bytes, jhead %d", |
353 | wbuf->lnum, wbuf->offs, wbuf->used); | 355 | wbuf->lnum, wbuf->offs, wbuf->used, wbuf->jhead); |
354 | ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); | 356 | ubifs_assert(!(c->vfs_sb->s_flags & MS_RDONLY)); |
355 | ubifs_assert(!(wbuf->avail & 7)); | 357 | ubifs_assert(!(wbuf->avail & 7)); |
356 | ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); | 358 | ubifs_assert(wbuf->offs + c->min_io_size <= c->leb_size); |
@@ -390,7 +392,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf) | |||
390 | * @offs: logical eraseblock offset to seek to | 392 | * @offs: logical eraseblock offset to seek to |
391 | * @dtype: data type | 393 | * @dtype: data type |
392 | * | 394 | * |
393 | * This function targets the write buffer to logical eraseblock @lnum:@offs. | 395 | * This function targets the write-buffer to logical eraseblock @lnum:@offs. |
394 | * The write-buffer is synchronized if it is not empty. Returns zero in case of | 396 | * The write-buffer is synchronized if it is not empty. Returns zero in case of |
395 | * success and a negative error code in case of failure. | 397 | * success and a negative error code in case of failure. |
396 | */ | 398 | */ |
@@ -399,7 +401,7 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs, | |||
399 | { | 401 | { |
400 | const struct ubifs_info *c = wbuf->c; | 402 | const struct ubifs_info *c = wbuf->c; |
401 | 403 | ||
402 | dbg_io("LEB %d:%d", lnum, offs); | 404 | dbg_io("LEB %d:%d, jhead %d", lnum, offs, wbuf->jhead); |
403 | ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); | 405 | ubifs_assert(lnum >= 0 && lnum < c->leb_cnt); |
404 | ubifs_assert(offs >= 0 && offs <= c->leb_size); | 406 | ubifs_assert(offs >= 0 && offs <= c->leb_size); |
405 | ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); | 407 | ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7)); |
@@ -506,9 +508,9 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) | |||
506 | struct ubifs_info *c = wbuf->c; | 508 | struct ubifs_info *c = wbuf->c; |
507 | int err, written, n, aligned_len = ALIGN(len, 8), offs; | 509 | int err, written, n, aligned_len = ALIGN(len, 8), offs; |
508 | 510 | ||
509 | dbg_io("%d bytes (%s) to wbuf at LEB %d:%d", len, | 511 | dbg_io("%d bytes (%s) to jhead %d wbuf at LEB %d:%d", len, |
510 | dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->lnum, | 512 | dbg_ntype(((struct ubifs_ch *)buf)->node_type), wbuf->jhead, |
511 | wbuf->offs + wbuf->used); | 513 | wbuf->lnum, wbuf->offs + wbuf->used); |
512 | ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt); | 514 | ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt); |
513 | ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0); | 515 | ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0); |
514 | ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size); | 516 | ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size); |
@@ -533,8 +535,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) | |||
533 | memcpy(wbuf->buf + wbuf->used, buf, len); | 535 | memcpy(wbuf->buf + wbuf->used, buf, len); |
534 | 536 | ||
535 | if (aligned_len == wbuf->avail) { | 537 | if (aligned_len == wbuf->avail) { |
536 | dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, | 538 | dbg_io("flush jhead %d wbuf to LEB %d:%d", |
537 | wbuf->offs); | 539 | wbuf->jhead, wbuf->lnum, wbuf->offs); |
538 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, | 540 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, |
539 | wbuf->offs, c->min_io_size, | 541 | wbuf->offs, c->min_io_size, |
540 | wbuf->dtype); | 542 | wbuf->dtype); |
@@ -562,7 +564,8 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len) | |||
562 | * minimal I/O unit. We have to fill and flush write-buffer and switch | 564 | * minimal I/O unit. We have to fill and flush write-buffer and switch |
563 | * to the next min. I/O unit. | 565 | * to the next min. I/O unit. |
564 | */ | 566 | */ |
565 | dbg_io("flush wbuf to LEB %d:%d", wbuf->lnum, wbuf->offs); | 567 | dbg_io("flush jhead %d wbuf to LEB %d:%d", |
568 | wbuf->jhead, wbuf->lnum, wbuf->offs); | ||
566 | memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); | 569 | memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail); |
567 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, | 570 | err = ubi_leb_write(c->ubi, wbuf->lnum, wbuf->buf, wbuf->offs, |
568 | c->min_io_size, wbuf->dtype); | 571 | c->min_io_size, wbuf->dtype); |
@@ -695,7 +698,8 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, | |||
695 | int err, rlen, overlap; | 698 | int err, rlen, overlap; |
696 | struct ubifs_ch *ch = buf; | 699 | struct ubifs_ch *ch = buf; |
697 | 700 | ||
698 | dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len); | 701 | dbg_io("LEB %d:%d, %s, length %d, jhead %d", lnum, offs, |
702 | dbg_ntype(type), len, wbuf->jhead); | ||
699 | ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); | 703 | ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0); |
700 | ubifs_assert(!(offs & 7) && offs < c->leb_size); | 704 | ubifs_assert(!(offs & 7) && offs < c->leb_size); |
701 | ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); | 705 | ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT); |
@@ -819,7 +823,7 @@ out: | |||
819 | * @c: UBIFS file-system description object | 823 | * @c: UBIFS file-system description object |
820 | * @wbuf: write-buffer to initialize | 824 | * @wbuf: write-buffer to initialize |
821 | * | 825 | * |
822 | * This function initializes write buffer. Returns zero in case of success | 826 | * This function initializes write-buffer. Returns zero in case of success |
823 | * %-ENOMEM in case of failure. | 827 | * %-ENOMEM in case of failure. |
824 | */ | 828 | */ |
825 | int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) | 829 | int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) |
@@ -845,20 +849,21 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf) | |||
845 | wbuf->sync_callback = NULL; | 849 | wbuf->sync_callback = NULL; |
846 | mutex_init(&wbuf->io_mutex); | 850 | mutex_init(&wbuf->io_mutex); |
847 | spin_lock_init(&wbuf->lock); | 851 | spin_lock_init(&wbuf->lock); |
848 | |||
849 | wbuf->c = c; | 852 | wbuf->c = c; |
850 | init_timer(&wbuf->timer); | ||
851 | wbuf->timer.function = wbuf_timer_callback_nolock; | ||
852 | wbuf->timer.data = (unsigned long)wbuf; | ||
853 | wbuf->timeout = DEFAULT_WBUF_TIMEOUT; | ||
854 | wbuf->next_ino = 0; | 853 | wbuf->next_ino = 0; |
855 | 854 | ||
855 | hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
856 | wbuf->timer.function = wbuf_timer_callback_nolock; | ||
857 | wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0); | ||
858 | wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT; | ||
859 | wbuf->delta *= 1000000000ULL; | ||
860 | ubifs_assert(wbuf->delta <= ULONG_MAX); | ||
856 | return 0; | 861 | return 0; |
857 | } | 862 | } |
858 | 863 | ||
859 | /** | 864 | /** |
860 | * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. | 865 | * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array. |
861 | * @wbuf: the write-buffer whereto add | 866 | * @wbuf: the write-buffer where to add |
862 | * @inum: the inode number | 867 | * @inum: the inode number |
863 | * | 868 | * |
864 | * This function adds an inode number to the inode array of the write-buffer. | 869 | * This function adds an inode number to the inode array of the write-buffer. |
diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 6db7a6be6c97..8aacd64957a2 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c | |||
@@ -25,7 +25,6 @@ | |||
25 | /* This file implements EXT2-compatible extended attribute ioctl() calls */ | 25 | /* This file implements EXT2-compatible extended attribute ioctl() calls */ |
26 | 26 | ||
27 | #include <linux/compat.h> | 27 | #include <linux/compat.h> |
28 | #include <linux/smp_lock.h> | ||
29 | #include <linux/mount.h> | 28 | #include <linux/mount.h> |
30 | #include "ubifs.h" | 29 | #include "ubifs.h" |
31 | 30 | ||
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 10662975d2ef..e5f6cf8a1155 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c | |||
@@ -53,6 +53,25 @@ static int is_empty(void *buf, int len) | |||
53 | } | 53 | } |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * first_non_ff - find offset of the first non-0xff byte. | ||
57 | * @buf: buffer to search in | ||
58 | * @len: length of buffer | ||
59 | * | ||
60 | * This function returns offset of the first non-0xff byte in @buf or %-1 if | ||
61 | * the buffer contains only 0xff bytes. | ||
62 | */ | ||
63 | static int first_non_ff(void *buf, int len) | ||
64 | { | ||
65 | uint8_t *p = buf; | ||
66 | int i; | ||
67 | |||
68 | for (i = 0; i < len; i++) | ||
69 | if (*p++ != 0xff) | ||
70 | return i; | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | /** | ||
56 | * get_master_node - get the last valid master node allowing for corruption. | 75 | * get_master_node - get the last valid master node allowing for corruption. |
57 | * @c: UBIFS file-system description object | 76 | * @c: UBIFS file-system description object |
58 | * @lnum: LEB number | 77 | * @lnum: LEB number |
@@ -343,43 +362,21 @@ int ubifs_write_rcvrd_mst_node(struct ubifs_info *c) | |||
343 | * | 362 | * |
344 | * This function returns %1 if @offs was in the last write to the LEB whose data | 363 | * This function returns %1 if @offs was in the last write to the LEB whose data |
345 | * is in @buf, otherwise %0 is returned. The determination is made by checking | 364 | * is in @buf, otherwise %0 is returned. The determination is made by checking |
346 | * for subsequent empty space starting from the next min_io_size boundary (or a | 365 | * for subsequent empty space starting from the next @c->min_io_size boundary. |
347 | * bit less than the common header size if min_io_size is one). | ||
348 | */ | 366 | */ |
349 | static int is_last_write(const struct ubifs_info *c, void *buf, int offs) | 367 | static int is_last_write(const struct ubifs_info *c, void *buf, int offs) |
350 | { | 368 | { |
351 | int empty_offs; | 369 | int empty_offs, check_len; |
352 | int check_len; | ||
353 | uint8_t *p; | 370 | uint8_t *p; |
354 | 371 | ||
355 | if (c->min_io_size == 1) { | ||
356 | check_len = c->leb_size - offs; | ||
357 | p = buf + check_len; | ||
358 | for (; check_len > 0; check_len--) | ||
359 | if (*--p != 0xff) | ||
360 | break; | ||
361 | /* | ||
362 | * 'check_len' is the size of the corruption which cannot be | ||
363 | * more than the size of 1 node if it was caused by an unclean | ||
364 | * unmount. | ||
365 | */ | ||
366 | if (check_len > UBIFS_MAX_NODE_SZ) | ||
367 | return 0; | ||
368 | return 1; | ||
369 | } | ||
370 | |||
371 | /* | 372 | /* |
372 | * Round up to the next c->min_io_size boundary i.e. 'offs' is in the | 373 | * Round up to the next @c->min_io_size boundary i.e. @offs is in the |
373 | * last wbuf written. After that should be empty space. | 374 | * last wbuf written. After that should be empty space. |
374 | */ | 375 | */ |
375 | empty_offs = ALIGN(offs + 1, c->min_io_size); | 376 | empty_offs = ALIGN(offs + 1, c->min_io_size); |
376 | check_len = c->leb_size - empty_offs; | 377 | check_len = c->leb_size - empty_offs; |
377 | p = buf + empty_offs - offs; | 378 | p = buf + empty_offs - offs; |
378 | 379 | return is_empty(p, check_len); | |
379 | for (; check_len > 0; check_len--) | ||
380 | if (*p++ != 0xff) | ||
381 | return 0; | ||
382 | return 1; | ||
383 | } | 380 | } |
384 | 381 | ||
385 | /** | 382 | /** |
@@ -392,7 +389,7 @@ static int is_last_write(const struct ubifs_info *c, void *buf, int offs) | |||
392 | * | 389 | * |
393 | * This function pads up to the next min_io_size boundary (if there is one) and | 390 | * This function pads up to the next min_io_size boundary (if there is one) and |
394 | * sets empty space to all 0xff. @buf, @offs and @len are updated to the next | 391 | * sets empty space to all 0xff. @buf, @offs and @len are updated to the next |
395 | * min_io_size boundary (if there is one). | 392 | * @c->min_io_size boundary. |
396 | */ | 393 | */ |
397 | static void clean_buf(const struct ubifs_info *c, void **buf, int lnum, | 394 | static void clean_buf(const struct ubifs_info *c, void **buf, int lnum, |
398 | int *offs, int *len) | 395 | int *offs, int *len) |
@@ -402,11 +399,6 @@ static void clean_buf(const struct ubifs_info *c, void **buf, int lnum, | |||
402 | lnum = lnum; | 399 | lnum = lnum; |
403 | dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs); | 400 | dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs); |
404 | 401 | ||
405 | if (c->min_io_size == 1) { | ||
406 | memset(*buf, 0xff, c->leb_size - *offs); | ||
407 | return; | ||
408 | } | ||
409 | |||
410 | ubifs_assert(!(*offs & 7)); | 402 | ubifs_assert(!(*offs & 7)); |
411 | empty_offs = ALIGN(*offs, c->min_io_size); | 403 | empty_offs = ALIGN(*offs, c->min_io_size); |
412 | pad_len = empty_offs - *offs; | 404 | pad_len = empty_offs - *offs; |
@@ -566,8 +558,8 @@ static int drop_incomplete_group(struct ubifs_scan_leb *sleb, int *offs) | |||
566 | * | 558 | * |
567 | * This function does a scan of a LEB, but caters for errors that might have | 559 | * This function does a scan of a LEB, but caters for errors that might have |
568 | * been caused by the unclean unmount from which we are attempting to recover. | 560 | * been caused by the unclean unmount from which we are attempting to recover. |
569 | * | 561 | * Returns %0 in case of success, %-EUCLEAN if an unrecoverable corruption is |
570 | * This function returns %0 on success and a negative error code on failure. | 562 | * found, and a negative error code in case of failure. |
571 | */ | 563 | */ |
572 | struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, | 564 | struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, |
573 | int offs, void *sbuf, int grouped) | 565 | int offs, void *sbuf, int grouped) |
@@ -666,7 +658,8 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, | |||
666 | goto corrupted; | 658 | goto corrupted; |
667 | default: | 659 | default: |
668 | dbg_err("unknown"); | 660 | dbg_err("unknown"); |
669 | goto corrupted; | 661 | err = -EINVAL; |
662 | goto error; | ||
670 | } | 663 | } |
671 | } | 664 | } |
672 | 665 | ||
@@ -675,8 +668,13 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, | |||
675 | clean_buf(c, &buf, lnum, &offs, &len); | 668 | clean_buf(c, &buf, lnum, &offs, &len); |
676 | need_clean = 1; | 669 | need_clean = 1; |
677 | } else { | 670 | } else { |
678 | ubifs_err("corrupt empty space at LEB %d:%d", | 671 | int corruption = first_non_ff(buf, len); |
679 | lnum, offs); | 672 | |
673 | ubifs_err("corrupt empty space LEB %d:%d, corruption " | ||
674 | "starts at %d", lnum, offs, corruption); | ||
675 | /* Make sure we dump interesting non-0xFF data */ | ||
676 | offs = corruption; | ||
677 | buf += corruption; | ||
680 | goto corrupted; | 678 | goto corrupted; |
681 | } | 679 | } |
682 | } | 680 | } |
@@ -836,7 +834,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum, | |||
836 | static int recover_head(const struct ubifs_info *c, int lnum, int offs, | 834 | static int recover_head(const struct ubifs_info *c, int lnum, int offs, |
837 | void *sbuf) | 835 | void *sbuf) |
838 | { | 836 | { |
839 | int len, err, need_clean = 0; | 837 | int len, err; |
840 | 838 | ||
841 | if (c->min_io_size > 1) | 839 | if (c->min_io_size > 1) |
842 | len = c->min_io_size; | 840 | len = c->min_io_size; |
@@ -850,19 +848,7 @@ static int recover_head(const struct ubifs_info *c, int lnum, int offs, | |||
850 | 848 | ||
851 | /* Read at the head location and check it is empty flash */ | 849 | /* Read at the head location and check it is empty flash */ |
852 | err = ubi_read(c->ubi, lnum, sbuf, offs, len); | 850 | err = ubi_read(c->ubi, lnum, sbuf, offs, len); |
853 | if (err) | 851 | if (err || !is_empty(sbuf, len)) { |
854 | need_clean = 1; | ||
855 | else { | ||
856 | uint8_t *p = sbuf; | ||
857 | |||
858 | while (len--) | ||
859 | if (*p++ != 0xff) { | ||
860 | need_clean = 1; | ||
861 | break; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | if (need_clean) { | ||
866 | dbg_rcvry("cleaning head at %d:%d", lnum, offs); | 852 | dbg_rcvry("cleaning head at %d:%d", lnum, offs); |
867 | if (offs == 0) | 853 | if (offs == 0) |
868 | return ubifs_leb_unmap(c, lnum); | 854 | return ubifs_leb_unmap(c, lnum); |
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c index 11cc80125a49..2970500f32df 100644 --- a/fs/ubifs/replay.c +++ b/fs/ubifs/replay.c | |||
@@ -837,9 +837,10 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) | |||
837 | 837 | ||
838 | dbg_mnt("replay log LEB %d:%d", lnum, offs); | 838 | dbg_mnt("replay log LEB %d:%d", lnum, offs); |
839 | sleb = ubifs_scan(c, lnum, offs, sbuf); | 839 | sleb = ubifs_scan(c, lnum, offs, sbuf); |
840 | if (IS_ERR(sleb)) { | 840 | if (IS_ERR(sleb) ) { |
841 | if (c->need_recovery) | 841 | if (PTR_ERR(sleb) != -EUCLEAN || !c->need_recovery) |
842 | sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); | 842 | return PTR_ERR(sleb); |
843 | sleb = ubifs_recover_log_leb(c, lnum, offs, sbuf); | ||
843 | if (IS_ERR(sleb)) | 844 | if (IS_ERR(sleb)) |
844 | return PTR_ERR(sleb); | 845 | return PTR_ERR(sleb); |
845 | } | 846 | } |
@@ -957,7 +958,7 @@ out: | |||
957 | return err; | 958 | return err; |
958 | 959 | ||
959 | out_dump: | 960 | out_dump: |
960 | ubifs_err("log error detected while replying the log at LEB %d:%d", | 961 | ubifs_err("log error detected while replaying the log at LEB %d:%d", |
961 | lnum, offs + snod->offs); | 962 | lnum, offs + snod->offs); |
962 | dbg_dump_node(c, snod->node); | 963 | dbg_dump_node(c, snod->node); |
963 | ubifs_scan_destroy(sleb); | 964 | ubifs_scan_destroy(sleb); |
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c index 0ed82479b44b..892ebfee4fe5 100644 --- a/fs/ubifs/scan.c +++ b/fs/ubifs/scan.c | |||
@@ -238,12 +238,12 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, | |||
238 | { | 238 | { |
239 | int len; | 239 | int len; |
240 | 240 | ||
241 | ubifs_err("corrupted data at LEB %d:%d", lnum, offs); | 241 | ubifs_err("corruption at LEB %d:%d", lnum, offs); |
242 | if (dbg_failure_mode) | 242 | if (dbg_failure_mode) |
243 | return; | 243 | return; |
244 | len = c->leb_size - offs; | 244 | len = c->leb_size - offs; |
245 | if (len > 4096) | 245 | if (len > 8192) |
246 | len = 4096; | 246 | len = 8192; |
247 | dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs); | 247 | dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs); |
248 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); | 248 | print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1); |
249 | } | 249 | } |
@@ -256,7 +256,9 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs, | |||
256 | * @sbuf: scan buffer (must be c->leb_size) | 256 | * @sbuf: scan buffer (must be c->leb_size) |
257 | * | 257 | * |
258 | * This function scans LEB number @lnum and returns complete information about | 258 | * This function scans LEB number @lnum and returns complete information about |
259 | * its contents. Returns an error code in case of failure. | 259 | * its contents. Returns the scaned information in case of success and, |
260 | * %-EUCLEAN if the LEB neads recovery, and other negative error codes in case | ||
261 | * of failure. | ||
260 | */ | 262 | */ |
261 | struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | 263 | struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, |
262 | int offs, void *sbuf) | 264 | int offs, void *sbuf) |
@@ -279,7 +281,6 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | |||
279 | cond_resched(); | 281 | cond_resched(); |
280 | 282 | ||
281 | ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0); | 283 | ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0); |
282 | |||
283 | if (ret > 0) { | 284 | if (ret > 0) { |
284 | /* Padding bytes or a valid padding node */ | 285 | /* Padding bytes or a valid padding node */ |
285 | offs += ret; | 286 | offs += ret; |
@@ -304,7 +305,8 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | |||
304 | goto corrupted; | 305 | goto corrupted; |
305 | default: | 306 | default: |
306 | dbg_err("unknown"); | 307 | dbg_err("unknown"); |
307 | goto corrupted; | 308 | err = -EINVAL; |
309 | goto error; | ||
308 | } | 310 | } |
309 | 311 | ||
310 | err = ubifs_add_snod(c, sleb, buf, offs); | 312 | err = ubifs_add_snod(c, sleb, buf, offs); |
@@ -317,8 +319,10 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum, | |||
317 | len -= node_len; | 319 | len -= node_len; |
318 | } | 320 | } |
319 | 321 | ||
320 | if (offs % c->min_io_size) | 322 | if (offs % c->min_io_size) { |
321 | goto corrupted; | 323 | ubifs_err("empty space starts at non-aligned offset %d", offs); |
324 | goto corrupted;; | ||
325 | } | ||
322 | 326 | ||
323 | ubifs_end_scan(c, sleb, lnum, offs); | 327 | ubifs_end_scan(c, sleb, lnum, offs); |
324 | 328 | ||
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 3589eab02a2f..26d2e0d80465 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
@@ -361,6 +361,11 @@ static void ubifs_delete_inode(struct inode *inode) | |||
361 | out: | 361 | out: |
362 | if (ui->dirty) | 362 | if (ui->dirty) |
363 | ubifs_release_dirty_inode_budget(c, ui); | 363 | ubifs_release_dirty_inode_budget(c, ui); |
364 | else { | ||
365 | /* We've deleted something - clean the "no space" flags */ | ||
366 | c->nospace = c->nospace_rp = 0; | ||
367 | smp_wmb(); | ||
368 | } | ||
364 | clear_inode(inode); | 369 | clear_inode(inode); |
365 | } | 370 | } |
366 | 371 | ||
@@ -792,7 +797,7 @@ static int alloc_wbufs(struct ubifs_info *c) | |||
792 | * does not need to be synchronized by timer. | 797 | * does not need to be synchronized by timer. |
793 | */ | 798 | */ |
794 | c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; | 799 | c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM; |
795 | c->jheads[GCHD].wbuf.timeout = 0; | 800 | c->jheads[GCHD].wbuf.no_timer = 1; |
796 | 801 | ||
797 | return 0; | 802 | return 0; |
798 | } | 803 | } |
@@ -933,6 +938,27 @@ static const match_table_t tokens = { | |||
933 | }; | 938 | }; |
934 | 939 | ||
935 | /** | 940 | /** |
941 | * parse_standard_option - parse a standard mount option. | ||
942 | * @option: the option to parse | ||
943 | * | ||
944 | * Normally, standard mount options like "sync" are passed to file-systems as | ||
945 | * flags. However, when a "rootflags=" kernel boot parameter is used, they may | ||
946 | * be present in the options string. This function tries to deal with this | ||
947 | * situation and parse standard options. Returns 0 if the option was not | ||
948 | * recognized, and the corresponding integer flag if it was. | ||
949 | * | ||
950 | * UBIFS is only interested in the "sync" option, so do not check for anything | ||
951 | * else. | ||
952 | */ | ||
953 | static int parse_standard_option(const char *option) | ||
954 | { | ||
955 | ubifs_msg("parse %s", option); | ||
956 | if (!strcmp(option, "sync")) | ||
957 | return MS_SYNCHRONOUS; | ||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | /** | ||
936 | * ubifs_parse_options - parse mount parameters. | 962 | * ubifs_parse_options - parse mount parameters. |
937 | * @c: UBIFS file-system description object | 963 | * @c: UBIFS file-system description object |
938 | * @options: parameters to parse | 964 | * @options: parameters to parse |
@@ -960,7 +986,7 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, | |||
960 | switch (token) { | 986 | switch (token) { |
961 | /* | 987 | /* |
962 | * %Opt_fast_unmount and %Opt_norm_unmount options are ignored. | 988 | * %Opt_fast_unmount and %Opt_norm_unmount options are ignored. |
963 | * We accepte them in order to be backware-compatible. But this | 989 | * We accept them in order to be backward-compatible. But this |
964 | * should be removed at some point. | 990 | * should be removed at some point. |
965 | */ | 991 | */ |
966 | case Opt_fast_unmount: | 992 | case Opt_fast_unmount: |
@@ -1008,9 +1034,19 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, | |||
1008 | break; | 1034 | break; |
1009 | } | 1035 | } |
1010 | default: | 1036 | default: |
1011 | ubifs_err("unrecognized mount option \"%s\" " | 1037 | { |
1012 | "or missing value", p); | 1038 | unsigned long flag; |
1013 | return -EINVAL; | 1039 | struct super_block *sb = c->vfs_sb; |
1040 | |||
1041 | flag = parse_standard_option(p); | ||
1042 | if (!flag) { | ||
1043 | ubifs_err("unrecognized mount option \"%s\" " | ||
1044 | "or missing value", p); | ||
1045 | return -EINVAL; | ||
1046 | } | ||
1047 | sb->s_flags |= flag; | ||
1048 | break; | ||
1049 | } | ||
1014 | } | 1050 | } |
1015 | } | 1051 | } |
1016 | 1052 | ||
@@ -1180,6 +1216,7 @@ static int mount_ubifs(struct ubifs_info *c) | |||
1180 | if (!ubifs_compr_present(c->default_compr)) { | 1216 | if (!ubifs_compr_present(c->default_compr)) { |
1181 | ubifs_err("'compressor \"%s\" is not compiled in", | 1217 | ubifs_err("'compressor \"%s\" is not compiled in", |
1182 | ubifs_compr_name(c->default_compr)); | 1218 | ubifs_compr_name(c->default_compr)); |
1219 | err = -ENOTSUPP; | ||
1183 | goto out_free; | 1220 | goto out_free; |
1184 | } | 1221 | } |
1185 | 1222 | ||
@@ -1250,6 +1287,9 @@ static int mount_ubifs(struct ubifs_info *c) | |||
1250 | if (err) | 1287 | if (err) |
1251 | goto out_journal; | 1288 | goto out_journal; |
1252 | 1289 | ||
1290 | /* Calculate 'min_idx_lebs' after journal replay */ | ||
1291 | c->min_idx_lebs = ubifs_calc_min_idx_lebs(c); | ||
1292 | |||
1253 | err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only); | 1293 | err = ubifs_mount_orphans(c, c->need_recovery, mounted_read_only); |
1254 | if (err) | 1294 | if (err) |
1255 | goto out_orphans; | 1295 | goto out_orphans; |
@@ -1656,7 +1696,7 @@ static void ubifs_remount_ro(struct ubifs_info *c) | |||
1656 | 1696 | ||
1657 | for (i = 0; i < c->jhead_cnt; i++) { | 1697 | for (i = 0; i < c->jhead_cnt; i++) { |
1658 | ubifs_wbuf_sync(&c->jheads[i].wbuf); | 1698 | ubifs_wbuf_sync(&c->jheads[i].wbuf); |
1659 | del_timer_sync(&c->jheads[i].wbuf.timer); | 1699 | hrtimer_cancel(&c->jheads[i].wbuf.timer); |
1660 | } | 1700 | } |
1661 | 1701 | ||
1662 | c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); | 1702 | c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); |
@@ -1717,10 +1757,8 @@ static void ubifs_put_super(struct super_block *sb) | |||
1717 | 1757 | ||
1718 | /* Synchronize write-buffers */ | 1758 | /* Synchronize write-buffers */ |
1719 | if (c->jheads) | 1759 | if (c->jheads) |
1720 | for (i = 0; i < c->jhead_cnt; i++) { | 1760 | for (i = 0; i < c->jhead_cnt; i++) |
1721 | ubifs_wbuf_sync(&c->jheads[i].wbuf); | 1761 | ubifs_wbuf_sync(&c->jheads[i].wbuf); |
1722 | del_timer_sync(&c->jheads[i].wbuf.timer); | ||
1723 | } | ||
1724 | 1762 | ||
1725 | /* | 1763 | /* |
1726 | * On fatal errors c->ro_media is set to 1, in which case we do | 1764 | * On fatal errors c->ro_media is set to 1, in which case we do |
@@ -1911,6 +1949,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
1911 | INIT_LIST_HEAD(&c->orph_list); | 1949 | INIT_LIST_HEAD(&c->orph_list); |
1912 | INIT_LIST_HEAD(&c->orph_new); | 1950 | INIT_LIST_HEAD(&c->orph_new); |
1913 | 1951 | ||
1952 | c->vfs_sb = sb; | ||
1914 | c->highest_inum = UBIFS_FIRST_INO; | 1953 | c->highest_inum = UBIFS_FIRST_INO; |
1915 | c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; | 1954 | c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; |
1916 | 1955 | ||
@@ -1937,18 +1976,19 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) | |||
1937 | err = bdi_init(&c->bdi); | 1976 | err = bdi_init(&c->bdi); |
1938 | if (err) | 1977 | if (err) |
1939 | goto out_close; | 1978 | goto out_close; |
1979 | err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d", | ||
1980 | c->vi.ubi_num, c->vi.vol_id); | ||
1981 | if (err) | ||
1982 | goto out_bdi; | ||
1940 | 1983 | ||
1941 | err = ubifs_parse_options(c, data, 0); | 1984 | err = ubifs_parse_options(c, data, 0); |
1942 | if (err) | 1985 | if (err) |
1943 | goto out_bdi; | 1986 | goto out_bdi; |
1944 | 1987 | ||
1945 | c->vfs_sb = sb; | ||
1946 | |||
1947 | sb->s_fs_info = c; | 1988 | sb->s_fs_info = c; |
1948 | sb->s_magic = UBIFS_SUPER_MAGIC; | 1989 | sb->s_magic = UBIFS_SUPER_MAGIC; |
1949 | sb->s_blocksize = UBIFS_BLOCK_SIZE; | 1990 | sb->s_blocksize = UBIFS_BLOCK_SIZE; |
1950 | sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT; | 1991 | sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT; |
1951 | sb->s_dev = c->vi.cdev; | ||
1952 | sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c); | 1992 | sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c); |
1953 | if (c->max_inode_sz > MAX_LFS_FILESIZE) | 1993 | if (c->max_inode_sz > MAX_LFS_FILESIZE) |
1954 | sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; | 1994 | sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; |
@@ -1993,16 +2033,9 @@ out_free: | |||
1993 | static int sb_test(struct super_block *sb, void *data) | 2033 | static int sb_test(struct super_block *sb, void *data) |
1994 | { | 2034 | { |
1995 | dev_t *dev = data; | 2035 | dev_t *dev = data; |
2036 | struct ubifs_info *c = sb->s_fs_info; | ||
1996 | 2037 | ||
1997 | return sb->s_dev == *dev; | 2038 | return c->vi.cdev == *dev; |
1998 | } | ||
1999 | |||
2000 | static int sb_set(struct super_block *sb, void *data) | ||
2001 | { | ||
2002 | dev_t *dev = data; | ||
2003 | |||
2004 | sb->s_dev = *dev; | ||
2005 | return 0; | ||
2006 | } | 2039 | } |
2007 | 2040 | ||
2008 | static int ubifs_get_sb(struct file_system_type *fs_type, int flags, | 2041 | static int ubifs_get_sb(struct file_system_type *fs_type, int flags, |
@@ -2030,7 +2063,7 @@ static int ubifs_get_sb(struct file_system_type *fs_type, int flags, | |||
2030 | 2063 | ||
2031 | dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); | 2064 | dbg_gen("opened ubi%d_%d", vi.ubi_num, vi.vol_id); |
2032 | 2065 | ||
2033 | sb = sget(fs_type, &sb_test, &sb_set, &vi.cdev); | 2066 | sb = sget(fs_type, &sb_test, &set_anon_super, &vi.cdev); |
2034 | if (IS_ERR(sb)) { | 2067 | if (IS_ERR(sb)) { |
2035 | err = PTR_ERR(sb); | 2068 | err = PTR_ERR(sb); |
2036 | goto out_close; | 2069 | goto out_close; |
@@ -2070,16 +2103,11 @@ out_close: | |||
2070 | return err; | 2103 | return err; |
2071 | } | 2104 | } |
2072 | 2105 | ||
2073 | static void ubifs_kill_sb(struct super_block *sb) | ||
2074 | { | ||
2075 | generic_shutdown_super(sb); | ||
2076 | } | ||
2077 | |||
2078 | static struct file_system_type ubifs_fs_type = { | 2106 | static struct file_system_type ubifs_fs_type = { |
2079 | .name = "ubifs", | 2107 | .name = "ubifs", |
2080 | .owner = THIS_MODULE, | 2108 | .owner = THIS_MODULE, |
2081 | .get_sb = ubifs_get_sb, | 2109 | .get_sb = ubifs_get_sb, |
2082 | .kill_sb = ubifs_kill_sb | 2110 | .kill_sb = kill_anon_super, |
2083 | }; | 2111 | }; |
2084 | 2112 | ||
2085 | /* | 2113 | /* |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 0a8341e14088..a29349094422 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -95,8 +95,9 @@ | |||
95 | */ | 95 | */ |
96 | #define BGT_NAME_PATTERN "ubifs_bgt%d_%d" | 96 | #define BGT_NAME_PATTERN "ubifs_bgt%d_%d" |
97 | 97 | ||
98 | /* Default write-buffer synchronization timeout (5 secs) */ | 98 | /* Write-buffer synchronization timeout interval in seconds */ |
99 | #define DEFAULT_WBUF_TIMEOUT (5 * HZ) | 99 | #define WBUF_TIMEOUT_SOFTLIMIT 3 |
100 | #define WBUF_TIMEOUT_HARDLIMIT 5 | ||
100 | 101 | ||
101 | /* Maximum possible inode number (only 32-bit inodes are supported now) */ | 102 | /* Maximum possible inode number (only 32-bit inodes are supported now) */ |
102 | #define MAX_INUM 0xFFFFFFFF | 103 | #define MAX_INUM 0xFFFFFFFF |
@@ -650,9 +651,12 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c, | |||
650 | * @io_mutex: serializes write-buffer I/O | 651 | * @io_mutex: serializes write-buffer I/O |
651 | * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes | 652 | * @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes |
652 | * fields | 653 | * fields |
654 | * @softlimit: soft write-buffer timeout interval | ||
655 | * @delta: hard and soft timeouts delta (the timer expire inteval is @softlimit | ||
656 | * and @softlimit + @delta) | ||
653 | * @timer: write-buffer timer | 657 | * @timer: write-buffer timer |
654 | * @timeout: timer expire interval in jiffies | 658 | * @no_timer: non-zero if this write-buffer does not have a timer |
655 | * @need_sync: it is set if its timer expired and needs sync | 659 | * @need_sync: non-zero if the timer expired and the wbuf needs sync'ing |
656 | * @next_ino: points to the next position of the following inode number | 660 | * @next_ino: points to the next position of the following inode number |
657 | * @inodes: stores the inode numbers of the nodes which are in wbuf | 661 | * @inodes: stores the inode numbers of the nodes which are in wbuf |
658 | * | 662 | * |
@@ -678,9 +682,11 @@ struct ubifs_wbuf { | |||
678 | int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad); | 682 | int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad); |
679 | struct mutex io_mutex; | 683 | struct mutex io_mutex; |
680 | spinlock_t lock; | 684 | spinlock_t lock; |
681 | struct timer_list timer; | 685 | ktime_t softlimit; |
682 | int timeout; | 686 | unsigned long long delta; |
683 | int need_sync; | 687 | struct hrtimer timer; |
688 | unsigned int no_timer:1; | ||
689 | unsigned int need_sync:1; | ||
684 | int next_ino; | 690 | int next_ino; |
685 | ino_t *inodes; | 691 | ino_t *inodes; |
686 | }; | 692 | }; |
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index cfd31e229c89..adafcf556531 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c | |||
@@ -55,9 +55,9 @@ | |||
55 | * ACL support is not implemented. | 55 | * ACL support is not implemented. |
56 | */ | 56 | */ |
57 | 57 | ||
58 | #include "ubifs.h" | ||
58 | #include <linux/xattr.h> | 59 | #include <linux/xattr.h> |
59 | #include <linux/posix_acl_xattr.h> | 60 | #include <linux/posix_acl_xattr.h> |
60 | #include "ubifs.h" | ||
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 |
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index e48e9a3af763..1e068535b58b 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c | |||
@@ -238,7 +238,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb, | |||
238 | 238 | ||
239 | mutex_lock(&sbi->s_alloc_mutex); | 239 | mutex_lock(&sbi->s_alloc_mutex); |
240 | part_len = sbi->s_partmaps[partition].s_partition_len; | 240 | part_len = sbi->s_partmaps[partition].s_partition_len; |
241 | if (first_block < 0 || first_block >= part_len) | 241 | if (first_block >= part_len) |
242 | goto out; | 242 | goto out; |
243 | 243 | ||
244 | if (first_block + block_count > part_len) | 244 | if (first_block + block_count > part_len) |
@@ -297,7 +297,7 @@ static int udf_bitmap_new_block(struct super_block *sb, | |||
297 | mutex_lock(&sbi->s_alloc_mutex); | 297 | mutex_lock(&sbi->s_alloc_mutex); |
298 | 298 | ||
299 | repeat: | 299 | repeat: |
300 | if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len) | 300 | if (goal >= sbi->s_partmaps[partition].s_partition_len) |
301 | goal = 0; | 301 | goal = 0; |
302 | 302 | ||
303 | nr_groups = bitmap->s_nr_groups; | 303 | nr_groups = bitmap->s_nr_groups; |
@@ -666,8 +666,7 @@ static int udf_table_prealloc_blocks(struct super_block *sb, | |||
666 | int8_t etype = -1; | 666 | int8_t etype = -1; |
667 | struct udf_inode_info *iinfo; | 667 | struct udf_inode_info *iinfo; |
668 | 668 | ||
669 | if (first_block < 0 || | 669 | if (first_block >= sbi->s_partmaps[partition].s_partition_len) |
670 | first_block >= sbi->s_partmaps[partition].s_partition_len) | ||
671 | return 0; | 670 | return 0; |
672 | 671 | ||
673 | iinfo = UDF_I(table); | 672 | iinfo = UDF_I(table); |
@@ -743,7 +742,7 @@ static int udf_table_new_block(struct super_block *sb, | |||
743 | return newblock; | 742 | return newblock; |
744 | 743 | ||
745 | mutex_lock(&sbi->s_alloc_mutex); | 744 | mutex_lock(&sbi->s_alloc_mutex); |
746 | if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len) | 745 | if (goal >= sbi->s_partmaps[partition].s_partition_len) |
747 | goal = 0; | 746 | goal = 0; |
748 | 747 | ||
749 | /* We search for the closest matching block to goal. If we find | 748 | /* We search for the closest matching block to goal. If we find |
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 703843f30ffd..1b88fd5df05d 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c | |||
@@ -56,7 +56,12 @@ unsigned long udf_get_last_block(struct super_block *sb) | |||
56 | struct block_device *bdev = sb->s_bdev; | 56 | struct block_device *bdev = sb->s_bdev; |
57 | unsigned long lblock = 0; | 57 | unsigned long lblock = 0; |
58 | 58 | ||
59 | if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock)) | 59 | /* |
60 | * ioctl failed or returned obviously bogus value? | ||
61 | * Try using the device size... | ||
62 | */ | ||
63 | if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) || | ||
64 | lblock == 0) | ||
60 | lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; | 65 | lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; |
61 | 66 | ||
62 | if (lblock) | 67 | if (lblock) |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 6832135159b6..9d1b8c2e6c45 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -1087,11 +1087,23 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) | |||
1087 | struct udf_inode_info *vati; | 1087 | struct udf_inode_info *vati; |
1088 | uint32_t pos; | 1088 | uint32_t pos; |
1089 | struct virtualAllocationTable20 *vat20; | 1089 | struct virtualAllocationTable20 *vat20; |
1090 | sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; | ||
1090 | 1091 | ||
1091 | /* VAT file entry is in the last recorded block */ | 1092 | /* VAT file entry is in the last recorded block */ |
1092 | ino.partitionReferenceNum = type1_index; | 1093 | ino.partitionReferenceNum = type1_index; |
1093 | ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root; | 1094 | ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root; |
1094 | sbi->s_vat_inode = udf_iget(sb, &ino); | 1095 | sbi->s_vat_inode = udf_iget(sb, &ino); |
1096 | if (!sbi->s_vat_inode && | ||
1097 | sbi->s_last_block != blocks - 1) { | ||
1098 | printk(KERN_NOTICE "UDF-fs: Failed to read VAT inode from the" | ||
1099 | " last recorded block (%lu), retrying with the last " | ||
1100 | "block of the device (%lu).\n", | ||
1101 | (unsigned long)sbi->s_last_block, | ||
1102 | (unsigned long)blocks - 1); | ||
1103 | ino.partitionReferenceNum = type1_index; | ||
1104 | ino.logicalBlockNum = blocks - 1 - map->s_partition_root; | ||
1105 | sbi->s_vat_inode = udf_iget(sb, &ino); | ||
1106 | } | ||
1095 | if (!sbi->s_vat_inode) | 1107 | if (!sbi->s_vat_inode) |
1096 | return 1; | 1108 | return 1; |
1097 | 1109 | ||
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 3d2512c21f05..7cf33379fd46 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -56,9 +56,7 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off | |||
56 | 56 | ||
57 | 57 | ||
58 | UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); | 58 | UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); |
59 | if (i_block < 0) { | 59 | if (i_block < direct_blocks) { |
60 | ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0"); | ||
61 | } else if (i_block < direct_blocks) { | ||
62 | offsets[n++] = i_block; | 60 | offsets[n++] = i_block; |
63 | } else if ((i_block -= direct_blocks) < indirect_blocks) { | 61 | } else if ((i_block -= direct_blocks) < indirect_blocks) { |
64 | offsets[n++] = UFS_IND_BLOCK; | 62 | offsets[n++] = UFS_IND_BLOCK; |
@@ -440,8 +438,6 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head | |||
440 | lock_kernel(); | 438 | lock_kernel(); |
441 | 439 | ||
442 | UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); | 440 | UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); |
443 | if (fragment < 0) | ||
444 | goto abort_negative; | ||
445 | if (fragment > | 441 | if (fragment > |
446 | ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) | 442 | ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) |
447 | << uspi->s_fpbshift)) | 443 | << uspi->s_fpbshift)) |
@@ -504,10 +500,6 @@ abort: | |||
504 | unlock_kernel(); | 500 | unlock_kernel(); |
505 | return err; | 501 | return err; |
506 | 502 | ||
507 | abort_negative: | ||
508 | ufs_warning(sb, "ufs_get_block", "block < 0"); | ||
509 | goto abort; | ||
510 | |||
511 | abort_too_big: | 503 | abort_too_big: |
512 | ufs_warning(sb, "ufs_get_block", "block > big"); | 504 | ufs_warning(sb, "ufs_get_block", "block > big"); |
513 | goto abort; | 505 | goto abort; |
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 1cd3b55ee3d2..2d3f90afe5f1 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c | |||
@@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags) | |||
53 | printk(KERN_ERR "XFS: possible memory allocation " | 53 | printk(KERN_ERR "XFS: possible memory allocation " |
54 | "deadlock in %s (mode:0x%x)\n", | 54 | "deadlock in %s (mode:0x%x)\n", |
55 | __func__, lflags); | 55 | __func__, lflags); |
56 | congestion_wait(WRITE, HZ/50); | 56 | congestion_wait(BLK_RW_ASYNC, HZ/50); |
57 | } while (1); | 57 | } while (1); |
58 | } | 58 | } |
59 | 59 | ||
@@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags) | |||
130 | printk(KERN_ERR "XFS: possible memory allocation " | 130 | printk(KERN_ERR "XFS: possible memory allocation " |
131 | "deadlock in %s (mode:0x%x)\n", | 131 | "deadlock in %s (mode:0x%x)\n", |
132 | __func__, lflags); | 132 | __func__, lflags); |
133 | congestion_wait(WRITE, HZ/50); | 133 | congestion_wait(BLK_RW_ASYNC, HZ/50); |
134 | } while (1); | 134 | } while (1); |
135 | } | 135 | } |
136 | 136 | ||
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c index 1e9d1246eebc..b23a54506446 100644 --- a/fs/xfs/linux-2.6/xfs_acl.c +++ b/fs/xfs/linux-2.6/xfs_acl.c | |||
@@ -25,14 +25,10 @@ | |||
25 | #include <linux/posix_acl_xattr.h> | 25 | #include <linux/posix_acl_xattr.h> |
26 | 26 | ||
27 | 27 | ||
28 | #define XFS_ACL_NOT_CACHED ((void *)-1) | ||
29 | |||
30 | /* | 28 | /* |
31 | * Locking scheme: | 29 | * Locking scheme: |
32 | * - all ACL updates are protected by inode->i_mutex, which is taken before | 30 | * - all ACL updates are protected by inode->i_mutex, which is taken before |
33 | * calling into this file. | 31 | * calling into this file. |
34 | * - access and updates to the ip->i_acl and ip->i_default_acl pointers are | ||
35 | * protected by inode->i_lock. | ||
36 | */ | 32 | */ |
37 | 33 | ||
38 | STATIC struct posix_acl * | 34 | STATIC struct posix_acl * |
@@ -102,59 +98,35 @@ xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl) | |||
102 | } | 98 | } |
103 | } | 99 | } |
104 | 100 | ||
105 | /* | ||
106 | * Update the cached ACL pointer in the inode. | ||
107 | * | ||
108 | * Because we don't hold any locks while reading/writing the attribute | ||
109 | * from/to disk another thread could have raced and updated the cached | ||
110 | * ACL value before us. In that case we release the previous cached value | ||
111 | * and update it with our new value. | ||
112 | */ | ||
113 | STATIC void | ||
114 | xfs_update_cached_acl(struct inode *inode, struct posix_acl **p_acl, | ||
115 | struct posix_acl *acl) | ||
116 | { | ||
117 | spin_lock(&inode->i_lock); | ||
118 | if (*p_acl && *p_acl != XFS_ACL_NOT_CACHED) | ||
119 | posix_acl_release(*p_acl); | ||
120 | *p_acl = posix_acl_dup(acl); | ||
121 | spin_unlock(&inode->i_lock); | ||
122 | } | ||
123 | |||
124 | struct posix_acl * | 101 | struct posix_acl * |
125 | xfs_get_acl(struct inode *inode, int type) | 102 | xfs_get_acl(struct inode *inode, int type) |
126 | { | 103 | { |
127 | struct xfs_inode *ip = XFS_I(inode); | 104 | struct xfs_inode *ip = XFS_I(inode); |
128 | struct posix_acl *acl = NULL, **p_acl; | 105 | struct posix_acl *acl; |
129 | struct xfs_acl *xfs_acl; | 106 | struct xfs_acl *xfs_acl; |
130 | int len = sizeof(struct xfs_acl); | 107 | int len = sizeof(struct xfs_acl); |
131 | char *ea_name; | 108 | char *ea_name; |
132 | int error; | 109 | int error; |
133 | 110 | ||
111 | acl = get_cached_acl(inode, type); | ||
112 | if (acl != ACL_NOT_CACHED) | ||
113 | return acl; | ||
114 | |||
134 | switch (type) { | 115 | switch (type) { |
135 | case ACL_TYPE_ACCESS: | 116 | case ACL_TYPE_ACCESS: |
136 | ea_name = SGI_ACL_FILE; | 117 | ea_name = SGI_ACL_FILE; |
137 | p_acl = &ip->i_acl; | ||
138 | break; | 118 | break; |
139 | case ACL_TYPE_DEFAULT: | 119 | case ACL_TYPE_DEFAULT: |
140 | ea_name = SGI_ACL_DEFAULT; | 120 | ea_name = SGI_ACL_DEFAULT; |
141 | p_acl = &ip->i_default_acl; | ||
142 | break; | 121 | break; |
143 | default: | 122 | default: |
144 | return ERR_PTR(-EINVAL); | 123 | BUG(); |
145 | } | 124 | } |
146 | 125 | ||
147 | spin_lock(&inode->i_lock); | ||
148 | if (*p_acl != XFS_ACL_NOT_CACHED) | ||
149 | acl = posix_acl_dup(*p_acl); | ||
150 | spin_unlock(&inode->i_lock); | ||
151 | |||
152 | /* | 126 | /* |
153 | * If we have a cached ACLs value just return it, not need to | 127 | * If we have a cached ACLs value just return it, not need to |
154 | * go out to the disk. | 128 | * go out to the disk. |
155 | */ | 129 | */ |
156 | if (acl) | ||
157 | return acl; | ||
158 | 130 | ||
159 | xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); | 131 | xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); |
160 | if (!xfs_acl) | 132 | if (!xfs_acl) |
@@ -165,7 +137,7 @@ xfs_get_acl(struct inode *inode, int type) | |||
165 | /* | 137 | /* |
166 | * If the attribute doesn't exist make sure we have a negative | 138 | * If the attribute doesn't exist make sure we have a negative |
167 | * cache entry, for any other error assume it is transient and | 139 | * cache entry, for any other error assume it is transient and |
168 | * leave the cache entry as XFS_ACL_NOT_CACHED. | 140 | * leave the cache entry as ACL_NOT_CACHED. |
169 | */ | 141 | */ |
170 | if (error == -ENOATTR) { | 142 | if (error == -ENOATTR) { |
171 | acl = NULL; | 143 | acl = NULL; |
@@ -179,7 +151,7 @@ xfs_get_acl(struct inode *inode, int type) | |||
179 | goto out; | 151 | goto out; |
180 | 152 | ||
181 | out_update_cache: | 153 | out_update_cache: |
182 | xfs_update_cached_acl(inode, p_acl, acl); | 154 | set_cached_acl(inode, type, acl); |
183 | out: | 155 | out: |
184 | kfree(xfs_acl); | 156 | kfree(xfs_acl); |
185 | return acl; | 157 | return acl; |
@@ -189,7 +161,6 @@ STATIC int | |||
189 | xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | 161 | xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) |
190 | { | 162 | { |
191 | struct xfs_inode *ip = XFS_I(inode); | 163 | struct xfs_inode *ip = XFS_I(inode); |
192 | struct posix_acl **p_acl; | ||
193 | char *ea_name; | 164 | char *ea_name; |
194 | int error; | 165 | int error; |
195 | 166 | ||
@@ -199,13 +170,11 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
199 | switch (type) { | 170 | switch (type) { |
200 | case ACL_TYPE_ACCESS: | 171 | case ACL_TYPE_ACCESS: |
201 | ea_name = SGI_ACL_FILE; | 172 | ea_name = SGI_ACL_FILE; |
202 | p_acl = &ip->i_acl; | ||
203 | break; | 173 | break; |
204 | case ACL_TYPE_DEFAULT: | 174 | case ACL_TYPE_DEFAULT: |
205 | if (!S_ISDIR(inode->i_mode)) | 175 | if (!S_ISDIR(inode->i_mode)) |
206 | return acl ? -EACCES : 0; | 176 | return acl ? -EACCES : 0; |
207 | ea_name = SGI_ACL_DEFAULT; | 177 | ea_name = SGI_ACL_DEFAULT; |
208 | p_acl = &ip->i_default_acl; | ||
209 | break; | 178 | break; |
210 | default: | 179 | default: |
211 | return -EINVAL; | 180 | return -EINVAL; |
@@ -242,7 +211,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
242 | } | 211 | } |
243 | 212 | ||
244 | if (!error) | 213 | if (!error) |
245 | xfs_update_cached_acl(inode, p_acl, acl); | 214 | set_cached_acl(inode, type, acl); |
246 | return error; | 215 | return error; |
247 | } | 216 | } |
248 | 217 | ||
@@ -384,30 +353,6 @@ xfs_acl_chmod(struct inode *inode) | |||
384 | return error; | 353 | return error; |
385 | } | 354 | } |
386 | 355 | ||
387 | void | ||
388 | xfs_inode_init_acls(struct xfs_inode *ip) | ||
389 | { | ||
390 | /* | ||
391 | * No need for locking, inode is not live yet. | ||
392 | */ | ||
393 | ip->i_acl = XFS_ACL_NOT_CACHED; | ||
394 | ip->i_default_acl = XFS_ACL_NOT_CACHED; | ||
395 | } | ||
396 | |||
397 | void | ||
398 | xfs_inode_clear_acls(struct xfs_inode *ip) | ||
399 | { | ||
400 | /* | ||
401 | * No need for locking here, the inode is not live anymore | ||
402 | * and just about to be freed. | ||
403 | */ | ||
404 | if (ip->i_acl != XFS_ACL_NOT_CACHED) | ||
405 | posix_acl_release(ip->i_acl); | ||
406 | if (ip->i_default_acl != XFS_ACL_NOT_CACHED) | ||
407 | posix_acl_release(ip->i_default_acl); | ||
408 | } | ||
409 | |||
410 | |||
411 | /* | 356 | /* |
412 | * System xattr handlers. | 357 | * System xattr handlers. |
413 | * | 358 | * |
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 178c20c13e83..965df1227d64 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -412,7 +412,7 @@ _xfs_buf_lookup_pages( | |||
412 | 412 | ||
413 | XFS_STATS_INC(xb_page_retries); | 413 | XFS_STATS_INC(xb_page_retries); |
414 | xfsbufd_wakeup(0, gfp_mask); | 414 | xfsbufd_wakeup(0, gfp_mask); |
415 | congestion_wait(WRITE, HZ/50); | 415 | congestion_wait(BLK_RW_ASYNC, HZ/50); |
416 | goto retry; | 416 | goto retry; |
417 | } | 417 | } |
418 | 418 | ||
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index f4e255441574..0542fd507649 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include "xfs_ioctl.h" | 41 | #include "xfs_ioctl.h" |
42 | 42 | ||
43 | #include <linux/dcache.h> | 43 | #include <linux/dcache.h> |
44 | #include <linux/smp_lock.h> | ||
45 | 44 | ||
46 | static struct vm_operations_struct xfs_file_vm_ops; | 45 | static struct vm_operations_struct xfs_file_vm_ops; |
47 | 46 | ||
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index f65a53f8752f..6127e24062d0 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h | |||
@@ -24,7 +24,7 @@ | |||
24 | * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. | 24 | * XFS_BIG_BLKNOS needs block layer disk addresses to be 64 bits. |
25 | * XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set. | 25 | * XFS_BIG_INUMS requires XFS_BIG_BLKNOS to be set. |
26 | */ | 26 | */ |
27 | #if defined(CONFIG_LBD) || (BITS_PER_LONG == 64) | 27 | #if defined(CONFIG_LBDAF) || (BITS_PER_LONG == 64) |
28 | # define XFS_BIG_BLKNOS 1 | 28 | # define XFS_BIG_BLKNOS 1 |
29 | # define XFS_BIG_INUMS 1 | 29 | # define XFS_BIG_INUMS 1 |
30 | #else | 30 | #else |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 2e09efbca8db..a220d36f789b 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -616,7 +616,7 @@ xfs_max_file_offset( | |||
616 | */ | 616 | */ |
617 | 617 | ||
618 | #if BITS_PER_LONG == 32 | 618 | #if BITS_PER_LONG == 32 |
619 | # if defined(CONFIG_LBD) | 619 | # if defined(CONFIG_LBDAF) |
620 | ASSERT(sizeof(sector_t) == 8); | 620 | ASSERT(sizeof(sector_t) == 8); |
621 | pagefactor = PAGE_CACHE_SIZE; | 621 | pagefactor = PAGE_CACHE_SIZE; |
622 | bitshift = BITS_PER_LONG; | 622 | bitshift = BITS_PER_LONG; |
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 63dc1f2efad5..947b150df8ed 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h | |||
@@ -46,8 +46,6 @@ extern int xfs_check_acl(struct inode *inode, int mask); | |||
46 | extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); | 46 | extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); |
47 | extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); | 47 | extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); |
48 | extern int xfs_acl_chmod(struct inode *inode); | 48 | extern int xfs_acl_chmod(struct inode *inode); |
49 | extern void xfs_inode_init_acls(struct xfs_inode *ip); | ||
50 | extern void xfs_inode_clear_acls(struct xfs_inode *ip); | ||
51 | extern int posix_acl_access_exists(struct inode *inode); | 49 | extern int posix_acl_access_exists(struct inode *inode); |
52 | extern int posix_acl_default_exists(struct inode *inode); | 50 | extern int posix_acl_default_exists(struct inode *inode); |
53 | 51 | ||
@@ -57,8 +55,6 @@ extern struct xattr_handler xfs_xattr_system_handler; | |||
57 | # define xfs_get_acl(inode, type) NULL | 55 | # define xfs_get_acl(inode, type) NULL |
58 | # define xfs_inherit_acl(inode, default_acl) 0 | 56 | # define xfs_inherit_acl(inode, default_acl) 0 |
59 | # define xfs_acl_chmod(inode) 0 | 57 | # define xfs_acl_chmod(inode) 0 |
60 | # define xfs_inode_init_acls(ip) | ||
61 | # define xfs_inode_clear_acls(ip) | ||
62 | # define posix_acl_access_exists(inode) 0 | 58 | # define posix_acl_access_exists(inode) 0 |
63 | # define posix_acl_default_exists(inode) 0 | 59 | # define posix_acl_default_exists(inode) 0 |
64 | #endif /* CONFIG_XFS_POSIX_ACL */ | 60 | #endif /* CONFIG_XFS_POSIX_ACL */ |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 76c540f719e4..34ec86923f7e 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -64,6 +64,10 @@ xfs_inode_alloc( | |||
64 | ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP); | 64 | ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP); |
65 | if (!ip) | 65 | if (!ip) |
66 | return NULL; | 66 | return NULL; |
67 | if (inode_init_always(mp->m_super, VFS_I(ip))) { | ||
68 | kmem_zone_free(xfs_inode_zone, ip); | ||
69 | return NULL; | ||
70 | } | ||
67 | 71 | ||
68 | ASSERT(atomic_read(&ip->i_iocount) == 0); | 72 | ASSERT(atomic_read(&ip->i_iocount) == 0); |
69 | ASSERT(atomic_read(&ip->i_pincount) == 0); | 73 | ASSERT(atomic_read(&ip->i_pincount) == 0); |
@@ -83,7 +87,6 @@ xfs_inode_alloc( | |||
83 | memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); | 87 | memset(&ip->i_d, 0, sizeof(xfs_icdinode_t)); |
84 | ip->i_size = 0; | 88 | ip->i_size = 0; |
85 | ip->i_new_size = 0; | 89 | ip->i_new_size = 0; |
86 | xfs_inode_init_acls(ip); | ||
87 | 90 | ||
88 | /* | 91 | /* |
89 | * Initialize inode's trace buffers. | 92 | * Initialize inode's trace buffers. |
@@ -106,17 +109,6 @@ xfs_inode_alloc( | |||
106 | #ifdef XFS_DIR2_TRACE | 109 | #ifdef XFS_DIR2_TRACE |
107 | ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); | 110 | ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); |
108 | #endif | 111 | #endif |
109 | /* | ||
110 | * Now initialise the VFS inode. We do this after the xfs_inode | ||
111 | * initialisation as internal failures will result in ->destroy_inode | ||
112 | * being called and that will pass down through the reclaim path and | ||
113 | * free the XFS inode. This path requires the XFS inode to already be | ||
114 | * initialised. Hence if this call fails, the xfs_inode has already | ||
115 | * been freed and we should not reference it at all in the error | ||
116 | * handling. | ||
117 | */ | ||
118 | if (!inode_init_always(mp->m_super, VFS_I(ip))) | ||
119 | return NULL; | ||
120 | 112 | ||
121 | /* prevent anyone from using this yet */ | 113 | /* prevent anyone from using this yet */ |
122 | VFS_I(ip)->i_state = I_NEW|I_LOCK; | 114 | VFS_I(ip)->i_state = I_NEW|I_LOCK; |
@@ -124,6 +116,71 @@ xfs_inode_alloc( | |||
124 | return ip; | 116 | return ip; |
125 | } | 117 | } |
126 | 118 | ||
119 | STATIC void | ||
120 | xfs_inode_free( | ||
121 | struct xfs_inode *ip) | ||
122 | { | ||
123 | switch (ip->i_d.di_mode & S_IFMT) { | ||
124 | case S_IFREG: | ||
125 | case S_IFDIR: | ||
126 | case S_IFLNK: | ||
127 | xfs_idestroy_fork(ip, XFS_DATA_FORK); | ||
128 | break; | ||
129 | } | ||
130 | |||
131 | if (ip->i_afp) | ||
132 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | ||
133 | |||
134 | #ifdef XFS_INODE_TRACE | ||
135 | ktrace_free(ip->i_trace); | ||
136 | #endif | ||
137 | #ifdef XFS_BMAP_TRACE | ||
138 | ktrace_free(ip->i_xtrace); | ||
139 | #endif | ||
140 | #ifdef XFS_BTREE_TRACE | ||
141 | ktrace_free(ip->i_btrace); | ||
142 | #endif | ||
143 | #ifdef XFS_RW_TRACE | ||
144 | ktrace_free(ip->i_rwtrace); | ||
145 | #endif | ||
146 | #ifdef XFS_ILOCK_TRACE | ||
147 | ktrace_free(ip->i_lock_trace); | ||
148 | #endif | ||
149 | #ifdef XFS_DIR2_TRACE | ||
150 | ktrace_free(ip->i_dir_trace); | ||
151 | #endif | ||
152 | |||
153 | if (ip->i_itemp) { | ||
154 | /* | ||
155 | * Only if we are shutting down the fs will we see an | ||
156 | * inode still in the AIL. If it is there, we should remove | ||
157 | * it to prevent a use-after-free from occurring. | ||
158 | */ | ||
159 | xfs_log_item_t *lip = &ip->i_itemp->ili_item; | ||
160 | struct xfs_ail *ailp = lip->li_ailp; | ||
161 | |||
162 | ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || | ||
163 | XFS_FORCED_SHUTDOWN(ip->i_mount)); | ||
164 | if (lip->li_flags & XFS_LI_IN_AIL) { | ||
165 | spin_lock(&ailp->xa_lock); | ||
166 | if (lip->li_flags & XFS_LI_IN_AIL) | ||
167 | xfs_trans_ail_delete(ailp, lip); | ||
168 | else | ||
169 | spin_unlock(&ailp->xa_lock); | ||
170 | } | ||
171 | xfs_inode_item_destroy(ip); | ||
172 | ip->i_itemp = NULL; | ||
173 | } | ||
174 | |||
175 | /* asserts to verify all state is correct here */ | ||
176 | ASSERT(atomic_read(&ip->i_iocount) == 0); | ||
177 | ASSERT(atomic_read(&ip->i_pincount) == 0); | ||
178 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); | ||
179 | ASSERT(completion_done(&ip->i_flush)); | ||
180 | |||
181 | kmem_zone_free(xfs_inode_zone, ip); | ||
182 | } | ||
183 | |||
127 | /* | 184 | /* |
128 | * Check the validity of the inode we just found it the cache | 185 | * Check the validity of the inode we just found it the cache |
129 | */ | 186 | */ |
@@ -168,7 +225,7 @@ xfs_iget_cache_hit( | |||
168 | * errors cleanly, then tag it so it can be set up correctly | 225 | * errors cleanly, then tag it so it can be set up correctly |
169 | * later. | 226 | * later. |
170 | */ | 227 | */ |
171 | if (!inode_init_always(mp->m_super, VFS_I(ip))) { | 228 | if (inode_init_always(mp->m_super, VFS_I(ip))) { |
172 | error = ENOMEM; | 229 | error = ENOMEM; |
173 | goto out_error; | 230 | goto out_error; |
174 | } | 231 | } |
@@ -300,7 +357,8 @@ out_preload_end: | |||
300 | if (lock_flags) | 357 | if (lock_flags) |
301 | xfs_iunlock(ip, lock_flags); | 358 | xfs_iunlock(ip, lock_flags); |
302 | out_destroy: | 359 | out_destroy: |
303 | xfs_destroy_inode(ip); | 360 | __destroy_inode(VFS_I(ip)); |
361 | xfs_inode_free(ip); | ||
304 | return error; | 362 | return error; |
305 | } | 363 | } |
306 | 364 | ||
@@ -505,63 +563,7 @@ xfs_ireclaim( | |||
505 | xfs_qm_dqdetach(ip); | 563 | xfs_qm_dqdetach(ip); |
506 | xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | 564 | xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); |
507 | 565 | ||
508 | switch (ip->i_d.di_mode & S_IFMT) { | 566 | xfs_inode_free(ip); |
509 | case S_IFREG: | ||
510 | case S_IFDIR: | ||
511 | case S_IFLNK: | ||
512 | xfs_idestroy_fork(ip, XFS_DATA_FORK); | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | if (ip->i_afp) | ||
517 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | ||
518 | |||
519 | #ifdef XFS_INODE_TRACE | ||
520 | ktrace_free(ip->i_trace); | ||
521 | #endif | ||
522 | #ifdef XFS_BMAP_TRACE | ||
523 | ktrace_free(ip->i_xtrace); | ||
524 | #endif | ||
525 | #ifdef XFS_BTREE_TRACE | ||
526 | ktrace_free(ip->i_btrace); | ||
527 | #endif | ||
528 | #ifdef XFS_RW_TRACE | ||
529 | ktrace_free(ip->i_rwtrace); | ||
530 | #endif | ||
531 | #ifdef XFS_ILOCK_TRACE | ||
532 | ktrace_free(ip->i_lock_trace); | ||
533 | #endif | ||
534 | #ifdef XFS_DIR2_TRACE | ||
535 | ktrace_free(ip->i_dir_trace); | ||
536 | #endif | ||
537 | if (ip->i_itemp) { | ||
538 | /* | ||
539 | * Only if we are shutting down the fs will we see an | ||
540 | * inode still in the AIL. If it is there, we should remove | ||
541 | * it to prevent a use-after-free from occurring. | ||
542 | */ | ||
543 | xfs_log_item_t *lip = &ip->i_itemp->ili_item; | ||
544 | struct xfs_ail *ailp = lip->li_ailp; | ||
545 | |||
546 | ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || | ||
547 | XFS_FORCED_SHUTDOWN(ip->i_mount)); | ||
548 | if (lip->li_flags & XFS_LI_IN_AIL) { | ||
549 | spin_lock(&ailp->xa_lock); | ||
550 | if (lip->li_flags & XFS_LI_IN_AIL) | ||
551 | xfs_trans_ail_delete(ailp, lip); | ||
552 | else | ||
553 | spin_unlock(&ailp->xa_lock); | ||
554 | } | ||
555 | xfs_inode_item_destroy(ip); | ||
556 | ip->i_itemp = NULL; | ||
557 | } | ||
558 | /* asserts to verify all state is correct here */ | ||
559 | ASSERT(atomic_read(&ip->i_iocount) == 0); | ||
560 | ASSERT(atomic_read(&ip->i_pincount) == 0); | ||
561 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); | ||
562 | ASSERT(completion_done(&ip->i_flush)); | ||
563 | xfs_inode_clear_acls(ip); | ||
564 | kmem_zone_free(xfs_inode_zone, ip); | ||
565 | } | 567 | } |
566 | 568 | ||
567 | /* | 569 | /* |
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 77016702938b..65f24a3cc992 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -273,11 +273,6 @@ typedef struct xfs_inode { | |||
273 | /* VFS inode */ | 273 | /* VFS inode */ |
274 | struct inode i_vnode; /* embedded VFS inode */ | 274 | struct inode i_vnode; /* embedded VFS inode */ |
275 | 275 | ||
276 | #ifdef CONFIG_XFS_POSIX_ACL | ||
277 | struct posix_acl *i_acl; | ||
278 | struct posix_acl *i_default_acl; | ||
279 | #endif | ||
280 | |||
281 | /* Trace buffers per inode. */ | 276 | /* Trace buffers per inode. */ |
282 | #ifdef XFS_INODE_TRACE | 277 | #ifdef XFS_INODE_TRACE |
283 | struct ktrace *i_trace; /* general inode trace */ | 278 | struct ktrace *i_trace; /* general inode trace */ |
@@ -315,23 +310,6 @@ static inline struct inode *VFS_I(struct xfs_inode *ip) | |||
315 | } | 310 | } |
316 | 311 | ||
317 | /* | 312 | /* |
318 | * Get rid of a partially initialized inode. | ||
319 | * | ||
320 | * We have to go through destroy_inode to make sure allocations | ||
321 | * from init_inode_always like the security data are undone. | ||
322 | * | ||
323 | * We mark the inode bad so that it takes the short cut in | ||
324 | * the reclaim path instead of going through the flush path | ||
325 | * which doesn't make sense for an inode that has never seen the | ||
326 | * light of day. | ||
327 | */ | ||
328 | static inline void xfs_destroy_inode(struct xfs_inode *ip) | ||
329 | { | ||
330 | make_bad_inode(VFS_I(ip)); | ||
331 | return destroy_inode(VFS_I(ip)); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * i_flags helper functions | 313 | * i_flags helper functions |
336 | */ | 314 | */ |
337 | static inline void | 315 | static inline void |