diff options
Diffstat (limited to 'fs')
78 files changed, 998 insertions, 874 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 455aa207e67..d4bf8caad8d 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -109,6 +109,7 @@ source "fs/sysfs/Kconfig" | |||
109 | 109 | ||
110 | config TMPFS | 110 | config TMPFS |
111 | bool "Virtual memory file system support (former shm fs)" | 111 | bool "Virtual memory file system support (former shm fs)" |
112 | depends on SHMEM | ||
112 | help | 113 | help |
113 | Tmpfs is a file system which keeps all files in virtual memory. | 114 | Tmpfs is a file system which keeps all files in virtual memory. |
114 | 115 | ||
diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 3ff8bdd18fb..0931bc1325e 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c | |||
@@ -21,7 +21,7 @@ static void afs_fl_release_private(struct file_lock *fl); | |||
21 | static struct workqueue_struct *afs_lock_manager; | 21 | static struct workqueue_struct *afs_lock_manager; |
22 | static DEFINE_MUTEX(afs_lock_manager_mutex); | 22 | static DEFINE_MUTEX(afs_lock_manager_mutex); |
23 | 23 | ||
24 | static struct file_lock_operations afs_lock_ops = { | 24 | static const struct file_lock_operations afs_lock_ops = { |
25 | .fl_copy_lock = afs_fl_copy_lock, | 25 | .fl_copy_lock = afs_fl_copy_lock, |
26 | .fl_release_private = afs_fl_release_private, | 26 | .fl_release_private = afs_fl_release_private, |
27 | }; | 27 | }; |
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/file.h> | 24 | #include <linux/file.h> |
25 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
26 | #include <linux/mman.h> | 26 | #include <linux/mman.h> |
27 | #include <linux/mmu_context.h> | ||
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
29 | #include <linux/aio.h> | 30 | #include <linux/aio.h> |
@@ -34,7 +35,6 @@ | |||
34 | 35 | ||
35 | #include <asm/kmap_types.h> | 36 | #include <asm/kmap_types.h> |
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | #include <asm/mmu_context.h> | ||
38 | 38 | ||
39 | #if DEBUG > 1 | 39 | #if DEBUG > 1 |
40 | #define dprintk printk | 40 | #define dprintk printk |
@@ -595,51 +595,6 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) | |||
595 | } | 595 | } |
596 | 596 | ||
597 | /* | 597 | /* |
598 | * use_mm | ||
599 | * Makes the calling kernel thread take on the specified | ||
600 | * mm context. | ||
601 | * Called by the retry thread execute retries within the | ||
602 | * iocb issuer's mm context, so that copy_from/to_user | ||
603 | * operations work seamlessly for aio. | ||
604 | * (Note: this routine is intended to be called only | ||
605 | * from a kernel thread context) | ||
606 | */ | ||
607 | static void use_mm(struct mm_struct *mm) | ||
608 | { | ||
609 | struct mm_struct *active_mm; | ||
610 | struct task_struct *tsk = current; | ||
611 | |||
612 | task_lock(tsk); | ||
613 | active_mm = tsk->active_mm; | ||
614 | atomic_inc(&mm->mm_count); | ||
615 | tsk->mm = mm; | ||
616 | tsk->active_mm = mm; | ||
617 | switch_mm(active_mm, mm, tsk); | ||
618 | task_unlock(tsk); | ||
619 | |||
620 | mmdrop(active_mm); | ||
621 | } | ||
622 | |||
623 | /* | ||
624 | * unuse_mm | ||
625 | * Reverses the effect of use_mm, i.e. releases the | ||
626 | * specified mm context which was earlier taken on | ||
627 | * by the calling kernel thread | ||
628 | * (Note: this routine is intended to be called only | ||
629 | * from a kernel thread context) | ||
630 | */ | ||
631 | static void unuse_mm(struct mm_struct *mm) | ||
632 | { | ||
633 | struct task_struct *tsk = current; | ||
634 | |||
635 | task_lock(tsk); | ||
636 | tsk->mm = NULL; | ||
637 | /* active_mm is still 'mm' */ | ||
638 | enter_lazy_tlb(mm, tsk); | ||
639 | task_unlock(tsk); | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * Queue up a kiocb to be retried. Assumes that the kiocb | 598 | * Queue up a kiocb to be retried. Assumes that the kiocb |
644 | * has already been marked as kicked, and places it on | 599 | * has already been marked as kicked, and places it on |
645 | * the retry run list for the corresponding ioctx, if it | 600 | * the retry run list for the corresponding ioctx, if it |
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index 2316e944a10..e947915109e 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c | |||
@@ -90,7 +90,7 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, | |||
90 | DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); | 90 | DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); |
91 | continue; | 91 | continue; |
92 | } | 92 | } |
93 | while (d_mountpoint(path.dentry) && follow_down(&path)); | 93 | while (d_mountpoint(path.dentry) && follow_down(&path)) |
94 | ; | 94 | ; |
95 | umount_ok = may_umount(path.mnt); | 95 | umount_ok = may_umount(path.mnt); |
96 | path_put(&path); | 96 | path_put(&path); |
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 615d5496fe0..dd376c124e7 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
@@ -842,7 +842,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent) | |||
842 | sb->s_magic = BEFS_SUPER_MAGIC; | 842 | sb->s_magic = BEFS_SUPER_MAGIC; |
843 | /* Set real blocksize of fs */ | 843 | /* Set real blocksize of fs */ |
844 | sb_set_blocksize(sb, (ulong) befs_sb->block_size); | 844 | sb_set_blocksize(sb, (ulong) befs_sb->block_size); |
845 | sb->s_op = (struct super_operations *) &befs_sops; | 845 | sb->s_op = &befs_sops; |
846 | root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))); | 846 | root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))); |
847 | if (IS_ERR(root)) { | 847 | if (IS_ERR(root)) { |
848 | ret = PTR_ERR(root); | 848 | ret = PTR_ERR(root); |
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 7c1e65d5487..442d94fe255 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c | |||
@@ -1280,9 +1280,6 @@ static int writenote(struct memelfnote *men, struct file *file, | |||
1280 | #define DUMP_WRITE(addr, nr) \ | 1280 | #define DUMP_WRITE(addr, nr) \ |
1281 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ | 1281 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ |
1282 | goto end_coredump; | 1282 | goto end_coredump; |
1283 | #define DUMP_SEEK(off) \ | ||
1284 | if (!dump_seek(file, (off))) \ | ||
1285 | goto end_coredump; | ||
1286 | 1283 | ||
1287 | static void fill_elf_header(struct elfhdr *elf, int segs, | 1284 | static void fill_elf_header(struct elfhdr *elf, int segs, |
1288 | u16 machine, u32 flags, u8 osabi) | 1285 | u16 machine, u32 flags, u8 osabi) |
@@ -2016,7 +2013,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
2016 | goto end_coredump; | 2013 | goto end_coredump; |
2017 | 2014 | ||
2018 | /* Align to page */ | 2015 | /* Align to page */ |
2019 | DUMP_SEEK(dataoff - foffset); | 2016 | if (!dump_seek(file, dataoff - foffset)) |
2017 | goto end_coredump; | ||
2020 | 2018 | ||
2021 | for (vma = first_vma(current, gate_vma); vma != NULL; | 2019 | for (vma = first_vma(current, gate_vma); vma != NULL; |
2022 | vma = next_vma(vma, gate_vma)) { | 2020 | vma = next_vma(vma, gate_vma)) { |
@@ -2027,33 +2025,19 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un | |||
2027 | 2025 | ||
2028 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { | 2026 | for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { |
2029 | struct page *page; | 2027 | struct page *page; |
2030 | struct vm_area_struct *tmp_vma; | 2028 | int stop; |
2031 | 2029 | ||
2032 | if (get_user_pages(current, current->mm, addr, 1, 0, 1, | 2030 | page = get_dump_page(addr); |
2033 | &page, &tmp_vma) <= 0) { | 2031 | if (page) { |
2034 | DUMP_SEEK(PAGE_SIZE); | 2032 | void *kaddr = kmap(page); |
2035 | } else { | 2033 | stop = ((size += PAGE_SIZE) > limit) || |
2036 | if (page == ZERO_PAGE(0)) { | 2034 | !dump_write(file, kaddr, PAGE_SIZE); |
2037 | if (!dump_seek(file, PAGE_SIZE)) { | 2035 | kunmap(page); |
2038 | page_cache_release(page); | ||
2039 | goto end_coredump; | ||
2040 | } | ||
2041 | } else { | ||
2042 | void *kaddr; | ||
2043 | flush_cache_page(tmp_vma, addr, | ||
2044 | page_to_pfn(page)); | ||
2045 | kaddr = kmap(page); | ||
2046 | if ((size += PAGE_SIZE) > limit || | ||
2047 | !dump_write(file, kaddr, | ||
2048 | PAGE_SIZE)) { | ||
2049 | kunmap(page); | ||
2050 | page_cache_release(page); | ||
2051 | goto end_coredump; | ||
2052 | } | ||
2053 | kunmap(page); | ||
2054 | } | ||
2055 | page_cache_release(page); | 2036 | page_cache_release(page); |
2056 | } | 2037 | } else |
2038 | stop = !dump_seek(file, PAGE_SIZE); | ||
2039 | if (stop) | ||
2040 | goto end_coredump; | ||
2057 | } | 2041 | } |
2058 | } | 2042 | } |
2059 | 2043 | ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 20fbeced472..76285471073 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c | |||
@@ -1325,9 +1325,6 @@ static int writenote(struct memelfnote *men, struct file *file) | |||
1325 | #define DUMP_WRITE(addr, nr) \ | 1325 | #define DUMP_WRITE(addr, nr) \ |
1326 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ | 1326 | if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ |
1327 | goto end_coredump; | 1327 | goto end_coredump; |
1328 | #define DUMP_SEEK(off) \ | ||
1329 | if (!dump_seek(file, (off))) \ | ||
1330 | goto end_coredump; | ||
1331 | 1328 | ||
1332 | static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) | 1329 | static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) |
1333 | { | 1330 | { |
@@ -1518,6 +1515,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, | |||
1518 | unsigned long *limit, unsigned long mm_flags) | 1515 | unsigned long *limit, unsigned long mm_flags) |
1519 | { | 1516 | { |
1520 | struct vm_area_struct *vma; | 1517 | struct vm_area_struct *vma; |
1518 | int err = 0; | ||
1521 | 1519 | ||
1522 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { | 1520 | for (vma = current->mm->mmap; vma; vma = vma->vm_next) { |
1523 | unsigned long addr; | 1521 | unsigned long addr; |
@@ -1525,43 +1523,26 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, | |||
1525 | if (!maydump(vma, mm_flags)) | 1523 | if (!maydump(vma, mm_flags)) |
1526 | continue; | 1524 | continue; |
1527 | 1525 | ||
1528 | for (addr = vma->vm_start; | 1526 | for (addr = vma->vm_start; addr < vma->vm_end; |
1529 | addr < vma->vm_end; | 1527 | addr += PAGE_SIZE) { |
1530 | addr += PAGE_SIZE | 1528 | struct page *page = get_dump_page(addr); |
1531 | ) { | 1529 | if (page) { |
1532 | struct vm_area_struct *vma; | 1530 | void *kaddr = kmap(page); |
1533 | struct page *page; | 1531 | *size += PAGE_SIZE; |
1534 | 1532 | if (*size > *limit) | |
1535 | if (get_user_pages(current, current->mm, addr, 1, 0, 1, | 1533 | err = -EFBIG; |
1536 | &page, &vma) <= 0) { | 1534 | else if (!dump_write(file, kaddr, PAGE_SIZE)) |
1537 | DUMP_SEEK(file->f_pos + PAGE_SIZE); | 1535 | err = -EIO; |
1538 | } | ||
1539 | else if (page == ZERO_PAGE(0)) { | ||
1540 | page_cache_release(page); | ||
1541 | DUMP_SEEK(file->f_pos + PAGE_SIZE); | ||
1542 | } | ||
1543 | else { | ||
1544 | void *kaddr; | ||
1545 | |||
1546 | flush_cache_page(vma, addr, page_to_pfn(page)); | ||
1547 | kaddr = kmap(page); | ||
1548 | if ((*size += PAGE_SIZE) > *limit || | ||
1549 | !dump_write(file, kaddr, PAGE_SIZE) | ||
1550 | ) { | ||
1551 | kunmap(page); | ||
1552 | page_cache_release(page); | ||
1553 | return -EIO; | ||
1554 | } | ||
1555 | kunmap(page); | 1536 | kunmap(page); |
1556 | page_cache_release(page); | 1537 | page_cache_release(page); |
1557 | } | 1538 | } else if (!dump_seek(file, file->f_pos + PAGE_SIZE)) |
1539 | err = -EFBIG; | ||
1540 | if (err) | ||
1541 | goto out; | ||
1558 | } | 1542 | } |
1559 | } | 1543 | } |
1560 | 1544 | out: | |
1561 | return 0; | 1545 | return err; |
1562 | |||
1563 | end_coredump: | ||
1564 | return -EFBIG; | ||
1565 | } | 1546 | } |
1566 | #endif | 1547 | #endif |
1567 | 1548 | ||
@@ -1802,7 +1783,8 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, | |||
1802 | goto end_coredump; | 1783 | goto end_coredump; |
1803 | } | 1784 | } |
1804 | 1785 | ||
1805 | DUMP_SEEK(dataoff); | 1786 | if (!dump_seek(file, dataoff)) |
1787 | goto end_coredump; | ||
1806 | 1788 | ||
1807 | if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0) | 1789 | if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0) |
1808 | goto end_coredump; | 1790 | goto end_coredump; |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 71e7e03ac34..5d1ed50bd46 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -1114,7 +1114,7 @@ EXPORT_SYMBOL(revalidate_disk); | |||
1114 | int check_disk_change(struct block_device *bdev) | 1114 | int check_disk_change(struct block_device *bdev) |
1115 | { | 1115 | { |
1116 | struct gendisk *disk = bdev->bd_disk; | 1116 | struct gendisk *disk = bdev->bd_disk; |
1117 | struct block_device_operations * bdops = disk->fops; | 1117 | const struct block_device_operations *bdops = disk->fops; |
1118 | 1118 | ||
1119 | if (!bdops->media_changed) | 1119 | if (!bdops->media_changed) |
1120 | return 0; | 1120 | return 0; |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8b819279001..6c4173146bb 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -772,7 +772,7 @@ static void btree_invalidatepage(struct page *page, unsigned long offset) | |||
772 | } | 772 | } |
773 | } | 773 | } |
774 | 774 | ||
775 | static struct address_space_operations btree_aops = { | 775 | static const struct address_space_operations btree_aops = { |
776 | .readpage = btree_readpage, | 776 | .readpage = btree_readpage, |
777 | .writepage = btree_writepage, | 777 | .writepage = btree_writepage, |
778 | .writepages = btree_writepages, | 778 | .writepages = btree_writepages, |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 59cba180fe8..9096fd0ca3c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -55,13 +55,13 @@ struct btrfs_iget_args { | |||
55 | struct btrfs_root *root; | 55 | struct btrfs_root *root; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static struct inode_operations btrfs_dir_inode_operations; | 58 | static const struct inode_operations btrfs_dir_inode_operations; |
59 | static struct inode_operations btrfs_symlink_inode_operations; | 59 | static const struct inode_operations btrfs_symlink_inode_operations; |
60 | static struct inode_operations btrfs_dir_ro_inode_operations; | 60 | static const struct inode_operations btrfs_dir_ro_inode_operations; |
61 | static struct inode_operations btrfs_special_inode_operations; | 61 | static const struct inode_operations btrfs_special_inode_operations; |
62 | static struct inode_operations btrfs_file_inode_operations; | 62 | static const struct inode_operations btrfs_file_inode_operations; |
63 | static struct address_space_operations btrfs_aops; | 63 | static const struct address_space_operations btrfs_aops; |
64 | static struct address_space_operations btrfs_symlink_aops; | 64 | static const struct address_space_operations btrfs_symlink_aops; |
65 | static struct file_operations btrfs_dir_file_operations; | 65 | static struct file_operations btrfs_dir_file_operations; |
66 | static struct extent_io_ops btrfs_extent_io_ops; | 66 | static struct extent_io_ops btrfs_extent_io_ops; |
67 | 67 | ||
@@ -5201,7 +5201,7 @@ static int btrfs_permission(struct inode *inode, int mask) | |||
5201 | return generic_permission(inode, mask, btrfs_check_acl); | 5201 | return generic_permission(inode, mask, btrfs_check_acl); |
5202 | } | 5202 | } |
5203 | 5203 | ||
5204 | static struct inode_operations btrfs_dir_inode_operations = { | 5204 | static const struct inode_operations btrfs_dir_inode_operations = { |
5205 | .getattr = btrfs_getattr, | 5205 | .getattr = btrfs_getattr, |
5206 | .lookup = btrfs_lookup, | 5206 | .lookup = btrfs_lookup, |
5207 | .create = btrfs_create, | 5207 | .create = btrfs_create, |
@@ -5219,7 +5219,7 @@ static struct inode_operations btrfs_dir_inode_operations = { | |||
5219 | .removexattr = btrfs_removexattr, | 5219 | .removexattr = btrfs_removexattr, |
5220 | .permission = btrfs_permission, | 5220 | .permission = btrfs_permission, |
5221 | }; | 5221 | }; |
5222 | static struct inode_operations btrfs_dir_ro_inode_operations = { | 5222 | static const struct inode_operations btrfs_dir_ro_inode_operations = { |
5223 | .lookup = btrfs_lookup, | 5223 | .lookup = btrfs_lookup, |
5224 | .permission = btrfs_permission, | 5224 | .permission = btrfs_permission, |
5225 | }; | 5225 | }; |
@@ -5259,7 +5259,7 @@ static struct extent_io_ops btrfs_extent_io_ops = { | |||
5259 | * | 5259 | * |
5260 | * For now we're avoiding this by dropping bmap. | 5260 | * For now we're avoiding this by dropping bmap. |
5261 | */ | 5261 | */ |
5262 | static struct address_space_operations btrfs_aops = { | 5262 | static const struct address_space_operations btrfs_aops = { |
5263 | .readpage = btrfs_readpage, | 5263 | .readpage = btrfs_readpage, |
5264 | .writepage = btrfs_writepage, | 5264 | .writepage = btrfs_writepage, |
5265 | .writepages = btrfs_writepages, | 5265 | .writepages = btrfs_writepages, |
@@ -5271,14 +5271,14 @@ static struct address_space_operations btrfs_aops = { | |||
5271 | .set_page_dirty = btrfs_set_page_dirty, | 5271 | .set_page_dirty = btrfs_set_page_dirty, |
5272 | }; | 5272 | }; |
5273 | 5273 | ||
5274 | static struct address_space_operations btrfs_symlink_aops = { | 5274 | static const struct address_space_operations btrfs_symlink_aops = { |
5275 | .readpage = btrfs_readpage, | 5275 | .readpage = btrfs_readpage, |
5276 | .writepage = btrfs_writepage, | 5276 | .writepage = btrfs_writepage, |
5277 | .invalidatepage = btrfs_invalidatepage, | 5277 | .invalidatepage = btrfs_invalidatepage, |
5278 | .releasepage = btrfs_releasepage, | 5278 | .releasepage = btrfs_releasepage, |
5279 | }; | 5279 | }; |
5280 | 5280 | ||
5281 | static struct inode_operations btrfs_file_inode_operations = { | 5281 | static const struct inode_operations btrfs_file_inode_operations = { |
5282 | .truncate = btrfs_truncate, | 5282 | .truncate = btrfs_truncate, |
5283 | .getattr = btrfs_getattr, | 5283 | .getattr = btrfs_getattr, |
5284 | .setattr = btrfs_setattr, | 5284 | .setattr = btrfs_setattr, |
@@ -5290,7 +5290,7 @@ static struct inode_operations btrfs_file_inode_operations = { | |||
5290 | .fallocate = btrfs_fallocate, | 5290 | .fallocate = btrfs_fallocate, |
5291 | .fiemap = btrfs_fiemap, | 5291 | .fiemap = btrfs_fiemap, |
5292 | }; | 5292 | }; |
5293 | static struct inode_operations btrfs_special_inode_operations = { | 5293 | static const struct inode_operations btrfs_special_inode_operations = { |
5294 | .getattr = btrfs_getattr, | 5294 | .getattr = btrfs_getattr, |
5295 | .setattr = btrfs_setattr, | 5295 | .setattr = btrfs_setattr, |
5296 | .permission = btrfs_permission, | 5296 | .permission = btrfs_permission, |
@@ -5299,7 +5299,7 @@ static struct inode_operations btrfs_special_inode_operations = { | |||
5299 | .listxattr = btrfs_listxattr, | 5299 | .listxattr = btrfs_listxattr, |
5300 | .removexattr = btrfs_removexattr, | 5300 | .removexattr = btrfs_removexattr, |
5301 | }; | 5301 | }; |
5302 | static struct inode_operations btrfs_symlink_inode_operations = { | 5302 | static const struct inode_operations btrfs_symlink_inode_operations = { |
5303 | .readlink = generic_readlink, | 5303 | .readlink = generic_readlink, |
5304 | .follow_link = page_follow_link_light, | 5304 | .follow_link = page_follow_link_light, |
5305 | .put_link = page_put_link, | 5305 | .put_link = page_put_link, |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 6d6d06cb6df..2db17cd66fc 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #include "export.h" | 51 | #include "export.h" |
52 | #include "compression.h" | 52 | #include "compression.h" |
53 | 53 | ||
54 | static struct super_operations btrfs_super_ops; | 54 | static const struct super_operations btrfs_super_ops; |
55 | 55 | ||
56 | static void btrfs_put_super(struct super_block *sb) | 56 | static void btrfs_put_super(struct super_block *sb) |
57 | { | 57 | { |
@@ -675,7 +675,7 @@ static int btrfs_unfreeze(struct super_block *sb) | |||
675 | return 0; | 675 | return 0; |
676 | } | 676 | } |
677 | 677 | ||
678 | static struct super_operations btrfs_super_ops = { | 678 | static const struct super_operations btrfs_super_ops = { |
679 | .delete_inode = btrfs_delete_inode, | 679 | .delete_inode = btrfs_delete_inode, |
680 | .put_super = btrfs_put_super, | 680 | .put_super = btrfs_put_super, |
681 | .sync_fs = btrfs_sync_fs, | 681 | .sync_fs = btrfs_sync_fs, |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index d91b0de7c50..30c0d45c1b5 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2605,7 +2605,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, | |||
2605 | extent); | 2605 | extent); |
2606 | cs = btrfs_file_extent_offset(src, extent); | 2606 | cs = btrfs_file_extent_offset(src, extent); |
2607 | cl = btrfs_file_extent_num_bytes(src, | 2607 | cl = btrfs_file_extent_num_bytes(src, |
2608 | extent);; | 2608 | extent); |
2609 | if (btrfs_file_extent_compression(src, | 2609 | if (btrfs_file_extent_compression(src, |
2610 | extent)) { | 2610 | extent)) { |
2611 | cs = 0; | 2611 | cs = 0; |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 606912d8f2a..fea9e898c4b 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -142,7 +142,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata, | |||
142 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); | 142 | rc = dns_resolve_server_name_to_ip(*devname, &srvIP); |
143 | if (rc != 0) { | 143 | if (rc != 0) { |
144 | 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", |
145 | __func__, *devname, rc));; | 145 | __func__, *devname, rc)); |
146 | goto compose_mount_options_err; | 146 | goto compose_mount_options_err; |
147 | } | 147 | } |
148 | /* md_len = strlen(...) + 12 for 'sep+prefixpath=' | 148 | /* md_len = strlen(...) + 12 for 'sep+prefixpath=' |
@@ -385,7 +385,7 @@ out_err: | |||
385 | goto out; | 385 | goto out; |
386 | } | 386 | } |
387 | 387 | ||
388 | struct inode_operations cifs_dfs_referral_inode_operations = { | 388 | const struct inode_operations cifs_dfs_referral_inode_operations = { |
389 | .follow_link = cifs_dfs_follow_mountpoint, | 389 | .follow_link = cifs_dfs_follow_mountpoint, |
390 | }; | 390 | }; |
391 | 391 | ||
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 3610e9958b4..d79ce2e95c2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -50,7 +50,7 @@ | |||
50 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ | 50 | #define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ |
51 | 51 | ||
52 | #ifdef CONFIG_CIFS_QUOTA | 52 | #ifdef CONFIG_CIFS_QUOTA |
53 | static struct quotactl_ops cifs_quotactl_ops; | 53 | static const struct quotactl_ops cifs_quotactl_ops; |
54 | #endif /* QUOTA */ | 54 | #endif /* QUOTA */ |
55 | 55 | ||
56 | int cifsFYI = 0; | 56 | int cifsFYI = 0; |
@@ -517,7 +517,7 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats) | |||
517 | return rc; | 517 | return rc; |
518 | } | 518 | } |
519 | 519 | ||
520 | static struct quotactl_ops cifs_quotactl_ops = { | 520 | static const struct quotactl_ops cifs_quotactl_ops = { |
521 | .set_xquota = cifs_xquota_set, | 521 | .set_xquota = cifs_xquota_set, |
522 | .get_xquota = cifs_xquota_get, | 522 | .get_xquota = cifs_xquota_get, |
523 | .set_xstate = cifs_xstate_set, | 523 | .set_xstate = cifs_xstate_set, |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 094325e3f71..ac2b24c192f 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -67,7 +67,7 @@ extern int cifs_setattr(struct dentry *, struct iattr *); | |||
67 | 67 | ||
68 | extern const struct inode_operations cifs_file_inode_ops; | 68 | extern const struct inode_operations cifs_file_inode_ops; |
69 | extern const struct inode_operations cifs_symlink_inode_ops; | 69 | extern const struct inode_operations cifs_symlink_inode_ops; |
70 | extern struct inode_operations cifs_dfs_referral_inode_operations; | 70 | extern const struct inode_operations cifs_dfs_referral_inode_operations; |
71 | 71 | ||
72 | 72 | ||
73 | /* Functions related to files and directories */ | 73 | /* Functions related to files and directories */ |
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index 00b30a2d546..542f625312f 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h | |||
@@ -582,7 +582,7 @@ extern const struct inode_operations ecryptfs_dir_iops; | |||
582 | extern const struct inode_operations ecryptfs_symlink_iops; | 582 | extern const struct inode_operations ecryptfs_symlink_iops; |
583 | extern const struct super_operations ecryptfs_sops; | 583 | extern const struct super_operations ecryptfs_sops; |
584 | extern const struct dentry_operations ecryptfs_dops; | 584 | extern const struct dentry_operations ecryptfs_dops; |
585 | extern struct address_space_operations ecryptfs_aops; | 585 | extern const struct address_space_operations ecryptfs_aops; |
586 | extern int ecryptfs_verbosity; | 586 | extern int ecryptfs_verbosity; |
587 | extern unsigned int ecryptfs_message_buf_len; | 587 | extern unsigned int ecryptfs_message_buf_len; |
588 | extern signed long ecryptfs_message_wait_timeout; | 588 | extern signed long ecryptfs_message_wait_timeout; |
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 5c6bab9786e..05772aeaa8f 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c | |||
@@ -545,7 +545,7 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block) | |||
545 | return rc; | 545 | return rc; |
546 | } | 546 | } |
547 | 547 | ||
548 | struct address_space_operations ecryptfs_aops = { | 548 | const struct address_space_operations ecryptfs_aops = { |
549 | .writepage = ecryptfs_writepage, | 549 | .writepage = ecryptfs_writepage, |
550 | .readpage = ecryptfs_readpage, | 550 | .readpage = ecryptfs_readpage, |
551 | .write_begin = ecryptfs_write_begin, | 551 | .write_begin = ecryptfs_write_begin, |
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c index b72b8588422..c18fbf3e406 100644 --- a/fs/ext2/xip.c +++ b/fs/ext2/xip.c | |||
@@ -20,7 +20,7 @@ __inode_direct_access(struct inode *inode, sector_t block, | |||
20 | void **kaddr, unsigned long *pfn) | 20 | void **kaddr, unsigned long *pfn) |
21 | { | 21 | { |
22 | struct block_device *bdev = inode->i_sb->s_bdev; | 22 | struct block_device *bdev = inode->i_sb->s_bdev; |
23 | struct block_device_operations *ops = bdev->bd_disk->fops; | 23 | const struct block_device_operations *ops = bdev->bd_disk->fops; |
24 | sector_t sector; | 24 | sector_t sector; |
25 | 25 | ||
26 | sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */ | 26 | sector = block * (PAGE_SIZE / 512); /* ext2 block to bdev sector */ |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index a8d80a7f110..72743d36050 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -720,7 +720,7 @@ static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, | |||
720 | static ssize_t ext3_quota_write(struct super_block *sb, int type, | 720 | static ssize_t ext3_quota_write(struct super_block *sb, int type, |
721 | const char *data, size_t len, loff_t off); | 721 | const char *data, size_t len, loff_t off); |
722 | 722 | ||
723 | static struct dquot_operations ext3_quota_operations = { | 723 | static const struct dquot_operations ext3_quota_operations = { |
724 | .initialize = dquot_initialize, | 724 | .initialize = dquot_initialize, |
725 | .drop = dquot_drop, | 725 | .drop = dquot_drop, |
726 | .alloc_space = dquot_alloc_space, | 726 | .alloc_space = dquot_alloc_space, |
@@ -737,7 +737,7 @@ static struct dquot_operations ext3_quota_operations = { | |||
737 | .destroy_dquot = dquot_destroy, | 737 | .destroy_dquot = dquot_destroy, |
738 | }; | 738 | }; |
739 | 739 | ||
740 | static struct quotactl_ops ext3_qctl_operations = { | 740 | static const struct quotactl_ops ext3_qctl_operations = { |
741 | .quota_on = ext3_quota_on, | 741 | .quota_on = ext3_quota_on, |
742 | .quota_off = vfs_quota_off, | 742 | .quota_off = vfs_quota_off, |
743 | .quota_sync = vfs_quota_sync, | 743 | .quota_sync = vfs_quota_sync, |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 4abd683b963..3a798737e30 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2337,7 +2337,7 @@ static int __mpage_da_writepage(struct page *page, | |||
2337 | /* | 2337 | /* |
2338 | * Rest of the page in the page_vec | 2338 | * Rest of the page in the page_vec |
2339 | * redirty then and skip then. We will | 2339 | * redirty then and skip then. We will |
2340 | * try to to write them again after | 2340 | * try to write them again after |
2341 | * starting a new transaction | 2341 | * starting a new transaction |
2342 | */ | 2342 | */ |
2343 | redirty_page_for_writepage(wbc, page); | 2343 | redirty_page_for_writepage(wbc, page); |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index a6b1ab73472..df539ba2777 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -964,7 +964,7 @@ static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, | |||
964 | static ssize_t ext4_quota_write(struct super_block *sb, int type, | 964 | static ssize_t ext4_quota_write(struct super_block *sb, int type, |
965 | const char *data, size_t len, loff_t off); | 965 | const char *data, size_t len, loff_t off); |
966 | 966 | ||
967 | static struct dquot_operations ext4_quota_operations = { | 967 | static const struct dquot_operations ext4_quota_operations = { |
968 | .initialize = dquot_initialize, | 968 | .initialize = dquot_initialize, |
969 | .drop = dquot_drop, | 969 | .drop = dquot_drop, |
970 | .alloc_space = dquot_alloc_space, | 970 | .alloc_space = dquot_alloc_space, |
@@ -985,7 +985,7 @@ static struct dquot_operations ext4_quota_operations = { | |||
985 | .destroy_dquot = dquot_destroy, | 985 | .destroy_dquot = dquot_destroy, |
986 | }; | 986 | }; |
987 | 987 | ||
988 | static struct quotactl_ops ext4_qctl_operations = { | 988 | static const struct quotactl_ops ext4_qctl_operations = { |
989 | .quota_on = ext4_quota_on, | 989 | .quota_on = ext4_quota_on, |
990 | .quota_off = vfs_quota_off, | 990 | .quota_off = vfs_quota_off, |
991 | .quota_sync = vfs_quota_sync, | 991 | .quota_sync = vfs_quota_sync, |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 28c590b7c9d..8f1cfb02a6c 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -179,7 +179,7 @@ static inline u64 gfs2_bit_search(const __le64 *ptr, u64 mask, u8 state) | |||
179 | * always aligned to a 64 bit boundary. | 179 | * always aligned to a 64 bit boundary. |
180 | * | 180 | * |
181 | * The size of the buffer is in bytes, but is it assumed that it is | 181 | * The size of the buffer is in bytes, but is it assumed that it is |
182 | * always ok to to read a complete multiple of 64 bits at the end | 182 | * always ok to read a complete multiple of 64 bits at the end |
183 | * of the block in case the end is no aligned to a natural boundary. | 183 | * of the block in case the end is no aligned to a natural boundary. |
184 | * | 184 | * |
185 | * Return: the block number (bitmap buffer scope) that was found | 185 | * Return: the block number (bitmap buffer scope) that was found |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index a93b885311d..06b7c2623f9 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -507,6 +507,13 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, | |||
507 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 507 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
508 | INIT_LIST_HEAD(&inode->i_mapping->private_list); | 508 | INIT_LIST_HEAD(&inode->i_mapping->private_list); |
509 | info = HUGETLBFS_I(inode); | 509 | info = HUGETLBFS_I(inode); |
510 | /* | ||
511 | * The policy is initialized here even if we are creating a | ||
512 | * private inode because initialization simply creates an | ||
513 | * an empty rb tree and calls spin_lock_init(), later when we | ||
514 | * call mpol_free_shared_policy() it will just return because | ||
515 | * the rb tree will still be empty. | ||
516 | */ | ||
510 | mpol_shared_policy_init(&info->policy, NULL); | 517 | mpol_shared_policy_init(&info->policy, NULL); |
511 | switch (mode & S_IFMT) { | 518 | switch (mode & S_IFMT) { |
512 | default: | 519 | default: |
@@ -931,13 +938,19 @@ static struct file_system_type hugetlbfs_fs_type = { | |||
931 | 938 | ||
932 | static struct vfsmount *hugetlbfs_vfsmount; | 939 | static struct vfsmount *hugetlbfs_vfsmount; |
933 | 940 | ||
934 | static int can_do_hugetlb_shm(void) | 941 | static int can_do_hugetlb_shm(int creat_flags) |
935 | { | 942 | { |
936 | return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group); | 943 | if (creat_flags != HUGETLB_SHMFS_INODE) |
944 | return 0; | ||
945 | if (capable(CAP_IPC_LOCK)) | ||
946 | return 1; | ||
947 | if (in_group_p(sysctl_hugetlb_shm_group)) | ||
948 | return 1; | ||
949 | return 0; | ||
937 | } | 950 | } |
938 | 951 | ||
939 | struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag, | 952 | struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag, |
940 | struct user_struct **user) | 953 | struct user_struct **user, int creat_flags) |
941 | { | 954 | { |
942 | int error = -ENOMEM; | 955 | int error = -ENOMEM; |
943 | struct file *file; | 956 | struct file *file; |
@@ -949,7 +962,7 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag, | |||
949 | if (!hugetlbfs_vfsmount) | 962 | if (!hugetlbfs_vfsmount) |
950 | return ERR_PTR(-ENOENT); | 963 | return ERR_PTR(-ENOENT); |
951 | 964 | ||
952 | if (!can_do_hugetlb_shm()) { | 965 | if (!can_do_hugetlb_shm(creat_flags)) { |
953 | *user = current_user(); | 966 | *user = current_user(); |
954 | if (user_shm_lock(size, *user)) { | 967 | if (user_shm_lock(size, *user)) { |
955 | WARN_ONCE(1, | 968 | WARN_ONCE(1, |
diff --git a/fs/inode.c b/fs/inode.c index b2ba83d2c4e..f5ff71cb3e2 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -123,7 +123,7 @@ static void wake_up_inode(struct inode *inode) | |||
123 | int inode_init_always(struct super_block *sb, struct inode *inode) | 123 | int inode_init_always(struct super_block *sb, struct inode *inode) |
124 | { | 124 | { |
125 | static const struct address_space_operations empty_aops; | 125 | static const struct address_space_operations empty_aops; |
126 | static struct inode_operations empty_iops; | 126 | static const struct inode_operations empty_iops; |
127 | static const struct file_operations empty_fops; | 127 | static const struct file_operations empty_fops; |
128 | struct address_space *const mapping = &inode->i_data; | 128 | struct address_space *const mapping = &inode->i_data; |
129 | 129 | ||
@@ -695,13 +695,15 @@ void unlock_new_inode(struct inode *inode) | |||
695 | } | 695 | } |
696 | #endif | 696 | #endif |
697 | /* | 697 | /* |
698 | * This is special! We do not need the spinlock | 698 | * This is special! We do not need the spinlock when clearing I_LOCK, |
699 | * when clearing I_LOCK, because we're guaranteed | 699 | * because we're guaranteed that nobody else tries to do anything about |
700 | * that nobody else tries to do anything about the | 700 | * the state of the inode when it is locked, as we just created it (so |
701 | * state of the inode when it is locked, as we | 701 | * there can be no old holders that haven't tested I_LOCK). |
702 | * just created it (so there can be no old holders | 702 | * However we must emit the memory barrier so that other CPUs reliably |
703 | * that haven't tested I_LOCK). | 703 | * see the clearing of I_LOCK after the other inode initialisation has |
704 | * completed. | ||
704 | */ | 705 | */ |
706 | smp_mb(); | ||
705 | WARN_ON((inode->i_state & (I_LOCK|I_NEW)) != (I_LOCK|I_NEW)); | 707 | WARN_ON((inode->i_state & (I_LOCK|I_NEW)) != (I_LOCK|I_NEW)); |
706 | inode->i_state &= ~(I_LOCK|I_NEW); | 708 | inode->i_state &= ~(I_LOCK|I_NEW); |
707 | wake_up_inode(inode); | 709 | wake_up_inode(inode); |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 0035c021395..9a80e8e595d 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -123,7 +123,7 @@ static struct dentry *jffs2_get_parent(struct dentry *child) | |||
123 | return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino)); | 123 | return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino)); |
124 | } | 124 | } |
125 | 125 | ||
126 | static struct export_operations jffs2_export_ops = { | 126 | static const struct export_operations jffs2_export_ops = { |
127 | .get_parent = jffs2_get_parent, | 127 | .get_parent = jffs2_get_parent, |
128 | .fh_to_dentry = jffs2_fh_to_dentry, | 128 | .fh_to_dentry = jffs2_fh_to_dentry, |
129 | .fh_to_parent = jffs2_fh_to_parent, | 129 | .fh_to_parent = jffs2_fh_to_parent, |
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 1f3b0fc0d35..fc9032dc886 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c | |||
@@ -166,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) | |||
166 | */ | 166 | */ |
167 | if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) | 167 | if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid) |
168 | continue; | 168 | continue; |
169 | if (!nlm_cmp_addr(nlm_addr(block->b_host), addr)) | 169 | if (!rpc_cmp_addr(nlm_addr(block->b_host), addr)) |
170 | continue; | 170 | continue; |
171 | if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) | 171 | if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0) |
172 | continue; | 172 | continue; |
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 4336adba952..c81249fef11 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -458,7 +458,7 @@ static void nlmclnt_locks_release_private(struct file_lock *fl) | |||
458 | nlm_put_lockowner(fl->fl_u.nfs_fl.owner); | 458 | nlm_put_lockowner(fl->fl_u.nfs_fl.owner); |
459 | } | 459 | } |
460 | 460 | ||
461 | static struct file_lock_operations nlmclnt_lock_ops = { | 461 | static const struct file_lock_operations nlmclnt_lock_ops = { |
462 | .fl_copy_lock = nlmclnt_locks_copy_lock, | 462 | .fl_copy_lock = nlmclnt_locks_copy_lock, |
463 | .fl_release_private = nlmclnt_locks_release_private, | 463 | .fl_release_private = nlmclnt_locks_release_private, |
464 | }; | 464 | }; |
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 7cb076ac6b4..4600c2037b8 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -111,7 +111,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) | |||
111 | */ | 111 | */ |
112 | chain = &nlm_hosts[nlm_hash_address(ni->sap)]; | 112 | chain = &nlm_hosts[nlm_hash_address(ni->sap)]; |
113 | hlist_for_each_entry(host, pos, chain, h_hash) { | 113 | hlist_for_each_entry(host, pos, chain, h_hash) { |
114 | if (!nlm_cmp_addr(nlm_addr(host), ni->sap)) | 114 | if (!rpc_cmp_addr(nlm_addr(host), ni->sap)) |
115 | continue; | 115 | continue; |
116 | 116 | ||
117 | /* See if we have an NSM handle for this client */ | 117 | /* See if we have an NSM handle for this client */ |
@@ -125,7 +125,7 @@ static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni) | |||
125 | if (host->h_server != ni->server) | 125 | if (host->h_server != ni->server) |
126 | continue; | 126 | continue; |
127 | if (ni->server && | 127 | if (ni->server && |
128 | !nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap)) | 128 | !rpc_cmp_addr(nlm_srcaddr(host), ni->src_sap)) |
129 | continue; | 129 | continue; |
130 | 130 | ||
131 | /* Move to head of hash chain. */ | 131 | /* Move to head of hash chain. */ |
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 30c933188dd..f956651d0f6 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -209,7 +209,7 @@ static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap) | |||
209 | struct nsm_handle *nsm; | 209 | struct nsm_handle *nsm; |
210 | 210 | ||
211 | list_for_each_entry(nsm, &nsm_handles, sm_link) | 211 | list_for_each_entry(nsm, &nsm_handles, sm_link) |
212 | if (nlm_cmp_addr(nsm_addr(nsm), sap)) | 212 | if (rpc_cmp_addr(nsm_addr(nsm), sap)) |
213 | return nsm; | 213 | return nsm; |
214 | return NULL; | 214 | return NULL; |
215 | } | 215 | } |
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index e577a78d7ba..d1001790fa9 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c | |||
@@ -705,7 +705,7 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2) | |||
705 | return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; | 705 | return fl1->fl_owner == fl2->fl_owner && fl1->fl_pid == fl2->fl_pid; |
706 | } | 706 | } |
707 | 707 | ||
708 | struct lock_manager_operations nlmsvc_lock_operations = { | 708 | const struct lock_manager_operations nlmsvc_lock_operations = { |
709 | .fl_compare_owner = nlmsvc_same_owner, | 709 | .fl_compare_owner = nlmsvc_same_owner, |
710 | .fl_notify = nlmsvc_notify_blocked, | 710 | .fl_notify = nlmsvc_notify_blocked, |
711 | .fl_grant = nlmsvc_grant_deferred, | 711 | .fl_grant = nlmsvc_grant_deferred, |
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 9e4d6aab611..ad478da7ca6 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c | |||
@@ -417,7 +417,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); | |||
417 | static int | 417 | static int |
418 | nlmsvc_match_ip(void *datap, struct nlm_host *host) | 418 | nlmsvc_match_ip(void *datap, struct nlm_host *host) |
419 | { | 419 | { |
420 | return nlm_cmp_addr(nlm_srcaddr(host), datap); | 420 | return rpc_cmp_addr(nlm_srcaddr(host), datap); |
421 | } | 421 | } |
422 | 422 | ||
423 | /** | 423 | /** |
diff --git a/fs/locks.c b/fs/locks.c index 19ee18a6829..a8794f233bc 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -434,7 +434,7 @@ static int lease_mylease_callback(struct file_lock *fl, struct file_lock *try) | |||
434 | return fl->fl_file == try->fl_file; | 434 | return fl->fl_file == try->fl_file; |
435 | } | 435 | } |
436 | 436 | ||
437 | static struct lock_manager_operations lease_manager_ops = { | 437 | static const struct lock_manager_operations lease_manager_ops = { |
438 | .fl_break = lease_break_callback, | 438 | .fl_break = lease_break_callback, |
439 | .fl_release_private = lease_release_private_callback, | 439 | .fl_release_private = lease_release_private_callback, |
440 | .fl_mylease = lease_mylease_callback, | 440 | .fl_mylease = lease_mylease_callback, |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index e5a2dac5f71..76b0aa0f73b 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -222,7 +222,7 @@ static unsigned decode_sessionid(struct xdr_stream *xdr, | |||
222 | 222 | ||
223 | p = read_buf(xdr, len); | 223 | p = read_buf(xdr, len); |
224 | if (unlikely(p == NULL)) | 224 | if (unlikely(p == NULL)) |
225 | return htonl(NFS4ERR_RESOURCE);; | 225 | return htonl(NFS4ERR_RESOURCE); |
226 | 226 | ||
227 | memcpy(sid->data, p, len); | 227 | memcpy(sid->data, p, len); |
228 | return 0; | 228 | return 0; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 1434080aefe..2ef4fecf398 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -638,7 +638,7 @@ static void nfs4_fl_release_lock(struct file_lock *fl) | |||
638 | nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner); | 638 | nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner); |
639 | } | 639 | } |
640 | 640 | ||
641 | static struct file_lock_operations nfs4_fl_lock_ops = { | 641 | static const struct file_lock_operations nfs4_fl_lock_ops = { |
642 | .fl_copy_lock = nfs4_fl_copy_lock, | 642 | .fl_copy_lock = nfs4_fl_copy_lock, |
643 | .fl_release_private = nfs4_fl_release_lock, | 643 | .fl_release_private = nfs4_fl_release_lock, |
644 | }; | 644 | }; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index d9462643155..984a5ebcc1d 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -1341,6 +1341,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) | |||
1341 | if (rv) | 1341 | if (rv) |
1342 | goto out; | 1342 | goto out; |
1343 | rv = check_nfsd_access(exp, rqstp); | 1343 | rv = check_nfsd_access(exp, rqstp); |
1344 | if (rv) | ||
1345 | fh_put(fhp); | ||
1344 | out: | 1346 | out: |
1345 | exp_put(exp); | 1347 | exp_put(exp); |
1346 | return rv; | 1348 | return rv; |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 01d4ec1c88e..edf926e1062 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -814,17 +814,6 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, | |||
814 | return p; | 814 | return p; |
815 | } | 815 | } |
816 | 816 | ||
817 | static __be32 * | ||
818 | encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, | ||
819 | struct svc_fh *fhp) | ||
820 | { | ||
821 | p = encode_post_op_attr(cd->rqstp, p, fhp); | ||
822 | *p++ = xdr_one; /* yes, a file handle follows */ | ||
823 | p = encode_fh(p, fhp); | ||
824 | fh_put(fhp); | ||
825 | return p; | ||
826 | } | ||
827 | |||
828 | static int | 817 | static int |
829 | compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, | 818 | compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, |
830 | const char *name, int namlen) | 819 | const char *name, int namlen) |
@@ -836,29 +825,54 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, | |||
836 | dparent = cd->fh.fh_dentry; | 825 | dparent = cd->fh.fh_dentry; |
837 | exp = cd->fh.fh_export; | 826 | exp = cd->fh.fh_export; |
838 | 827 | ||
839 | fh_init(fhp, NFS3_FHSIZE); | ||
840 | if (isdotent(name, namlen)) { | 828 | if (isdotent(name, namlen)) { |
841 | if (namlen == 2) { | 829 | if (namlen == 2) { |
842 | dchild = dget_parent(dparent); | 830 | dchild = dget_parent(dparent); |
843 | if (dchild == dparent) { | 831 | if (dchild == dparent) { |
844 | /* filesystem root - cannot return filehandle for ".." */ | 832 | /* filesystem root - cannot return filehandle for ".." */ |
845 | dput(dchild); | 833 | dput(dchild); |
846 | return 1; | 834 | return -ENOENT; |
847 | } | 835 | } |
848 | } else | 836 | } else |
849 | dchild = dget(dparent); | 837 | dchild = dget(dparent); |
850 | } else | 838 | } else |
851 | dchild = lookup_one_len(name, dparent, namlen); | 839 | dchild = lookup_one_len(name, dparent, namlen); |
852 | if (IS_ERR(dchild)) | 840 | if (IS_ERR(dchild)) |
853 | return 1; | 841 | return -ENOENT; |
854 | if (d_mountpoint(dchild) || | 842 | rv = -ENOENT; |
855 | fh_compose(fhp, exp, dchild, &cd->fh) != 0 || | 843 | if (d_mountpoint(dchild)) |
856 | !dchild->d_inode) | 844 | goto out; |
857 | rv = 1; | 845 | rv = fh_compose(fhp, exp, dchild, &cd->fh); |
846 | if (rv) | ||
847 | goto out; | ||
848 | if (!dchild->d_inode) | ||
849 | goto out; | ||
850 | rv = 0; | ||
851 | out: | ||
858 | dput(dchild); | 852 | dput(dchild); |
859 | return rv; | 853 | return rv; |
860 | } | 854 | } |
861 | 855 | ||
856 | __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen) | ||
857 | { | ||
858 | struct svc_fh fh; | ||
859 | int err; | ||
860 | |||
861 | fh_init(&fh, NFS3_FHSIZE); | ||
862 | err = compose_entry_fh(cd, &fh, name, namlen); | ||
863 | if (err) { | ||
864 | *p++ = 0; | ||
865 | *p++ = 0; | ||
866 | goto out; | ||
867 | } | ||
868 | p = encode_post_op_attr(cd->rqstp, p, &fh); | ||
869 | *p++ = xdr_one; /* yes, a file handle follows */ | ||
870 | p = encode_fh(p, &fh); | ||
871 | out: | ||
872 | fh_put(&fh); | ||
873 | return p; | ||
874 | } | ||
875 | |||
862 | /* | 876 | /* |
863 | * Encode a directory entry. This one works for both normal readdir | 877 | * Encode a directory entry. This one works for both normal readdir |
864 | * and readdirplus. | 878 | * and readdirplus. |
@@ -929,16 +943,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, | |||
929 | 943 | ||
930 | p = encode_entry_baggage(cd, p, name, namlen, ino); | 944 | p = encode_entry_baggage(cd, p, name, namlen, ino); |
931 | 945 | ||
932 | /* throw in readdirplus baggage */ | 946 | if (plus) |
933 | if (plus) { | 947 | p = encode_entryplus_baggage(cd, p, name, namlen); |
934 | struct svc_fh fh; | ||
935 | |||
936 | if (compose_entry_fh(cd, &fh, name, namlen) > 0) { | ||
937 | *p++ = 0; | ||
938 | *p++ = 0; | ||
939 | } else | ||
940 | p = encode_entryplus_baggage(cd, p, &fh); | ||
941 | } | ||
942 | num_entry_words = p - cd->buffer; | 948 | num_entry_words = p - cd->buffer; |
943 | } else if (cd->rqstp->rq_respages[pn+1] != NULL) { | 949 | } else if (cd->rqstp->rq_respages[pn+1] != NULL) { |
944 | /* temporarily encode entry into next page, then move back to | 950 | /* temporarily encode entry into next page, then move back to |
@@ -951,17 +957,8 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, | |||
951 | 957 | ||
952 | p1 = encode_entry_baggage(cd, p1, name, namlen, ino); | 958 | p1 = encode_entry_baggage(cd, p1, name, namlen, ino); |
953 | 959 | ||
954 | /* throw in readdirplus baggage */ | 960 | if (plus) |
955 | if (plus) { | 961 | p = encode_entryplus_baggage(cd, p1, name, namlen); |
956 | struct svc_fh fh; | ||
957 | |||
958 | if (compose_entry_fh(cd, &fh, name, namlen) > 0) { | ||
959 | /* zero out the filehandle */ | ||
960 | *p1++ = 0; | ||
961 | *p1++ = 0; | ||
962 | } else | ||
963 | p1 = encode_entryplus_baggage(cd, p1, &fh); | ||
964 | } | ||
965 | 962 | ||
966 | /* determine entry word length and lengths to go in pages */ | 963 | /* determine entry word length and lengths to go in pages */ |
967 | num_entry_words = p1 - tmp; | 964 | num_entry_words = p1 - tmp; |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 54b8b4140c8..725d02f210e 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -321,7 +321,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
321 | deny = ~pas.group & pas.other; | 321 | deny = ~pas.group & pas.other; |
322 | if (deny) { | 322 | if (deny) { |
323 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; | 323 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; |
324 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; | 324 | ace->flag = eflag; |
325 | ace->access_mask = deny_mask_from_posix(deny, flags); | 325 | ace->access_mask = deny_mask_from_posix(deny, flags); |
326 | ace->whotype = NFS4_ACL_WHO_GROUP; | 326 | ace->whotype = NFS4_ACL_WHO_GROUP; |
327 | ace++; | 327 | ace++; |
@@ -335,7 +335,7 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, | |||
335 | if (deny) { | 335 | if (deny) { |
336 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; | 336 | ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE; |
337 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; | 337 | ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP; |
338 | ace->access_mask = mask_from_posix(deny, flags); | 338 | ace->access_mask = deny_mask_from_posix(deny, flags); |
339 | ace->whotype = NFS4_ACL_WHO_NAMED; | 339 | ace->whotype = NFS4_ACL_WHO_NAMED; |
340 | ace->who = pa->e_id; | 340 | ace->who = pa->e_id; |
341 | ace++; | 341 | ace++; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 3fd23f7acec..24e8d78f8dd 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -43,25 +43,30 @@ | |||
43 | #include <linux/sunrpc/xdr.h> | 43 | #include <linux/sunrpc/xdr.h> |
44 | #include <linux/sunrpc/svc.h> | 44 | #include <linux/sunrpc/svc.h> |
45 | #include <linux/sunrpc/clnt.h> | 45 | #include <linux/sunrpc/clnt.h> |
46 | #include <linux/sunrpc/svcsock.h> | ||
46 | #include <linux/nfsd/nfsd.h> | 47 | #include <linux/nfsd/nfsd.h> |
47 | #include <linux/nfsd/state.h> | 48 | #include <linux/nfsd/state.h> |
48 | #include <linux/sunrpc/sched.h> | 49 | #include <linux/sunrpc/sched.h> |
49 | #include <linux/nfs4.h> | 50 | #include <linux/nfs4.h> |
51 | #include <linux/sunrpc/xprtsock.h> | ||
50 | 52 | ||
51 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 53 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
52 | 54 | ||
53 | #define NFSPROC4_CB_NULL 0 | 55 | #define NFSPROC4_CB_NULL 0 |
54 | #define NFSPROC4_CB_COMPOUND 1 | 56 | #define NFSPROC4_CB_COMPOUND 1 |
57 | #define NFS4_STATEID_SIZE 16 | ||
55 | 58 | ||
56 | /* Index of predefined Linux callback client operations */ | 59 | /* Index of predefined Linux callback client operations */ |
57 | 60 | ||
58 | enum { | 61 | enum { |
59 | NFSPROC4_CLNT_CB_NULL = 0, | 62 | NFSPROC4_CLNT_CB_NULL = 0, |
60 | NFSPROC4_CLNT_CB_RECALL, | 63 | NFSPROC4_CLNT_CB_RECALL, |
64 | NFSPROC4_CLNT_CB_SEQUENCE, | ||
61 | }; | 65 | }; |
62 | 66 | ||
63 | enum nfs_cb_opnum4 { | 67 | enum nfs_cb_opnum4 { |
64 | OP_CB_RECALL = 4, | 68 | OP_CB_RECALL = 4, |
69 | OP_CB_SEQUENCE = 11, | ||
65 | }; | 70 | }; |
66 | 71 | ||
67 | #define NFS4_MAXTAGLEN 20 | 72 | #define NFS4_MAXTAGLEN 20 |
@@ -70,17 +75,29 @@ enum nfs_cb_opnum4 { | |||
70 | #define NFS4_dec_cb_null_sz 0 | 75 | #define NFS4_dec_cb_null_sz 0 |
71 | #define cb_compound_enc_hdr_sz 4 | 76 | #define cb_compound_enc_hdr_sz 4 |
72 | #define cb_compound_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2)) | 77 | #define cb_compound_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2)) |
78 | #define sessionid_sz (NFS4_MAX_SESSIONID_LEN >> 2) | ||
79 | #define cb_sequence_enc_sz (sessionid_sz + 4 + \ | ||
80 | 1 /* no referring calls list yet */) | ||
81 | #define cb_sequence_dec_sz (op_dec_sz + sessionid_sz + 4) | ||
82 | |||
73 | #define op_enc_sz 1 | 83 | #define op_enc_sz 1 |
74 | #define op_dec_sz 2 | 84 | #define op_dec_sz 2 |
75 | #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) | 85 | #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) |
76 | #define enc_stateid_sz (NFS4_STATEID_SIZE >> 2) | 86 | #define enc_stateid_sz (NFS4_STATEID_SIZE >> 2) |
77 | #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ | 87 | #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ |
88 | cb_sequence_enc_sz + \ | ||
78 | 1 + enc_stateid_sz + \ | 89 | 1 + enc_stateid_sz + \ |
79 | enc_nfs4_fh_sz) | 90 | enc_nfs4_fh_sz) |
80 | 91 | ||
81 | #define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \ | 92 | #define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \ |
93 | cb_sequence_dec_sz + \ | ||
82 | op_dec_sz) | 94 | op_dec_sz) |
83 | 95 | ||
96 | struct nfs4_rpc_args { | ||
97 | void *args_op; | ||
98 | struct nfsd4_cb_sequence args_seq; | ||
99 | }; | ||
100 | |||
84 | /* | 101 | /* |
85 | * Generic encode routines from fs/nfs/nfs4xdr.c | 102 | * Generic encode routines from fs/nfs/nfs4xdr.c |
86 | */ | 103 | */ |
@@ -137,11 +154,13 @@ xdr_error: \ | |||
137 | } while (0) | 154 | } while (0) |
138 | 155 | ||
139 | struct nfs4_cb_compound_hdr { | 156 | struct nfs4_cb_compound_hdr { |
140 | int status; | 157 | /* args */ |
141 | u32 ident; | 158 | u32 ident; /* minorversion 0 only */ |
142 | u32 nops; | 159 | u32 nops; |
143 | __be32 *nops_p; | 160 | __be32 *nops_p; |
144 | u32 minorversion; | 161 | u32 minorversion; |
162 | /* res */ | ||
163 | int status; | ||
145 | u32 taglen; | 164 | u32 taglen; |
146 | char *tag; | 165 | char *tag; |
147 | }; | 166 | }; |
@@ -238,6 +257,27 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp, | |||
238 | hdr->nops++; | 257 | hdr->nops++; |
239 | } | 258 | } |
240 | 259 | ||
260 | static void | ||
261 | encode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *args, | ||
262 | struct nfs4_cb_compound_hdr *hdr) | ||
263 | { | ||
264 | __be32 *p; | ||
265 | |||
266 | if (hdr->minorversion == 0) | ||
267 | return; | ||
268 | |||
269 | RESERVE_SPACE(1 + NFS4_MAX_SESSIONID_LEN + 20); | ||
270 | |||
271 | WRITE32(OP_CB_SEQUENCE); | ||
272 | WRITEMEM(args->cbs_clp->cl_sessionid.data, NFS4_MAX_SESSIONID_LEN); | ||
273 | WRITE32(args->cbs_clp->cl_cb_seq_nr); | ||
274 | WRITE32(0); /* slotid, always 0 */ | ||
275 | WRITE32(0); /* highest slotid always 0 */ | ||
276 | WRITE32(0); /* cachethis always 0 */ | ||
277 | WRITE32(0); /* FIXME: support referring_call_lists */ | ||
278 | hdr->nops++; | ||
279 | } | ||
280 | |||
241 | static int | 281 | static int |
242 | nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | 282 | nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) |
243 | { | 283 | { |
@@ -249,15 +289,19 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) | |||
249 | } | 289 | } |
250 | 290 | ||
251 | static int | 291 | static int |
252 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args) | 292 | nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, |
293 | struct nfs4_rpc_args *rpc_args) | ||
253 | { | 294 | { |
254 | struct xdr_stream xdr; | 295 | struct xdr_stream xdr; |
296 | struct nfs4_delegation *args = rpc_args->args_op; | ||
255 | struct nfs4_cb_compound_hdr hdr = { | 297 | struct nfs4_cb_compound_hdr hdr = { |
256 | .ident = args->dl_ident, | 298 | .ident = args->dl_ident, |
299 | .minorversion = rpc_args->args_seq.cbs_minorversion, | ||
257 | }; | 300 | }; |
258 | 301 | ||
259 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 302 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
260 | encode_cb_compound_hdr(&xdr, &hdr); | 303 | encode_cb_compound_hdr(&xdr, &hdr); |
304 | encode_cb_sequence(&xdr, &rpc_args->args_seq, &hdr); | ||
261 | encode_cb_recall(&xdr, args, &hdr); | 305 | encode_cb_recall(&xdr, args, &hdr); |
262 | encode_cb_nops(&hdr); | 306 | encode_cb_nops(&hdr); |
263 | return 0; | 307 | return 0; |
@@ -299,6 +343,57 @@ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) | |||
299 | return 0; | 343 | return 0; |
300 | } | 344 | } |
301 | 345 | ||
346 | /* | ||
347 | * Our current back channel implmentation supports a single backchannel | ||
348 | * with a single slot. | ||
349 | */ | ||
350 | static int | ||
351 | decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_cb_sequence *res, | ||
352 | struct rpc_rqst *rqstp) | ||
353 | { | ||
354 | struct nfs4_sessionid id; | ||
355 | int status; | ||
356 | u32 dummy; | ||
357 | __be32 *p; | ||
358 | |||
359 | if (res->cbs_minorversion == 0) | ||
360 | return 0; | ||
361 | |||
362 | status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE); | ||
363 | if (status) | ||
364 | return status; | ||
365 | |||
366 | /* | ||
367 | * If the server returns different values for sessionID, slotID or | ||
368 | * sequence number, the server is looney tunes. | ||
369 | */ | ||
370 | status = -ESERVERFAULT; | ||
371 | |||
372 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); | ||
373 | memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); | ||
374 | p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); | ||
375 | if (memcmp(id.data, res->cbs_clp->cl_sessionid.data, | ||
376 | NFS4_MAX_SESSIONID_LEN)) { | ||
377 | dprintk("%s Invalid session id\n", __func__); | ||
378 | goto out; | ||
379 | } | ||
380 | READ32(dummy); | ||
381 | if (dummy != res->cbs_clp->cl_cb_seq_nr) { | ||
382 | dprintk("%s Invalid sequence number\n", __func__); | ||
383 | goto out; | ||
384 | } | ||
385 | READ32(dummy); /* slotid must be 0 */ | ||
386 | if (dummy != 0) { | ||
387 | dprintk("%s Invalid slotid\n", __func__); | ||
388 | goto out; | ||
389 | } | ||
390 | /* FIXME: process highest slotid and target highest slotid */ | ||
391 | status = 0; | ||
392 | out: | ||
393 | return status; | ||
394 | } | ||
395 | |||
396 | |||
302 | static int | 397 | static int |
303 | nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) | 398 | nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) |
304 | { | 399 | { |
@@ -306,7 +401,8 @@ nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) | |||
306 | } | 401 | } |
307 | 402 | ||
308 | static int | 403 | static int |
309 | nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p) | 404 | nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p, |
405 | struct nfsd4_cb_sequence *seq) | ||
310 | { | 406 | { |
311 | struct xdr_stream xdr; | 407 | struct xdr_stream xdr; |
312 | struct nfs4_cb_compound_hdr hdr; | 408 | struct nfs4_cb_compound_hdr hdr; |
@@ -316,6 +412,11 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p) | |||
316 | status = decode_cb_compound_hdr(&xdr, &hdr); | 412 | status = decode_cb_compound_hdr(&xdr, &hdr); |
317 | if (status) | 413 | if (status) |
318 | goto out; | 414 | goto out; |
415 | if (seq) { | ||
416 | status = decode_cb_sequence(&xdr, seq, rqstp); | ||
417 | if (status) | ||
418 | goto out; | ||
419 | } | ||
319 | status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); | 420 | status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); |
320 | out: | 421 | out: |
321 | return status; | 422 | return status; |
@@ -377,16 +478,15 @@ static int max_cb_time(void) | |||
377 | 478 | ||
378 | int setup_callback_client(struct nfs4_client *clp) | 479 | int setup_callback_client(struct nfs4_client *clp) |
379 | { | 480 | { |
380 | struct sockaddr_in addr; | ||
381 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; | 481 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
382 | struct rpc_timeout timeparms = { | 482 | struct rpc_timeout timeparms = { |
383 | .to_initval = max_cb_time(), | 483 | .to_initval = max_cb_time(), |
384 | .to_retries = 0, | 484 | .to_retries = 0, |
385 | }; | 485 | }; |
386 | struct rpc_create_args args = { | 486 | struct rpc_create_args args = { |
387 | .protocol = IPPROTO_TCP, | 487 | .protocol = XPRT_TRANSPORT_TCP, |
388 | .address = (struct sockaddr *)&addr, | 488 | .address = (struct sockaddr *) &cb->cb_addr, |
389 | .addrsize = sizeof(addr), | 489 | .addrsize = cb->cb_addrlen, |
390 | .timeout = &timeparms, | 490 | .timeout = &timeparms, |
391 | .program = &cb_program, | 491 | .program = &cb_program, |
392 | .prognumber = cb->cb_prog, | 492 | .prognumber = cb->cb_prog, |
@@ -399,13 +499,10 @@ int setup_callback_client(struct nfs4_client *clp) | |||
399 | 499 | ||
400 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) | 500 | if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) |
401 | return -EINVAL; | 501 | return -EINVAL; |
402 | 502 | if (cb->cb_minorversion) { | |
403 | /* Initialize address */ | 503 | args.bc_xprt = clp->cl_cb_xprt; |
404 | memset(&addr, 0, sizeof(addr)); | 504 | args.protocol = XPRT_TRANSPORT_BC_TCP; |
405 | addr.sin_family = AF_INET; | 505 | } |
406 | addr.sin_port = htons(cb->cb_port); | ||
407 | addr.sin_addr.s_addr = htonl(cb->cb_addr); | ||
408 | |||
409 | /* Create RPC client */ | 506 | /* Create RPC client */ |
410 | client = rpc_create(&args); | 507 | client = rpc_create(&args); |
411 | if (IS_ERR(client)) { | 508 | if (IS_ERR(client)) { |
@@ -439,42 +536,29 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { | |||
439 | .rpc_call_done = nfsd4_cb_probe_done, | 536 | .rpc_call_done = nfsd4_cb_probe_done, |
440 | }; | 537 | }; |
441 | 538 | ||
442 | static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb) | 539 | static struct rpc_cred *callback_cred; |
443 | { | ||
444 | struct auth_cred acred = { | ||
445 | .machine_cred = 1 | ||
446 | }; | ||
447 | 540 | ||
448 | /* | 541 | int set_callback_cred(void) |
449 | * Note in the gss case this doesn't actually have to wait for a | 542 | { |
450 | * gss upcall (or any calls to the client); this just creates a | 543 | callback_cred = rpc_lookup_machine_cred(); |
451 | * non-uptodate cred which the rpc state machine will fill in with | 544 | if (!callback_cred) |
452 | * a refresh_upcall later. | 545 | return -ENOMEM; |
453 | */ | 546 | return 0; |
454 | return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred, | ||
455 | RPCAUTH_LOOKUP_NEW); | ||
456 | } | 547 | } |
457 | 548 | ||
549 | |||
458 | void do_probe_callback(struct nfs4_client *clp) | 550 | void do_probe_callback(struct nfs4_client *clp) |
459 | { | 551 | { |
460 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; | 552 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
461 | struct rpc_message msg = { | 553 | struct rpc_message msg = { |
462 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], | 554 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], |
463 | .rpc_argp = clp, | 555 | .rpc_argp = clp, |
556 | .rpc_cred = callback_cred | ||
464 | }; | 557 | }; |
465 | struct rpc_cred *cred; | ||
466 | int status; | 558 | int status; |
467 | 559 | ||
468 | cred = lookup_cb_cred(cb); | ||
469 | if (IS_ERR(cred)) { | ||
470 | status = PTR_ERR(cred); | ||
471 | goto out; | ||
472 | } | ||
473 | cb->cb_cred = cred; | ||
474 | msg.rpc_cred = cb->cb_cred; | ||
475 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, | 560 | status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, |
476 | &nfsd4_cb_probe_ops, (void *)clp); | 561 | &nfsd4_cb_probe_ops, (void *)clp); |
477 | out: | ||
478 | if (status) { | 562 | if (status) { |
479 | warn_no_callback_path(clp, status); | 563 | warn_no_callback_path(clp, status); |
480 | put_nfs4_client(clp); | 564 | put_nfs4_client(clp); |
@@ -503,11 +587,95 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
503 | do_probe_callback(clp); | 587 | do_probe_callback(clp); |
504 | } | 588 | } |
505 | 589 | ||
590 | /* | ||
591 | * There's currently a single callback channel slot. | ||
592 | * If the slot is available, then mark it busy. Otherwise, set the | ||
593 | * thread for sleeping on the callback RPC wait queue. | ||
594 | */ | ||
595 | static int nfsd41_cb_setup_sequence(struct nfs4_client *clp, | ||
596 | struct rpc_task *task) | ||
597 | { | ||
598 | struct nfs4_rpc_args *args = task->tk_msg.rpc_argp; | ||
599 | u32 *ptr = (u32 *)clp->cl_sessionid.data; | ||
600 | int status = 0; | ||
601 | |||
602 | dprintk("%s: %u:%u:%u:%u\n", __func__, | ||
603 | ptr[0], ptr[1], ptr[2], ptr[3]); | ||
604 | |||
605 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { | ||
606 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); | ||
607 | dprintk("%s slot is busy\n", __func__); | ||
608 | status = -EAGAIN; | ||
609 | goto out; | ||
610 | } | ||
611 | |||
612 | /* | ||
613 | * We'll need the clp during XDR encoding and decoding, | ||
614 | * and the sequence during decoding to verify the reply | ||
615 | */ | ||
616 | args->args_seq.cbs_clp = clp; | ||
617 | task->tk_msg.rpc_resp = &args->args_seq; | ||
618 | |||
619 | out: | ||
620 | dprintk("%s status=%d\n", __func__, status); | ||
621 | return status; | ||
622 | } | ||
623 | |||
624 | /* | ||
625 | * TODO: cb_sequence should support referring call lists, cachethis, multiple | ||
626 | * slots, and mark callback channel down on communication errors. | ||
627 | */ | ||
628 | static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata) | ||
629 | { | ||
630 | struct nfs4_delegation *dp = calldata; | ||
631 | struct nfs4_client *clp = dp->dl_client; | ||
632 | struct nfs4_rpc_args *args = task->tk_msg.rpc_argp; | ||
633 | u32 minorversion = clp->cl_cb_conn.cb_minorversion; | ||
634 | int status = 0; | ||
635 | |||
636 | args->args_seq.cbs_minorversion = minorversion; | ||
637 | if (minorversion) { | ||
638 | status = nfsd41_cb_setup_sequence(clp, task); | ||
639 | if (status) { | ||
640 | if (status != -EAGAIN) { | ||
641 | /* terminate rpc task */ | ||
642 | task->tk_status = status; | ||
643 | task->tk_action = NULL; | ||
644 | } | ||
645 | return; | ||
646 | } | ||
647 | } | ||
648 | rpc_call_start(task); | ||
649 | } | ||
650 | |||
651 | static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | ||
652 | { | ||
653 | struct nfs4_delegation *dp = calldata; | ||
654 | struct nfs4_client *clp = dp->dl_client; | ||
655 | |||
656 | dprintk("%s: minorversion=%d\n", __func__, | ||
657 | clp->cl_cb_conn.cb_minorversion); | ||
658 | |||
659 | if (clp->cl_cb_conn.cb_minorversion) { | ||
660 | /* No need for lock, access serialized in nfsd4_cb_prepare */ | ||
661 | ++clp->cl_cb_seq_nr; | ||
662 | clear_bit(0, &clp->cl_cb_slot_busy); | ||
663 | rpc_wake_up_next(&clp->cl_cb_waitq); | ||
664 | dprintk("%s: freed slot, new seqid=%d\n", __func__, | ||
665 | clp->cl_cb_seq_nr); | ||
666 | |||
667 | /* We're done looking into the sequence information */ | ||
668 | task->tk_msg.rpc_resp = NULL; | ||
669 | } | ||
670 | } | ||
671 | |||
506 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | 672 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) |
507 | { | 673 | { |
508 | struct nfs4_delegation *dp = calldata; | 674 | struct nfs4_delegation *dp = calldata; |
509 | struct nfs4_client *clp = dp->dl_client; | 675 | struct nfs4_client *clp = dp->dl_client; |
510 | 676 | ||
677 | nfsd4_cb_done(task, calldata); | ||
678 | |||
511 | switch (task->tk_status) { | 679 | switch (task->tk_status) { |
512 | case -EIO: | 680 | case -EIO: |
513 | /* Network partition? */ | 681 | /* Network partition? */ |
@@ -520,16 +688,19 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
520 | break; | 688 | break; |
521 | default: | 689 | default: |
522 | /* success, or error we can't handle */ | 690 | /* success, or error we can't handle */ |
523 | return; | 691 | goto done; |
524 | } | 692 | } |
525 | if (dp->dl_retries--) { | 693 | if (dp->dl_retries--) { |
526 | rpc_delay(task, 2*HZ); | 694 | rpc_delay(task, 2*HZ); |
527 | task->tk_status = 0; | 695 | task->tk_status = 0; |
528 | rpc_restart_call(task); | 696 | rpc_restart_call(task); |
697 | return; | ||
529 | } else { | 698 | } else { |
530 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | 699 | atomic_set(&clp->cl_cb_conn.cb_set, 0); |
531 | warn_no_callback_path(clp, task->tk_status); | 700 | warn_no_callback_path(clp, task->tk_status); |
532 | } | 701 | } |
702 | done: | ||
703 | kfree(task->tk_msg.rpc_argp); | ||
533 | } | 704 | } |
534 | 705 | ||
535 | static void nfsd4_cb_recall_release(void *calldata) | 706 | static void nfsd4_cb_recall_release(void *calldata) |
@@ -542,6 +713,7 @@ static void nfsd4_cb_recall_release(void *calldata) | |||
542 | } | 713 | } |
543 | 714 | ||
544 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | 715 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { |
716 | .rpc_call_prepare = nfsd4_cb_prepare, | ||
545 | .rpc_call_done = nfsd4_cb_recall_done, | 717 | .rpc_call_done = nfsd4_cb_recall_done, |
546 | .rpc_release = nfsd4_cb_recall_release, | 718 | .rpc_release = nfsd4_cb_recall_release, |
547 | }; | 719 | }; |
@@ -554,17 +726,24 @@ nfsd4_cb_recall(struct nfs4_delegation *dp) | |||
554 | { | 726 | { |
555 | struct nfs4_client *clp = dp->dl_client; | 727 | struct nfs4_client *clp = dp->dl_client; |
556 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; | 728 | struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; |
729 | struct nfs4_rpc_args *args; | ||
557 | struct rpc_message msg = { | 730 | struct rpc_message msg = { |
558 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], | 731 | .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], |
559 | .rpc_argp = dp, | 732 | .rpc_cred = callback_cred |
560 | .rpc_cred = clp->cl_cb_conn.cb_cred | ||
561 | }; | 733 | }; |
562 | int status; | 734 | int status = -ENOMEM; |
563 | 735 | ||
736 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
737 | if (!args) | ||
738 | goto out; | ||
739 | args->args_op = dp; | ||
740 | msg.rpc_argp = args; | ||
564 | dp->dl_retries = 1; | 741 | dp->dl_retries = 1; |
565 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, | 742 | status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, |
566 | &nfsd4_cb_recall_ops, dp); | 743 | &nfsd4_cb_recall_ops, dp); |
744 | out: | ||
567 | if (status) { | 745 | if (status) { |
746 | kfree(args); | ||
568 | put_nfs4_client(clp); | 747 | put_nfs4_client(clp); |
569 | nfs4_put_delegation(dp); | 748 | nfs4_put_delegation(dp); |
570 | } | 749 | } |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 7c8801769a3..bebc0c2e1b0 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -68,7 +68,6 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
68 | u32 *bmval, u32 *writable) | 68 | u32 *bmval, u32 *writable) |
69 | { | 69 | { |
70 | struct dentry *dentry = cstate->current_fh.fh_dentry; | 70 | struct dentry *dentry = cstate->current_fh.fh_dentry; |
71 | struct svc_export *exp = cstate->current_fh.fh_export; | ||
72 | 71 | ||
73 | /* | 72 | /* |
74 | * Check about attributes are supported by the NFSv4 server or not. | 73 | * Check about attributes are supported by the NFSv4 server or not. |
@@ -80,17 +79,13 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
80 | return nfserr_attrnotsupp; | 79 | return nfserr_attrnotsupp; |
81 | 80 | ||
82 | /* | 81 | /* |
83 | * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported | 82 | * Check FATTR4_WORD0_ACL can be supported |
84 | * in current environment or not. | 83 | * in current environment or not. |
85 | */ | 84 | */ |
86 | if (bmval[0] & FATTR4_WORD0_ACL) { | 85 | if (bmval[0] & FATTR4_WORD0_ACL) { |
87 | if (!IS_POSIXACL(dentry->d_inode)) | 86 | if (!IS_POSIXACL(dentry->d_inode)) |
88 | return nfserr_attrnotsupp; | 87 | return nfserr_attrnotsupp; |
89 | } | 88 | } |
90 | if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) { | ||
91 | if (exp->ex_fslocs.locations == NULL) | ||
92 | return nfserr_attrnotsupp; | ||
93 | } | ||
94 | 89 | ||
95 | /* | 90 | /* |
96 | * According to spec, read-only attributes return ERR_INVAL. | 91 | * According to spec, read-only attributes return ERR_INVAL. |
@@ -123,6 +118,35 @@ nfsd4_check_open_attributes(struct svc_rqst *rqstp, | |||
123 | return status; | 118 | return status; |
124 | } | 119 | } |
125 | 120 | ||
121 | static int | ||
122 | is_create_with_attrs(struct nfsd4_open *open) | ||
123 | { | ||
124 | return open->op_create == NFS4_OPEN_CREATE | ||
125 | && (open->op_createmode == NFS4_CREATE_UNCHECKED | ||
126 | || open->op_createmode == NFS4_CREATE_GUARDED | ||
127 | || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * if error occurs when setting the acl, just clear the acl bit | ||
132 | * in the returned attr bitmap. | ||
133 | */ | ||
134 | static void | ||
135 | do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | ||
136 | struct nfs4_acl *acl, u32 *bmval) | ||
137 | { | ||
138 | __be32 status; | ||
139 | |||
140 | status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); | ||
141 | if (status) | ||
142 | /* | ||
143 | * We should probably fail the whole open at this point, | ||
144 | * but we've already created the file, so it's too late; | ||
145 | * So this seems the least of evils: | ||
146 | */ | ||
147 | bmval[0] &= ~FATTR4_WORD0_ACL; | ||
148 | } | ||
149 | |||
126 | static inline void | 150 | static inline void |
127 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) | 151 | fh_dup2(struct svc_fh *dst, struct svc_fh *src) |
128 | { | 152 | { |
@@ -206,6 +230,9 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o | |||
206 | if (status) | 230 | if (status) |
207 | goto out; | 231 | goto out; |
208 | 232 | ||
233 | if (is_create_with_attrs(open) && open->op_acl != NULL) | ||
234 | do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval); | ||
235 | |||
209 | set_change_info(&open->op_cinfo, current_fh); | 236 | set_change_info(&open->op_cinfo, current_fh); |
210 | fh_dup2(current_fh, &resfh); | 237 | fh_dup2(current_fh, &resfh); |
211 | 238 | ||
@@ -536,12 +563,17 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
536 | status = nfserr_badtype; | 563 | status = nfserr_badtype; |
537 | } | 564 | } |
538 | 565 | ||
539 | if (!status) { | 566 | if (status) |
540 | fh_unlock(&cstate->current_fh); | 567 | goto out; |
541 | set_change_info(&create->cr_cinfo, &cstate->current_fh); | 568 | |
542 | fh_dup2(&cstate->current_fh, &resfh); | 569 | if (create->cr_acl != NULL) |
543 | } | 570 | do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, |
571 | create->cr_bmval); | ||
544 | 572 | ||
573 | fh_unlock(&cstate->current_fh); | ||
574 | set_change_info(&create->cr_cinfo, &cstate->current_fh); | ||
575 | fh_dup2(&cstate->current_fh, &resfh); | ||
576 | out: | ||
545 | fh_put(&resfh); | 577 | fh_put(&resfh); |
546 | return status; | 578 | return status; |
547 | } | 579 | } |
@@ -947,34 +979,6 @@ static struct nfsd4_operation nfsd4_ops[]; | |||
947 | static const char *nfsd4_op_name(unsigned opnum); | 979 | static const char *nfsd4_op_name(unsigned opnum); |
948 | 980 | ||
949 | /* | 981 | /* |
950 | * This is a replay of a compound for which no cache entry pages | ||
951 | * were used. Encode the sequence operation, and if cachethis is FALSE | ||
952 | * encode the uncache rep error on the next operation. | ||
953 | */ | ||
954 | static __be32 | ||
955 | nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args, | ||
956 | struct nfsd4_compoundres *resp) | ||
957 | { | ||
958 | struct nfsd4_op *op; | ||
959 | |||
960 | dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__, | ||
961 | resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis); | ||
962 | |||
963 | /* Encode the replayed sequence operation */ | ||
964 | BUG_ON(resp->opcnt != 1); | ||
965 | op = &args->ops[resp->opcnt - 1]; | ||
966 | nfsd4_encode_operation(resp, op); | ||
967 | |||
968 | /*return nfserr_retry_uncached_rep in next operation. */ | ||
969 | if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) { | ||
970 | op = &args->ops[resp->opcnt++]; | ||
971 | op->status = nfserr_retry_uncached_rep; | ||
972 | nfsd4_encode_operation(resp, op); | ||
973 | } | ||
974 | return op->status; | ||
975 | } | ||
976 | |||
977 | /* | ||
978 | * Enforce NFSv4.1 COMPOUND ordering rules. | 982 | * Enforce NFSv4.1 COMPOUND ordering rules. |
979 | * | 983 | * |
980 | * TODO: | 984 | * TODO: |
@@ -1083,13 +1087,10 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
1083 | BUG_ON(op->status == nfs_ok); | 1087 | BUG_ON(op->status == nfs_ok); |
1084 | 1088 | ||
1085 | encode_op: | 1089 | encode_op: |
1086 | /* Only from SEQUENCE or CREATE_SESSION */ | 1090 | /* Only from SEQUENCE */ |
1087 | if (resp->cstate.status == nfserr_replay_cache) { | 1091 | if (resp->cstate.status == nfserr_replay_cache) { |
1088 | dprintk("%s NFS4.1 replay from cache\n", __func__); | 1092 | dprintk("%s NFS4.1 replay from cache\n", __func__); |
1089 | if (nfsd4_not_cached(resp)) | 1093 | status = op->status; |
1090 | status = nfsd4_enc_uncached_replay(args, resp); | ||
1091 | else | ||
1092 | status = op->status; | ||
1093 | goto out; | 1094 | goto out; |
1094 | } | 1095 | } |
1095 | if (op->status == nfserr_replay_me) { | 1096 | if (op->status == nfserr_replay_me) { |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 980a216a48c..2153f9bdbeb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/lockd/bind.h> | 55 | #include <linux/lockd/bind.h> |
56 | #include <linux/module.h> | 56 | #include <linux/module.h> |
57 | #include <linux/sunrpc/svcauth_gss.h> | 57 | #include <linux/sunrpc/svcauth_gss.h> |
58 | #include <linux/sunrpc/clnt.h> | ||
58 | 59 | ||
59 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 60 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
60 | 61 | ||
@@ -413,36 +414,65 @@ gen_sessionid(struct nfsd4_session *ses) | |||
413 | } | 414 | } |
414 | 415 | ||
415 | /* | 416 | /* |
416 | * Give the client the number of slots it requests bound by | 417 | * The protocol defines ca_maxresponssize_cached to include the size of |
417 | * NFSD_MAX_SLOTS_PER_SESSION and by sv_drc_max_pages. | 418 | * the rpc header, but all we need to cache is the data starting after |
419 | * the end of the initial SEQUENCE operation--the rest we regenerate | ||
420 | * each time. Therefore we can advertise a ca_maxresponssize_cached | ||
421 | * value that is the number of bytes in our cache plus a few additional | ||
422 | * bytes. In order to stay on the safe side, and not promise more than | ||
423 | * we can cache, those additional bytes must be the minimum possible: 24 | ||
424 | * bytes of rpc header (xid through accept state, with AUTH_NULL | ||
425 | * verifier), 12 for the compound header (with zero-length tag), and 44 | ||
426 | * for the SEQUENCE op response: | ||
427 | */ | ||
428 | #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) | ||
429 | |||
430 | /* | ||
431 | * Give the client the number of ca_maxresponsesize_cached slots it | ||
432 | * requests, of size bounded by NFSD_SLOT_CACHE_SIZE, | ||
433 | * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more | ||
434 | * than NFSD_MAX_SLOTS_PER_SESSION. | ||
418 | * | 435 | * |
419 | * If we run out of pages (sv_drc_pages_used == sv_drc_max_pages) we | 436 | * If we run out of reserved DRC memory we should (up to a point) |
420 | * should (up to a point) re-negotiate active sessions and reduce their | 437 | * re-negotiate active sessions and reduce their slot usage to make |
421 | * slot usage to make rooom for new connections. For now we just fail the | 438 | * rooom for new connections. For now we just fail the create session. |
422 | * create session. | ||
423 | */ | 439 | */ |
424 | static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | 440 | static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) |
425 | { | 441 | { |
426 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | 442 | int mem, size = fchan->maxresp_cached; |
427 | 443 | ||
428 | if (fchan->maxreqs < 1) | 444 | if (fchan->maxreqs < 1) |
429 | return nfserr_inval; | 445 | return nfserr_inval; |
430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
432 | 446 | ||
433 | spin_lock(&nfsd_serv->sv_lock); | 447 | if (size < NFSD_MIN_HDR_SEQ_SZ) |
434 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | 448 | size = NFSD_MIN_HDR_SEQ_SZ; |
435 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | 449 | size -= NFSD_MIN_HDR_SEQ_SZ; |
436 | nfsd_serv->sv_drc_pages_used += np; | 450 | if (size > NFSD_SLOT_CACHE_SIZE) |
437 | spin_unlock(&nfsd_serv->sv_lock); | 451 | size = NFSD_SLOT_CACHE_SIZE; |
452 | |||
453 | /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */ | ||
454 | mem = fchan->maxreqs * size; | ||
455 | if (mem > NFSD_MAX_MEM_PER_SESSION) { | ||
456 | fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size; | ||
457 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
458 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
459 | mem = fchan->maxreqs * size; | ||
460 | } | ||
438 | 461 | ||
439 | if (np <= 0) { | 462 | spin_lock(&nfsd_drc_lock); |
440 | status = nfserr_resource; | 463 | /* bound the total session drc memory ussage */ |
441 | fchan->maxreqs = 0; | 464 | if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) { |
442 | } else | 465 | fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size; |
443 | fchan->maxreqs = np / NFSD_PAGES_PER_SLOT; | 466 | mem = fchan->maxreqs * size; |
467 | } | ||
468 | nfsd_drc_mem_used += mem; | ||
469 | spin_unlock(&nfsd_drc_lock); | ||
444 | 470 | ||
445 | return status; | 471 | if (fchan->maxreqs == 0) |
472 | return nfserr_serverfault; | ||
473 | |||
474 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | ||
475 | return 0; | ||
446 | } | 476 | } |
447 | 477 | ||
448 | /* | 478 | /* |
@@ -466,36 +496,41 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
466 | fchan->maxresp_sz = maxcount; | 496 | fchan->maxresp_sz = maxcount; |
467 | session_fchan->maxresp_sz = fchan->maxresp_sz; | 497 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
468 | 498 | ||
469 | /* Set the max response cached size our default which is | ||
470 | * a multiple of PAGE_SIZE and small */ | ||
471 | session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | ||
472 | fchan->maxresp_cached = session_fchan->maxresp_cached; | ||
473 | |||
474 | /* Use the client's maxops if possible */ | 499 | /* Use the client's maxops if possible */ |
475 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 500 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
476 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 501 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
477 | session_fchan->maxops = fchan->maxops; | 502 | session_fchan->maxops = fchan->maxops; |
478 | 503 | ||
479 | /* try to use the client requested number of slots */ | ||
480 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
481 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
482 | |||
483 | /* FIXME: Error means no more DRC pages so the server should | 504 | /* FIXME: Error means no more DRC pages so the server should |
484 | * recover pages from existing sessions. For now fail session | 505 | * recover pages from existing sessions. For now fail session |
485 | * creation. | 506 | * creation. |
486 | */ | 507 | */ |
487 | status = set_forechannel_maxreqs(fchan); | 508 | status = set_forechannel_drc_size(fchan); |
488 | 509 | ||
510 | session_fchan->maxresp_cached = fchan->maxresp_cached; | ||
489 | session_fchan->maxreqs = fchan->maxreqs; | 511 | session_fchan->maxreqs = fchan->maxreqs; |
512 | |||
513 | dprintk("%s status %d\n", __func__, status); | ||
490 | return status; | 514 | return status; |
491 | } | 515 | } |
492 | 516 | ||
517 | static void | ||
518 | free_session_slots(struct nfsd4_session *ses) | ||
519 | { | ||
520 | int i; | ||
521 | |||
522 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) | ||
523 | kfree(ses->se_slots[i]); | ||
524 | } | ||
525 | |||
493 | static int | 526 | static int |
494 | alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | 527 | alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, |
495 | struct nfsd4_create_session *cses) | 528 | struct nfsd4_create_session *cses) |
496 | { | 529 | { |
497 | struct nfsd4_session *new, tmp; | 530 | struct nfsd4_session *new, tmp; |
498 | int idx, status = nfserr_resource, slotsize; | 531 | struct nfsd4_slot *sp; |
532 | int idx, slotsize, cachesize, i; | ||
533 | int status; | ||
499 | 534 | ||
500 | memset(&tmp, 0, sizeof(tmp)); | 535 | memset(&tmp, 0, sizeof(tmp)); |
501 | 536 | ||
@@ -506,14 +541,27 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
506 | if (status) | 541 | if (status) |
507 | goto out; | 542 | goto out; |
508 | 543 | ||
509 | /* allocate struct nfsd4_session and slot table in one piece */ | 544 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) |
510 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot); | 545 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
546 | |||
547 | status = nfserr_serverfault; | ||
548 | /* allocate struct nfsd4_session and slot table pointers in one piece */ | ||
549 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); | ||
511 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 550 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
512 | if (!new) | 551 | if (!new) |
513 | goto out; | 552 | goto out; |
514 | 553 | ||
515 | memcpy(new, &tmp, sizeof(*new)); | 554 | memcpy(new, &tmp, sizeof(*new)); |
516 | 555 | ||
556 | /* allocate each struct nfsd4_slot and data cache in one piece */ | ||
557 | cachesize = new->se_fchannel.maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; | ||
558 | for (i = 0; i < new->se_fchannel.maxreqs; i++) { | ||
559 | sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL); | ||
560 | if (!sp) | ||
561 | goto out_free; | ||
562 | new->se_slots[i] = sp; | ||
563 | } | ||
564 | |||
517 | new->se_client = clp; | 565 | new->se_client = clp; |
518 | gen_sessionid(new); | 566 | gen_sessionid(new); |
519 | idx = hash_sessionid(&new->se_sessionid); | 567 | idx = hash_sessionid(&new->se_sessionid); |
@@ -530,6 +578,10 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
530 | status = nfs_ok; | 578 | status = nfs_ok; |
531 | out: | 579 | out: |
532 | return status; | 580 | return status; |
581 | out_free: | ||
582 | free_session_slots(new); | ||
583 | kfree(new); | ||
584 | goto out; | ||
533 | } | 585 | } |
534 | 586 | ||
535 | /* caller must hold sessionid_lock */ | 587 | /* caller must hold sessionid_lock */ |
@@ -572,19 +624,16 @@ release_session(struct nfsd4_session *ses) | |||
572 | nfsd4_put_session(ses); | 624 | nfsd4_put_session(ses); |
573 | } | 625 | } |
574 | 626 | ||
575 | static void nfsd4_release_respages(struct page **respages, short resused); | ||
576 | |||
577 | void | 627 | void |
578 | free_session(struct kref *kref) | 628 | free_session(struct kref *kref) |
579 | { | 629 | { |
580 | struct nfsd4_session *ses; | 630 | struct nfsd4_session *ses; |
581 | int i; | ||
582 | 631 | ||
583 | ses = container_of(kref, struct nfsd4_session, se_ref); | 632 | ses = container_of(kref, struct nfsd4_session, se_ref); |
584 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { | 633 | spin_lock(&nfsd_drc_lock); |
585 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | 634 | nfsd_drc_mem_used -= ses->se_fchannel.maxreqs * NFSD_SLOT_CACHE_SIZE; |
586 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | 635 | spin_unlock(&nfsd_drc_lock); |
587 | } | 636 | free_session_slots(ses); |
588 | kfree(ses); | 637 | kfree(ses); |
589 | } | 638 | } |
590 | 639 | ||
@@ -647,18 +696,14 @@ shutdown_callback_client(struct nfs4_client *clp) | |||
647 | clp->cl_cb_conn.cb_client = NULL; | 696 | clp->cl_cb_conn.cb_client = NULL; |
648 | rpc_shutdown_client(clnt); | 697 | rpc_shutdown_client(clnt); |
649 | } | 698 | } |
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 | } | ||
654 | } | 699 | } |
655 | 700 | ||
656 | static inline void | 701 | static inline void |
657 | free_client(struct nfs4_client *clp) | 702 | free_client(struct nfs4_client *clp) |
658 | { | 703 | { |
659 | shutdown_callback_client(clp); | 704 | shutdown_callback_client(clp); |
660 | nfsd4_release_respages(clp->cl_slot.sl_cache_entry.ce_respages, | 705 | if (clp->cl_cb_xprt) |
661 | clp->cl_slot.sl_cache_entry.ce_resused); | 706 | svc_xprt_put(clp->cl_cb_xprt); |
662 | if (clp->cl_cred.cr_group_info) | 707 | if (clp->cl_cred.cr_group_info) |
663 | put_group_info(clp->cl_cred.cr_group_info); | 708 | put_group_info(clp->cl_cred.cr_group_info); |
664 | kfree(clp->cl_principal); | 709 | kfree(clp->cl_principal); |
@@ -714,25 +759,6 @@ expire_client(struct nfs4_client *clp) | |||
714 | put_nfs4_client(clp); | 759 | put_nfs4_client(clp); |
715 | } | 760 | } |
716 | 761 | ||
717 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | ||
718 | { | ||
719 | struct nfs4_client *clp; | ||
720 | |||
721 | clp = alloc_client(name); | ||
722 | if (clp == NULL) | ||
723 | return NULL; | ||
724 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
725 | atomic_set(&clp->cl_count, 1); | ||
726 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
727 | INIT_LIST_HEAD(&clp->cl_idhash); | ||
728 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
729 | INIT_LIST_HEAD(&clp->cl_openowners); | ||
730 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
731 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
732 | INIT_LIST_HEAD(&clp->cl_lru); | ||
733 | return clp; | ||
734 | } | ||
735 | |||
736 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) | 762 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |
737 | { | 763 | { |
738 | memcpy(target->cl_verifier.data, source->data, | 764 | memcpy(target->cl_verifier.data, source->data, |
@@ -795,6 +821,46 @@ static void gen_confirm(struct nfs4_client *clp) | |||
795 | *p++ = i++; | 821 | *p++ = i++; |
796 | } | 822 | } |
797 | 823 | ||
824 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | ||
825 | struct svc_rqst *rqstp, nfs4_verifier *verf) | ||
826 | { | ||
827 | struct nfs4_client *clp; | ||
828 | struct sockaddr *sa = svc_addr(rqstp); | ||
829 | char *princ; | ||
830 | |||
831 | clp = alloc_client(name); | ||
832 | if (clp == NULL) | ||
833 | return NULL; | ||
834 | |||
835 | princ = svc_gss_principal(rqstp); | ||
836 | if (princ) { | ||
837 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | ||
838 | if (clp->cl_principal == NULL) { | ||
839 | free_client(clp); | ||
840 | return NULL; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
845 | atomic_set(&clp->cl_count, 1); | ||
846 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
847 | INIT_LIST_HEAD(&clp->cl_idhash); | ||
848 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
849 | INIT_LIST_HEAD(&clp->cl_openowners); | ||
850 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
851 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
852 | INIT_LIST_HEAD(&clp->cl_lru); | ||
853 | clear_bit(0, &clp->cl_cb_slot_busy); | ||
854 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | ||
855 | copy_verf(clp, verf); | ||
856 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | ||
857 | clp->cl_flavor = rqstp->rq_flavor; | ||
858 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
859 | gen_confirm(clp); | ||
860 | |||
861 | return clp; | ||
862 | } | ||
863 | |||
798 | static int check_name(struct xdr_netobj name) | 864 | static int check_name(struct xdr_netobj name) |
799 | { | 865 | { |
800 | if (name.len == 0) | 866 | if (name.len == 0) |
@@ -902,93 +968,40 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, | |||
902 | return NULL; | 968 | return NULL; |
903 | } | 969 | } |
904 | 970 | ||
905 | /* a helper function for parse_callback */ | ||
906 | static int | ||
907 | parse_octet(unsigned int *lenp, char **addrp) | ||
908 | { | ||
909 | unsigned int len = *lenp; | ||
910 | char *p = *addrp; | ||
911 | int n = -1; | ||
912 | char c; | ||
913 | |||
914 | for (;;) { | ||
915 | if (!len) | ||
916 | break; | ||
917 | len--; | ||
918 | c = *p++; | ||
919 | if (c == '.') | ||
920 | break; | ||
921 | if ((c < '0') || (c > '9')) { | ||
922 | n = -1; | ||
923 | break; | ||
924 | } | ||
925 | if (n < 0) | ||
926 | n = 0; | ||
927 | n = (n * 10) + (c - '0'); | ||
928 | if (n > 255) { | ||
929 | n = -1; | ||
930 | break; | ||
931 | } | ||
932 | } | ||
933 | *lenp = len; | ||
934 | *addrp = p; | ||
935 | return n; | ||
936 | } | ||
937 | |||
938 | /* parse and set the setclientid ipv4 callback address */ | ||
939 | static int | ||
940 | parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp) | ||
941 | { | ||
942 | int temp = 0; | ||
943 | u32 cbaddr = 0; | ||
944 | u16 cbport = 0; | ||
945 | u32 addrlen = addr_len; | ||
946 | char *addr = addr_val; | ||
947 | int i, shift; | ||
948 | |||
949 | /* ipaddress */ | ||
950 | shift = 24; | ||
951 | for(i = 4; i > 0 ; i--) { | ||
952 | if ((temp = parse_octet(&addrlen, &addr)) < 0) { | ||
953 | return 0; | ||
954 | } | ||
955 | cbaddr |= (temp << shift); | ||
956 | if (shift > 0) | ||
957 | shift -= 8; | ||
958 | } | ||
959 | *cbaddrp = cbaddr; | ||
960 | |||
961 | /* port */ | ||
962 | shift = 8; | ||
963 | for(i = 2; i > 0 ; i--) { | ||
964 | if ((temp = parse_octet(&addrlen, &addr)) < 0) { | ||
965 | return 0; | ||
966 | } | ||
967 | cbport |= (temp << shift); | ||
968 | if (shift > 0) | ||
969 | shift -= 8; | ||
970 | } | ||
971 | *cbportp = cbport; | ||
972 | return 1; | ||
973 | } | ||
974 | |||
975 | static void | 971 | static void |
976 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 972 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) |
977 | { | 973 | { |
978 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; | 974 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
979 | 975 | unsigned short expected_family; | |
980 | /* Currently, we only support tcp for the callback channel */ | 976 | |
981 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) | 977 | /* Currently, we only support tcp and tcp6 for the callback channel */ |
978 | if (se->se_callback_netid_len == 3 && | ||
979 | !memcmp(se->se_callback_netid_val, "tcp", 3)) | ||
980 | expected_family = AF_INET; | ||
981 | else if (se->se_callback_netid_len == 4 && | ||
982 | !memcmp(se->se_callback_netid_val, "tcp6", 4)) | ||
983 | expected_family = AF_INET6; | ||
984 | else | ||
982 | goto out_err; | 985 | goto out_err; |
983 | 986 | ||
984 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, | 987 | cb->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, |
985 | &cb->cb_addr, &cb->cb_port))) | 988 | se->se_callback_addr_len, |
989 | (struct sockaddr *) &cb->cb_addr, | ||
990 | sizeof(cb->cb_addr)); | ||
991 | |||
992 | if (!cb->cb_addrlen || cb->cb_addr.ss_family != expected_family) | ||
986 | goto out_err; | 993 | goto out_err; |
994 | |||
995 | if (cb->cb_addr.ss_family == AF_INET6) | ||
996 | ((struct sockaddr_in6 *) &cb->cb_addr)->sin6_scope_id = scopeid; | ||
997 | |||
987 | cb->cb_minorversion = 0; | 998 | cb->cb_minorversion = 0; |
988 | cb->cb_prog = se->se_callback_prog; | 999 | cb->cb_prog = se->se_callback_prog; |
989 | cb->cb_ident = se->se_callback_ident; | 1000 | cb->cb_ident = se->se_callback_ident; |
990 | return; | 1001 | return; |
991 | out_err: | 1002 | out_err: |
1003 | cb->cb_addr.ss_family = AF_UNSPEC; | ||
1004 | cb->cb_addrlen = 0; | ||
992 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " | 1005 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " |
993 | "will not receive delegations\n", | 1006 | "will not receive delegations\n", |
994 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 1007 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); |
@@ -996,175 +1009,87 @@ out_err: | |||
996 | return; | 1009 | return; |
997 | } | 1010 | } |
998 | 1011 | ||
999 | void | ||
1000 | nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp) | ||
1001 | { | ||
1002 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1003 | |||
1004 | resp->cstate.statp = statp; | ||
1005 | } | ||
1006 | |||
1007 | /* | 1012 | /* |
1008 | * Dereference the result pages. | 1013 | * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size. |
1009 | */ | 1014 | */ |
1010 | static void | 1015 | void |
1011 | nfsd4_release_respages(struct page **respages, short resused) | 1016 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) |
1012 | { | 1017 | { |
1013 | int i; | 1018 | struct nfsd4_slot *slot = resp->cstate.slot; |
1019 | unsigned int base; | ||
1014 | 1020 | ||
1015 | dprintk("--> %s\n", __func__); | 1021 | dprintk("--> %s slot %p\n", __func__, slot); |
1016 | for (i = 0; i < resused; i++) { | ||
1017 | if (!respages[i]) | ||
1018 | continue; | ||
1019 | put_page(respages[i]); | ||
1020 | respages[i] = NULL; | ||
1021 | } | ||
1022 | } | ||
1023 | 1022 | ||
1024 | static void | 1023 | slot->sl_opcnt = resp->opcnt; |
1025 | nfsd4_copy_pages(struct page **topages, struct page **frompages, short count) | 1024 | slot->sl_status = resp->cstate.status; |
1026 | { | ||
1027 | int i; | ||
1028 | 1025 | ||
1029 | for (i = 0; i < count; i++) { | 1026 | if (nfsd4_not_cached(resp)) { |
1030 | topages[i] = frompages[i]; | 1027 | slot->sl_datalen = 0; |
1031 | if (!topages[i]) | 1028 | return; |
1032 | continue; | ||
1033 | get_page(topages[i]); | ||
1034 | } | 1029 | } |
1030 | slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap; | ||
1031 | base = (char *)resp->cstate.datap - | ||
1032 | (char *)resp->xbuf->head[0].iov_base; | ||
1033 | if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data, | ||
1034 | slot->sl_datalen)) | ||
1035 | WARN("%s: sessions DRC could not cache compound\n", __func__); | ||
1036 | return; | ||
1035 | } | 1037 | } |
1036 | 1038 | ||
1037 | /* | 1039 | /* |
1038 | * Cache the reply pages up to NFSD_PAGES_PER_SLOT + 1, clearing the previous | 1040 | * Encode the replay sequence operation from the slot values. |
1039 | * pages. We add a page to NFSD_PAGES_PER_SLOT for the case where the total | 1041 | * If cachethis is FALSE encode the uncached rep error on the next |
1040 | * length of the XDR response is less than se_fmaxresp_cached | 1042 | * operation which sets resp->p and increments resp->opcnt for |
1041 | * (NFSD_PAGES_PER_SLOT * PAGE_SIZE) but the xdr_buf pages is used for a | 1043 | * nfs4svc_encode_compoundres. |
1042 | * of the reply (e.g. readdir). | ||
1043 | * | 1044 | * |
1044 | * Store the base and length of the rq_req.head[0] page | ||
1045 | * of the NFSv4.1 data, just past the rpc header. | ||
1046 | */ | 1045 | */ |
1047 | void | 1046 | static __be32 |
1048 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | 1047 | nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, |
1048 | struct nfsd4_compoundres *resp) | ||
1049 | { | 1049 | { |
1050 | struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; | 1050 | struct nfsd4_op *op; |
1051 | struct svc_rqst *rqstp = resp->rqstp; | 1051 | struct nfsd4_slot *slot = resp->cstate.slot; |
1052 | struct nfsd4_compoundargs *args = rqstp->rq_argp; | ||
1053 | struct nfsd4_op *op = &args->ops[resp->opcnt]; | ||
1054 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
1055 | |||
1056 | dprintk("--> %s entry %p\n", __func__, entry); | ||
1057 | |||
1058 | /* Don't cache a failed OP_SEQUENCE. */ | ||
1059 | if (resp->opcnt == 1 && op->opnum == OP_SEQUENCE && resp->cstate.status) | ||
1060 | return; | ||
1061 | 1052 | ||
1062 | nfsd4_release_respages(entry->ce_respages, entry->ce_resused); | 1053 | dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__, |
1063 | entry->ce_opcnt = resp->opcnt; | 1054 | resp->opcnt, resp->cstate.slot->sl_cachethis); |
1064 | entry->ce_status = resp->cstate.status; | ||
1065 | 1055 | ||
1066 | /* | 1056 | /* Encode the replayed sequence operation */ |
1067 | * Don't need a page to cache just the sequence operation - the slot | 1057 | op = &args->ops[resp->opcnt - 1]; |
1068 | * does this for us! | 1058 | nfsd4_encode_operation(resp, op); |
1069 | */ | ||
1070 | 1059 | ||
1071 | if (nfsd4_not_cached(resp)) { | 1060 | /* Return nfserr_retry_uncached_rep in next operation. */ |
1072 | entry->ce_resused = 0; | 1061 | if (args->opcnt > 1 && slot->sl_cachethis == 0) { |
1073 | entry->ce_rpchdrlen = 0; | 1062 | op = &args->ops[resp->opcnt++]; |
1074 | dprintk("%s Just cache SEQUENCE. ce_cachethis %d\n", __func__, | 1063 | op->status = nfserr_retry_uncached_rep; |
1075 | resp->cstate.slot->sl_cache_entry.ce_cachethis); | 1064 | nfsd4_encode_operation(resp, op); |
1076 | return; | ||
1077 | } | ||
1078 | entry->ce_resused = rqstp->rq_resused; | ||
1079 | if (entry->ce_resused > NFSD_PAGES_PER_SLOT + 1) | ||
1080 | entry->ce_resused = NFSD_PAGES_PER_SLOT + 1; | ||
1081 | nfsd4_copy_pages(entry->ce_respages, rqstp->rq_respages, | ||
1082 | entry->ce_resused); | ||
1083 | entry->ce_datav.iov_base = resp->cstate.statp; | ||
1084 | entry->ce_datav.iov_len = resv->iov_len - ((char *)resp->cstate.statp - | ||
1085 | (char *)page_address(rqstp->rq_respages[0])); | ||
1086 | /* Current request rpc header length*/ | ||
1087 | entry->ce_rpchdrlen = (char *)resp->cstate.statp - | ||
1088 | (char *)page_address(rqstp->rq_respages[0]); | ||
1089 | } | ||
1090 | |||
1091 | /* | ||
1092 | * We keep the rpc header, but take the nfs reply from the replycache. | ||
1093 | */ | ||
1094 | static int | ||
1095 | nfsd41_copy_replay_data(struct nfsd4_compoundres *resp, | ||
1096 | struct nfsd4_cache_entry *entry) | ||
1097 | { | ||
1098 | struct svc_rqst *rqstp = resp->rqstp; | ||
1099 | struct kvec *resv = &resp->rqstp->rq_res.head[0]; | ||
1100 | int len; | ||
1101 | |||
1102 | /* Current request rpc header length*/ | ||
1103 | len = (char *)resp->cstate.statp - | ||
1104 | (char *)page_address(rqstp->rq_respages[0]); | ||
1105 | if (entry->ce_datav.iov_len + len > PAGE_SIZE) { | ||
1106 | dprintk("%s v41 cached reply too large (%Zd).\n", __func__, | ||
1107 | entry->ce_datav.iov_len); | ||
1108 | return 0; | ||
1109 | } | 1065 | } |
1110 | /* copy the cached reply nfsd data past the current rpc header */ | 1066 | return op->status; |
1111 | memcpy((char *)resv->iov_base + len, entry->ce_datav.iov_base, | ||
1112 | entry->ce_datav.iov_len); | ||
1113 | resv->iov_len = len + entry->ce_datav.iov_len; | ||
1114 | return 1; | ||
1115 | } | 1067 | } |
1116 | 1068 | ||
1117 | /* | 1069 | /* |
1118 | * Keep the first page of the replay. Copy the NFSv4.1 data from the first | 1070 | * The sequence operation is not cached because we can use the slot and |
1119 | * cached page. Replace any futher replay pages from the cache. | 1071 | * session values. |
1120 | */ | 1072 | */ |
1121 | __be32 | 1073 | __be32 |
1122 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | 1074 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, |
1123 | struct nfsd4_sequence *seq) | 1075 | struct nfsd4_sequence *seq) |
1124 | { | 1076 | { |
1125 | struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; | 1077 | struct nfsd4_slot *slot = resp->cstate.slot; |
1126 | __be32 status; | 1078 | __be32 status; |
1127 | 1079 | ||
1128 | dprintk("--> %s entry %p\n", __func__, entry); | 1080 | dprintk("--> %s slot %p\n", __func__, slot); |
1129 | |||
1130 | /* | ||
1131 | * If this is just the sequence operation, we did not keep | ||
1132 | * a page in the cache entry because we can just use the | ||
1133 | * slot info stored in struct nfsd4_sequence that was checked | ||
1134 | * against the slot in nfsd4_sequence(). | ||
1135 | * | ||
1136 | * This occurs when seq->cachethis is FALSE, or when the client | ||
1137 | * session inactivity timer fires and a solo sequence operation | ||
1138 | * is sent (lease renewal). | ||
1139 | */ | ||
1140 | if (seq && nfsd4_not_cached(resp)) { | ||
1141 | seq->maxslots = resp->cstate.session->se_fchannel.maxreqs; | ||
1142 | return nfs_ok; | ||
1143 | } | ||
1144 | |||
1145 | if (!nfsd41_copy_replay_data(resp, entry)) { | ||
1146 | /* | ||
1147 | * Not enough room to use the replay rpc header, send the | ||
1148 | * cached header. Release all the allocated result pages. | ||
1149 | */ | ||
1150 | svc_free_res_pages(resp->rqstp); | ||
1151 | nfsd4_copy_pages(resp->rqstp->rq_respages, entry->ce_respages, | ||
1152 | entry->ce_resused); | ||
1153 | } else { | ||
1154 | /* Release all but the first allocated result page */ | ||
1155 | 1081 | ||
1156 | resp->rqstp->rq_resused--; | 1082 | /* Either returns 0 or nfserr_retry_uncached */ |
1157 | svc_free_res_pages(resp->rqstp); | 1083 | status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); |
1084 | if (status == nfserr_retry_uncached_rep) | ||
1085 | return status; | ||
1158 | 1086 | ||
1159 | nfsd4_copy_pages(&resp->rqstp->rq_respages[1], | 1087 | /* The sequence operation has been encoded, cstate->datap set. */ |
1160 | &entry->ce_respages[1], | 1088 | memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen); |
1161 | entry->ce_resused - 1); | ||
1162 | } | ||
1163 | 1089 | ||
1164 | resp->rqstp->rq_resused = entry->ce_resused; | 1090 | resp->opcnt = slot->sl_opcnt; |
1165 | resp->opcnt = entry->ce_opcnt; | 1091 | resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen); |
1166 | resp->cstate.iovlen = entry->ce_datav.iov_len + entry->ce_rpchdrlen; | 1092 | status = slot->sl_status; |
1167 | status = entry->ce_status; | ||
1168 | 1093 | ||
1169 | return status; | 1094 | return status; |
1170 | } | 1095 | } |
@@ -1194,13 +1119,15 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1194 | int status; | 1119 | int status; |
1195 | unsigned int strhashval; | 1120 | unsigned int strhashval; |
1196 | char dname[HEXDIR_LEN]; | 1121 | char dname[HEXDIR_LEN]; |
1122 | char addr_str[INET6_ADDRSTRLEN]; | ||
1197 | nfs4_verifier verf = exid->verifier; | 1123 | nfs4_verifier verf = exid->verifier; |
1198 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | 1124 | struct sockaddr *sa = svc_addr(rqstp); |
1199 | 1125 | ||
1126 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | ||
1200 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1127 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
1201 | " ip_addr=%u flags %x, spa_how %d\n", | 1128 | "ip_addr=%s flags %x, spa_how %d\n", |
1202 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, | 1129 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, |
1203 | ip_addr, exid->flags, exid->spa_how); | 1130 | addr_str, exid->flags, exid->spa_how); |
1204 | 1131 | ||
1205 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) | 1132 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) |
1206 | return nfserr_inval; | 1133 | return nfserr_inval; |
@@ -1281,28 +1208,23 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1281 | 1208 | ||
1282 | out_new: | 1209 | out_new: |
1283 | /* Normal case */ | 1210 | /* Normal case */ |
1284 | new = create_client(exid->clname, dname); | 1211 | new = create_client(exid->clname, dname, rqstp, &verf); |
1285 | if (new == NULL) { | 1212 | if (new == NULL) { |
1286 | status = nfserr_resource; | 1213 | status = nfserr_serverfault; |
1287 | goto out; | 1214 | goto out; |
1288 | } | 1215 | } |
1289 | 1216 | ||
1290 | copy_verf(new, &verf); | ||
1291 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | ||
1292 | new->cl_addr = ip_addr; | ||
1293 | gen_clid(new); | 1217 | gen_clid(new); |
1294 | gen_confirm(new); | ||
1295 | add_to_unconfirmed(new, strhashval); | 1218 | add_to_unconfirmed(new, strhashval); |
1296 | out_copy: | 1219 | out_copy: |
1297 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1220 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1298 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1221 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
1299 | 1222 | ||
1300 | new->cl_slot.sl_seqid = 0; | ||
1301 | exid->seqid = 1; | 1223 | exid->seqid = 1; |
1302 | nfsd4_set_ex_flags(new, exid); | 1224 | nfsd4_set_ex_flags(new, exid); |
1303 | 1225 | ||
1304 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1226 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
1305 | new->cl_slot.sl_seqid, new->cl_exchange_flags); | 1227 | new->cl_cs_slot.sl_seqid, new->cl_exchange_flags); |
1306 | status = nfs_ok; | 1228 | status = nfs_ok; |
1307 | 1229 | ||
1308 | out: | 1230 | out: |
@@ -1313,40 +1235,60 @@ error: | |||
1313 | } | 1235 | } |
1314 | 1236 | ||
1315 | static int | 1237 | static int |
1316 | check_slot_seqid(u32 seqid, struct nfsd4_slot *slot) | 1238 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
1317 | { | 1239 | { |
1318 | dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid, | 1240 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
1319 | slot->sl_seqid); | 1241 | slot_seqid); |
1320 | 1242 | ||
1321 | /* The slot is in use, and no response has been sent. */ | 1243 | /* The slot is in use, and no response has been sent. */ |
1322 | if (slot->sl_inuse) { | 1244 | if (slot_inuse) { |
1323 | if (seqid == slot->sl_seqid) | 1245 | if (seqid == slot_seqid) |
1324 | return nfserr_jukebox; | 1246 | return nfserr_jukebox; |
1325 | else | 1247 | else |
1326 | return nfserr_seq_misordered; | 1248 | return nfserr_seq_misordered; |
1327 | } | 1249 | } |
1328 | /* Normal */ | 1250 | /* Normal */ |
1329 | if (likely(seqid == slot->sl_seqid + 1)) | 1251 | if (likely(seqid == slot_seqid + 1)) |
1330 | return nfs_ok; | 1252 | return nfs_ok; |
1331 | /* Replay */ | 1253 | /* Replay */ |
1332 | if (seqid == slot->sl_seqid) | 1254 | if (seqid == slot_seqid) |
1333 | return nfserr_replay_cache; | 1255 | return nfserr_replay_cache; |
1334 | /* Wraparound */ | 1256 | /* Wraparound */ |
1335 | if (seqid == 1 && (slot->sl_seqid + 1) == 0) | 1257 | if (seqid == 1 && (slot_seqid + 1) == 0) |
1336 | return nfs_ok; | 1258 | return nfs_ok; |
1337 | /* Misordered replay or misordered new request */ | 1259 | /* Misordered replay or misordered new request */ |
1338 | return nfserr_seq_misordered; | 1260 | return nfserr_seq_misordered; |
1339 | } | 1261 | } |
1340 | 1262 | ||
1263 | /* | ||
1264 | * Cache the create session result into the create session single DRC | ||
1265 | * slot cache by saving the xdr structure. sl_seqid has been set. | ||
1266 | * Do this for solo or embedded create session operations. | ||
1267 | */ | ||
1268 | static void | ||
1269 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | ||
1270 | struct nfsd4_clid_slot *slot, int nfserr) | ||
1271 | { | ||
1272 | slot->sl_status = nfserr; | ||
1273 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | ||
1274 | } | ||
1275 | |||
1276 | static __be32 | ||
1277 | nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | ||
1278 | struct nfsd4_clid_slot *slot) | ||
1279 | { | ||
1280 | memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); | ||
1281 | return slot->sl_status; | ||
1282 | } | ||
1283 | |||
1341 | __be32 | 1284 | __be32 |
1342 | nfsd4_create_session(struct svc_rqst *rqstp, | 1285 | nfsd4_create_session(struct svc_rqst *rqstp, |
1343 | struct nfsd4_compound_state *cstate, | 1286 | struct nfsd4_compound_state *cstate, |
1344 | struct nfsd4_create_session *cr_ses) | 1287 | struct nfsd4_create_session *cr_ses) |
1345 | { | 1288 | { |
1346 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | 1289 | struct sockaddr *sa = svc_addr(rqstp); |
1347 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1348 | struct nfs4_client *conf, *unconf; | 1290 | struct nfs4_client *conf, *unconf; |
1349 | struct nfsd4_slot *slot = NULL; | 1291 | struct nfsd4_clid_slot *cs_slot = NULL; |
1350 | int status = 0; | 1292 | int status = 0; |
1351 | 1293 | ||
1352 | nfs4_lock_state(); | 1294 | nfs4_lock_state(); |
@@ -1354,40 +1296,38 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1354 | conf = find_confirmed_client(&cr_ses->clientid); | 1296 | conf = find_confirmed_client(&cr_ses->clientid); |
1355 | 1297 | ||
1356 | if (conf) { | 1298 | if (conf) { |
1357 | slot = &conf->cl_slot; | 1299 | cs_slot = &conf->cl_cs_slot; |
1358 | status = check_slot_seqid(cr_ses->seqid, slot); | 1300 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1359 | if (status == nfserr_replay_cache) { | 1301 | if (status == nfserr_replay_cache) { |
1360 | dprintk("Got a create_session replay! seqid= %d\n", | 1302 | dprintk("Got a create_session replay! seqid= %d\n", |
1361 | slot->sl_seqid); | 1303 | cs_slot->sl_seqid); |
1362 | cstate->slot = slot; | ||
1363 | cstate->status = status; | ||
1364 | /* Return the cached reply status */ | 1304 | /* Return the cached reply status */ |
1365 | status = nfsd4_replay_cache_entry(resp, NULL); | 1305 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
1366 | goto out; | 1306 | goto out; |
1367 | } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) { | 1307 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
1368 | status = nfserr_seq_misordered; | 1308 | status = nfserr_seq_misordered; |
1369 | dprintk("Sequence misordered!\n"); | 1309 | dprintk("Sequence misordered!\n"); |
1370 | dprintk("Expected seqid= %d but got seqid= %d\n", | 1310 | dprintk("Expected seqid= %d but got seqid= %d\n", |
1371 | slot->sl_seqid, cr_ses->seqid); | 1311 | cs_slot->sl_seqid, cr_ses->seqid); |
1372 | goto out; | 1312 | goto out; |
1373 | } | 1313 | } |
1374 | conf->cl_slot.sl_seqid++; | 1314 | cs_slot->sl_seqid++; |
1375 | } else if (unconf) { | 1315 | } else if (unconf) { |
1376 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | 1316 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || |
1377 | (ip_addr != unconf->cl_addr)) { | 1317 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { |
1378 | status = nfserr_clid_inuse; | 1318 | status = nfserr_clid_inuse; |
1379 | goto out; | 1319 | goto out; |
1380 | } | 1320 | } |
1381 | 1321 | ||
1382 | slot = &unconf->cl_slot; | 1322 | cs_slot = &unconf->cl_cs_slot; |
1383 | status = check_slot_seqid(cr_ses->seqid, slot); | 1323 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1384 | if (status) { | 1324 | if (status) { |
1385 | /* an unconfirmed replay returns misordered */ | 1325 | /* an unconfirmed replay returns misordered */ |
1386 | status = nfserr_seq_misordered; | 1326 | status = nfserr_seq_misordered; |
1387 | goto out; | 1327 | goto out_cache; |
1388 | } | 1328 | } |
1389 | 1329 | ||
1390 | slot->sl_seqid++; /* from 0 to 1 */ | 1330 | cs_slot->sl_seqid++; /* from 0 to 1 */ |
1391 | move_to_confirmed(unconf); | 1331 | move_to_confirmed(unconf); |
1392 | 1332 | ||
1393 | /* | 1333 | /* |
@@ -1396,6 +1336,19 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1396 | cr_ses->flags &= ~SESSION4_PERSIST; | 1336 | cr_ses->flags &= ~SESSION4_PERSIST; |
1397 | cr_ses->flags &= ~SESSION4_RDMA; | 1337 | cr_ses->flags &= ~SESSION4_RDMA; |
1398 | 1338 | ||
1339 | if (cr_ses->flags & SESSION4_BACK_CHAN) { | ||
1340 | unconf->cl_cb_xprt = rqstp->rq_xprt; | ||
1341 | svc_xprt_get(unconf->cl_cb_xprt); | ||
1342 | rpc_copy_addr( | ||
1343 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, | ||
1344 | sa); | ||
1345 | unconf->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | ||
1346 | unconf->cl_cb_conn.cb_minorversion = | ||
1347 | cstate->minorversion; | ||
1348 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; | ||
1349 | unconf->cl_cb_seq_nr = 1; | ||
1350 | nfsd4_probe_callback(unconf); | ||
1351 | } | ||
1399 | conf = unconf; | 1352 | conf = unconf; |
1400 | } else { | 1353 | } else { |
1401 | status = nfserr_stale_clientid; | 1354 | status = nfserr_stale_clientid; |
@@ -1408,12 +1361,11 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1408 | 1361 | ||
1409 | memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data, | 1362 | memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data, |
1410 | NFS4_MAX_SESSIONID_LEN); | 1363 | NFS4_MAX_SESSIONID_LEN); |
1411 | cr_ses->seqid = slot->sl_seqid; | 1364 | cr_ses->seqid = cs_slot->sl_seqid; |
1412 | 1365 | ||
1413 | slot->sl_inuse = true; | 1366 | out_cache: |
1414 | cstate->slot = slot; | 1367 | /* cache solo and embedded create sessions under the state lock */ |
1415 | /* Ensure a page is used for the cache */ | 1368 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1416 | slot->sl_cache_entry.ce_cachethis = 1; | ||
1417 | out: | 1369 | out: |
1418 | nfs4_unlock_state(); | 1370 | nfs4_unlock_state(); |
1419 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1371 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1478,18 +1430,23 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1478 | if (seq->slotid >= session->se_fchannel.maxreqs) | 1430 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1479 | goto out; | 1431 | goto out; |
1480 | 1432 | ||
1481 | slot = &session->se_slots[seq->slotid]; | 1433 | slot = session->se_slots[seq->slotid]; |
1482 | dprintk("%s: slotid %d\n", __func__, seq->slotid); | 1434 | dprintk("%s: slotid %d\n", __func__, seq->slotid); |
1483 | 1435 | ||
1484 | status = check_slot_seqid(seq->seqid, slot); | 1436 | /* We do not negotiate the number of slots yet, so set the |
1437 | * maxslots to the session maxreqs which is used to encode | ||
1438 | * sr_highest_slotid and the sr_target_slot id to maxslots */ | ||
1439 | seq->maxslots = session->se_fchannel.maxreqs; | ||
1440 | |||
1441 | status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse); | ||
1485 | if (status == nfserr_replay_cache) { | 1442 | if (status == nfserr_replay_cache) { |
1486 | cstate->slot = slot; | 1443 | cstate->slot = slot; |
1487 | cstate->session = session; | 1444 | cstate->session = session; |
1488 | /* Return the cached reply status and set cstate->status | 1445 | /* Return the cached reply status and set cstate->status |
1489 | * for nfsd4_svc_encode_compoundres processing */ | 1446 | * for nfsd4_proc_compound processing */ |
1490 | status = nfsd4_replay_cache_entry(resp, seq); | 1447 | status = nfsd4_replay_cache_entry(resp, seq); |
1491 | cstate->status = nfserr_replay_cache; | 1448 | cstate->status = nfserr_replay_cache; |
1492 | goto replay_cache; | 1449 | goto out; |
1493 | } | 1450 | } |
1494 | if (status) | 1451 | if (status) |
1495 | goto out; | 1452 | goto out; |
@@ -1497,23 +1454,23 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1497 | /* Success! bump slot seqid */ | 1454 | /* Success! bump slot seqid */ |
1498 | slot->sl_inuse = true; | 1455 | slot->sl_inuse = true; |
1499 | slot->sl_seqid = seq->seqid; | 1456 | slot->sl_seqid = seq->seqid; |
1500 | slot->sl_cache_entry.ce_cachethis = seq->cachethis; | 1457 | slot->sl_cachethis = seq->cachethis; |
1501 | /* Always set the cache entry cachethis for solo sequence */ | ||
1502 | if (nfsd4_is_solo_sequence(resp)) | ||
1503 | slot->sl_cache_entry.ce_cachethis = 1; | ||
1504 | 1458 | ||
1505 | cstate->slot = slot; | 1459 | cstate->slot = slot; |
1506 | cstate->session = session; | 1460 | cstate->session = session; |
1507 | 1461 | ||
1508 | replay_cache: | 1462 | /* Hold a session reference until done processing the compound: |
1509 | /* Renew the clientid on success and on replay. | ||
1510 | * Hold a session reference until done processing the compound: | ||
1511 | * nfsd4_put_session called only if the cstate slot is set. | 1463 | * nfsd4_put_session called only if the cstate slot is set. |
1512 | */ | 1464 | */ |
1513 | renew_client(session->se_client); | ||
1514 | nfsd4_get_session(session); | 1465 | nfsd4_get_session(session); |
1515 | out: | 1466 | out: |
1516 | spin_unlock(&sessionid_lock); | 1467 | spin_unlock(&sessionid_lock); |
1468 | /* Renew the clientid on success and on replay */ | ||
1469 | if (cstate->session) { | ||
1470 | nfs4_lock_state(); | ||
1471 | renew_client(session->se_client); | ||
1472 | nfs4_unlock_state(); | ||
1473 | } | ||
1517 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 1474 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
1518 | return status; | 1475 | return status; |
1519 | } | 1476 | } |
@@ -1522,7 +1479,7 @@ __be32 | |||
1522 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1479 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1523 | struct nfsd4_setclientid *setclid) | 1480 | struct nfsd4_setclientid *setclid) |
1524 | { | 1481 | { |
1525 | struct sockaddr_in *sin = svc_addr_in(rqstp); | 1482 | struct sockaddr *sa = svc_addr(rqstp); |
1526 | struct xdr_netobj clname = { | 1483 | struct xdr_netobj clname = { |
1527 | .len = setclid->se_namelen, | 1484 | .len = setclid->se_namelen, |
1528 | .data = setclid->se_name, | 1485 | .data = setclid->se_name, |
@@ -1531,7 +1488,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1531 | unsigned int strhashval; | 1488 | unsigned int strhashval; |
1532 | struct nfs4_client *conf, *unconf, *new; | 1489 | struct nfs4_client *conf, *unconf, *new; |
1533 | __be32 status; | 1490 | __be32 status; |
1534 | char *princ; | ||
1535 | char dname[HEXDIR_LEN]; | 1491 | char dname[HEXDIR_LEN]; |
1536 | 1492 | ||
1537 | if (!check_name(clname)) | 1493 | if (!check_name(clname)) |
@@ -1554,8 +1510,11 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1554 | /* RFC 3530 14.2.33 CASE 0: */ | 1510 | /* RFC 3530 14.2.33 CASE 0: */ |
1555 | status = nfserr_clid_inuse; | 1511 | status = nfserr_clid_inuse; |
1556 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1512 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1557 | dprintk("NFSD: setclientid: string in use by client" | 1513 | char addr_str[INET6_ADDRSTRLEN]; |
1558 | " at %pI4\n", &conf->cl_addr); | 1514 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, |
1515 | sizeof(addr_str)); | ||
1516 | dprintk("NFSD: setclientid: string in use by client " | ||
1517 | "at %s\n", addr_str); | ||
1559 | goto out; | 1518 | goto out; |
1560 | } | 1519 | } |
1561 | } | 1520 | } |
@@ -1573,7 +1532,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1573 | */ | 1532 | */ |
1574 | if (unconf) | 1533 | if (unconf) |
1575 | expire_client(unconf); | 1534 | expire_client(unconf); |
1576 | new = create_client(clname, dname); | 1535 | new = create_client(clname, dname, rqstp, &clverifier); |
1577 | if (new == NULL) | 1536 | if (new == NULL) |
1578 | goto out; | 1537 | goto out; |
1579 | gen_clid(new); | 1538 | gen_clid(new); |
@@ -1590,7 +1549,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1590 | */ | 1549 | */ |
1591 | expire_client(unconf); | 1550 | expire_client(unconf); |
1592 | } | 1551 | } |
1593 | new = create_client(clname, dname); | 1552 | new = create_client(clname, dname, rqstp, &clverifier); |
1594 | if (new == NULL) | 1553 | if (new == NULL) |
1595 | goto out; | 1554 | goto out; |
1596 | copy_clid(new, conf); | 1555 | copy_clid(new, conf); |
@@ -1600,7 +1559,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1600 | * probable client reboot; state will be removed if | 1559 | * probable client reboot; state will be removed if |
1601 | * confirmed. | 1560 | * confirmed. |
1602 | */ | 1561 | */ |
1603 | new = create_client(clname, dname); | 1562 | new = create_client(clname, dname, rqstp, &clverifier); |
1604 | if (new == NULL) | 1563 | if (new == NULL) |
1605 | goto out; | 1564 | goto out; |
1606 | gen_clid(new); | 1565 | gen_clid(new); |
@@ -1611,25 +1570,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1611 | * confirmed. | 1570 | * confirmed. |
1612 | */ | 1571 | */ |
1613 | expire_client(unconf); | 1572 | expire_client(unconf); |
1614 | new = create_client(clname, dname); | 1573 | new = create_client(clname, dname, rqstp, &clverifier); |
1615 | if (new == NULL) | 1574 | if (new == NULL) |
1616 | goto out; | 1575 | goto out; |
1617 | gen_clid(new); | 1576 | gen_clid(new); |
1618 | } | 1577 | } |
1619 | copy_verf(new, &clverifier); | 1578 | gen_callback(new, setclid, rpc_get_scope_id(sa)); |
1620 | new->cl_addr = sin->sin_addr.s_addr; | ||
1621 | new->cl_flavor = rqstp->rq_flavor; | ||
1622 | princ = svc_gss_principal(rqstp); | ||
1623 | if (princ) { | ||
1624 | new->cl_principal = kstrdup(princ, GFP_KERNEL); | ||
1625 | if (new->cl_principal == NULL) { | ||
1626 | free_client(new); | ||
1627 | goto out; | ||
1628 | } | ||
1629 | } | ||
1630 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | ||
1631 | gen_confirm(new); | ||
1632 | gen_callback(new, setclid); | ||
1633 | add_to_unconfirmed(new, strhashval); | 1579 | add_to_unconfirmed(new, strhashval); |
1634 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 1580 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
1635 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 1581 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
@@ -1651,7 +1597,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1651 | struct nfsd4_compound_state *cstate, | 1597 | struct nfsd4_compound_state *cstate, |
1652 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 1598 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
1653 | { | 1599 | { |
1654 | struct sockaddr_in *sin = svc_addr_in(rqstp); | 1600 | struct sockaddr *sa = svc_addr(rqstp); |
1655 | struct nfs4_client *conf, *unconf; | 1601 | struct nfs4_client *conf, *unconf; |
1656 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 1602 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
1657 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 1603 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
@@ -1670,9 +1616,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1670 | unconf = find_unconfirmed_client(clid); | 1616 | unconf = find_unconfirmed_client(clid); |
1671 | 1617 | ||
1672 | status = nfserr_clid_inuse; | 1618 | status = nfserr_clid_inuse; |
1673 | if (conf && conf->cl_addr != sin->sin_addr.s_addr) | 1619 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) |
1674 | goto out; | 1620 | goto out; |
1675 | if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) | 1621 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) |
1676 | goto out; | 1622 | goto out; |
1677 | 1623 | ||
1678 | /* | 1624 | /* |
@@ -2163,7 +2109,7 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
2163 | return -EAGAIN; | 2109 | return -EAGAIN; |
2164 | } | 2110 | } |
2165 | 2111 | ||
2166 | static struct lock_manager_operations nfsd_lease_mng_ops = { | 2112 | static const struct lock_manager_operations nfsd_lease_mng_ops = { |
2167 | .fl_break = nfsd_break_deleg_cb, | 2113 | .fl_break = nfsd_break_deleg_cb, |
2168 | .fl_release_private = nfsd_release_deleg_cb, | 2114 | .fl_release_private = nfsd_release_deleg_cb, |
2169 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, | 2115 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, |
@@ -3368,7 +3314,7 @@ nfs4_transform_lock_offset(struct file_lock *lock) | |||
3368 | 3314 | ||
3369 | /* Hack!: For now, we're defining this just so we can use a pointer to it | 3315 | /* Hack!: For now, we're defining this just so we can use a pointer to it |
3370 | * as a unique cookie to identify our (NFSv4's) posix locks. */ | 3316 | * as a unique cookie to identify our (NFSv4's) posix locks. */ |
3371 | static struct lock_manager_operations nfsd_posix_mng_ops = { | 3317 | static const struct lock_manager_operations nfsd_posix_mng_ops = { |
3372 | }; | 3318 | }; |
3373 | 3319 | ||
3374 | static inline void | 3320 | static inline void |
@@ -4072,7 +4018,7 @@ set_max_delegations(void) | |||
4072 | 4018 | ||
4073 | /* initialization to perform when the nfsd service is started: */ | 4019 | /* initialization to perform when the nfsd service is started: */ |
4074 | 4020 | ||
4075 | static void | 4021 | static int |
4076 | __nfs4_state_start(void) | 4022 | __nfs4_state_start(void) |
4077 | { | 4023 | { |
4078 | unsigned long grace_time; | 4024 | unsigned long grace_time; |
@@ -4084,19 +4030,26 @@ __nfs4_state_start(void) | |||
4084 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4030 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4085 | grace_time/HZ); | 4031 | grace_time/HZ); |
4086 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4032 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4033 | if (laundry_wq == NULL) | ||
4034 | return -ENOMEM; | ||
4087 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); | 4035 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); |
4088 | set_max_delegations(); | 4036 | set_max_delegations(); |
4037 | return set_callback_cred(); | ||
4089 | } | 4038 | } |
4090 | 4039 | ||
4091 | void | 4040 | int |
4092 | nfs4_state_start(void) | 4041 | nfs4_state_start(void) |
4093 | { | 4042 | { |
4043 | int ret; | ||
4044 | |||
4094 | if (nfs4_init) | 4045 | if (nfs4_init) |
4095 | return; | 4046 | return 0; |
4096 | nfsd4_load_reboot_recovery_data(); | 4047 | nfsd4_load_reboot_recovery_data(); |
4097 | __nfs4_state_start(); | 4048 | ret = __nfs4_state_start(); |
4049 | if (ret) | ||
4050 | return ret; | ||
4098 | nfs4_init = 1; | 4051 | nfs4_init = 1; |
4099 | return; | 4052 | return 0; |
4100 | } | 4053 | } |
4101 | 4054 | ||
4102 | time_t | 4055 | time_t |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2dcc7feaa6f..0fbd50cee1f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1599,7 +1599,8 @@ static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location, | |||
1599 | static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) | 1599 | static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat) |
1600 | { | 1600 | { |
1601 | struct svc_fh tmp_fh; | 1601 | struct svc_fh tmp_fh; |
1602 | char *path, *rootpath; | 1602 | char *path = NULL, *rootpath; |
1603 | size_t rootlen; | ||
1603 | 1604 | ||
1604 | fh_init(&tmp_fh, NFS4_FHSIZE); | 1605 | fh_init(&tmp_fh, NFS4_FHSIZE); |
1605 | *stat = exp_pseudoroot(rqstp, &tmp_fh); | 1606 | *stat = exp_pseudoroot(rqstp, &tmp_fh); |
@@ -1609,14 +1610,18 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * | |||
1609 | 1610 | ||
1610 | path = exp->ex_pathname; | 1611 | path = exp->ex_pathname; |
1611 | 1612 | ||
1612 | if (strncmp(path, rootpath, strlen(rootpath))) { | 1613 | rootlen = strlen(rootpath); |
1614 | if (strncmp(path, rootpath, rootlen)) { | ||
1613 | dprintk("nfsd: fs_locations failed;" | 1615 | dprintk("nfsd: fs_locations failed;" |
1614 | "%s is not contained in %s\n", path, rootpath); | 1616 | "%s is not contained in %s\n", path, rootpath); |
1615 | *stat = nfserr_notsupp; | 1617 | *stat = nfserr_notsupp; |
1616 | return NULL; | 1618 | path = NULL; |
1619 | goto out; | ||
1617 | } | 1620 | } |
1618 | 1621 | path += rootlen; | |
1619 | return path + strlen(rootpath); | 1622 | out: |
1623 | fh_put(&tmp_fh); | ||
1624 | return path; | ||
1620 | } | 1625 | } |
1621 | 1626 | ||
1622 | /* | 1627 | /* |
@@ -1793,11 +1798,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1793 | goto out_nfserr; | 1798 | goto out_nfserr; |
1794 | } | 1799 | } |
1795 | } | 1800 | } |
1796 | if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) { | ||
1797 | if (exp->ex_fslocs.locations == NULL) { | ||
1798 | bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS; | ||
1799 | } | ||
1800 | } | ||
1801 | if ((buflen -= 16) < 0) | 1801 | if ((buflen -= 16) < 0) |
1802 | goto out_resource; | 1802 | goto out_resource; |
1803 | 1803 | ||
@@ -1825,8 +1825,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1825 | goto out_resource; | 1825 | goto out_resource; |
1826 | if (!aclsupport) | 1826 | if (!aclsupport) |
1827 | word0 &= ~FATTR4_WORD0_ACL; | 1827 | word0 &= ~FATTR4_WORD0_ACL; |
1828 | if (!exp->ex_fslocs.locations) | ||
1829 | word0 &= ~FATTR4_WORD0_FS_LOCATIONS; | ||
1830 | if (!word2) { | 1828 | if (!word2) { |
1831 | WRITE32(2); | 1829 | WRITE32(2); |
1832 | WRITE32(word0); | 1830 | WRITE32(word0); |
@@ -3064,6 +3062,7 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr, | |||
3064 | WRITE32(0); | 3062 | WRITE32(0); |
3065 | 3063 | ||
3066 | ADJUST_ARGS(); | 3064 | ADJUST_ARGS(); |
3065 | resp->cstate.datap = p; /* DRC cache data pointer */ | ||
3067 | return 0; | 3066 | return 0; |
3068 | } | 3067 | } |
3069 | 3068 | ||
@@ -3166,7 +3165,7 @@ static int nfsd4_check_drc_limit(struct nfsd4_compoundres *resp) | |||
3166 | return status; | 3165 | return status; |
3167 | 3166 | ||
3168 | session = resp->cstate.session; | 3167 | session = resp->cstate.session; |
3169 | if (session == NULL || slot->sl_cache_entry.ce_cachethis == 0) | 3168 | if (session == NULL || slot->sl_cachethis == 0) |
3170 | return status; | 3169 | return status; |
3171 | 3170 | ||
3172 | if (resp->opcnt >= args->opcnt) | 3171 | if (resp->opcnt >= args->opcnt) |
@@ -3291,6 +3290,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3291 | /* | 3290 | /* |
3292 | * All that remains is to write the tag and operation count... | 3291 | * All that remains is to write the tag and operation count... |
3293 | */ | 3292 | */ |
3293 | struct nfsd4_compound_state *cs = &resp->cstate; | ||
3294 | struct kvec *iov; | 3294 | struct kvec *iov; |
3295 | p = resp->tagp; | 3295 | p = resp->tagp; |
3296 | *p++ = htonl(resp->taglen); | 3296 | *p++ = htonl(resp->taglen); |
@@ -3304,17 +3304,11 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compo | |||
3304 | iov = &rqstp->rq_res.head[0]; | 3304 | iov = &rqstp->rq_res.head[0]; |
3305 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; | 3305 | iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base; |
3306 | BUG_ON(iov->iov_len > PAGE_SIZE); | 3306 | BUG_ON(iov->iov_len > PAGE_SIZE); |
3307 | if (nfsd4_has_session(&resp->cstate)) { | 3307 | if (nfsd4_has_session(cs) && cs->status != nfserr_replay_cache) { |
3308 | if (resp->cstate.status == nfserr_replay_cache && | 3308 | nfsd4_store_cache_entry(resp); |
3309 | !nfsd4_not_cached(resp)) { | 3309 | dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__); |
3310 | iov->iov_len = resp->cstate.iovlen; | 3310 | resp->cstate.slot->sl_inuse = false; |
3311 | } else { | 3311 | nfsd4_put_session(resp->cstate.session); |
3312 | nfsd4_store_cache_entry(resp); | ||
3313 | dprintk("%s: SET SLOT STATE TO AVAILABLE\n", __func__); | ||
3314 | resp->cstate.slot->sl_inuse = 0; | ||
3315 | } | ||
3316 | if (resp->cstate.session) | ||
3317 | nfsd4_put_session(resp->cstate.session); | ||
3318 | } | 3312 | } |
3319 | return 1; | 3313 | return 1; |
3320 | } | 3314 | } |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7e906c5b767..00388d2a3c9 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -174,12 +174,13 @@ static const struct file_operations exports_operations = { | |||
174 | }; | 174 | }; |
175 | 175 | ||
176 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); | 176 | extern int nfsd_pool_stats_open(struct inode *inode, struct file *file); |
177 | extern int nfsd_pool_stats_release(struct inode *inode, struct file *file); | ||
177 | 178 | ||
178 | static struct file_operations pool_stats_operations = { | 179 | static struct file_operations pool_stats_operations = { |
179 | .open = nfsd_pool_stats_open, | 180 | .open = nfsd_pool_stats_open, |
180 | .read = seq_read, | 181 | .read = seq_read, |
181 | .llseek = seq_lseek, | 182 | .llseek = seq_lseek, |
182 | .release = seq_release, | 183 | .release = nfsd_pool_stats_release, |
183 | .owner = THIS_MODULE, | 184 | .owner = THIS_MODULE, |
184 | }; | 185 | }; |
185 | 186 | ||
@@ -776,10 +777,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size) | |||
776 | size -= len; | 777 | size -= len; |
777 | mesg += len; | 778 | mesg += len; |
778 | } | 779 | } |
779 | 780 | rv = mesg - buf; | |
780 | mutex_unlock(&nfsd_mutex); | ||
781 | return (mesg-buf); | ||
782 | |||
783 | out_free: | 781 | out_free: |
784 | kfree(nthreads); | 782 | kfree(nthreads); |
785 | mutex_unlock(&nfsd_mutex); | 783 | mutex_unlock(&nfsd_mutex); |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 8847f3fbfc1..01965b2f3a7 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -397,44 +397,51 @@ static inline void _fh_update_old(struct dentry *dentry, | |||
397 | fh->ofh_dirino = 0; | 397 | fh->ofh_dirino = 0; |
398 | } | 398 | } |
399 | 399 | ||
400 | __be32 | 400 | static bool is_root_export(struct svc_export *exp) |
401 | fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | ||
402 | struct svc_fh *ref_fh) | ||
403 | { | 401 | { |
404 | /* ref_fh is a reference file handle. | 402 | return exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root; |
405 | * if it is non-null and for the same filesystem, then we should compose | 403 | } |
406 | * a filehandle which is of the same version, where possible. | ||
407 | * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca | ||
408 | * Then create a 32byte filehandle using nfs_fhbase_old | ||
409 | * | ||
410 | */ | ||
411 | 404 | ||
412 | u8 version; | 405 | static struct super_block *exp_sb(struct svc_export *exp) |
413 | u8 fsid_type = 0; | 406 | { |
414 | struct inode * inode = dentry->d_inode; | 407 | return exp->ex_path.dentry->d_inode->i_sb; |
415 | struct dentry *parent = dentry->d_parent; | 408 | } |
416 | __u32 *datap; | ||
417 | dev_t ex_dev = exp->ex_path.dentry->d_inode->i_sb->s_dev; | ||
418 | int root_export = (exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root); | ||
419 | 409 | ||
420 | dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", | 410 | static bool fsid_type_ok_for_exp(u8 fsid_type, struct svc_export *exp) |
421 | MAJOR(ex_dev), MINOR(ex_dev), | 411 | { |
422 | (long) exp->ex_path.dentry->d_inode->i_ino, | 412 | switch (fsid_type) { |
423 | parent->d_name.name, dentry->d_name.name, | 413 | case FSID_DEV: |
424 | (inode ? inode->i_ino : 0)); | 414 | if (!old_valid_dev(exp_sb(exp)->s_dev)) |
415 | return 0; | ||
416 | /* FALL THROUGH */ | ||
417 | case FSID_MAJOR_MINOR: | ||
418 | case FSID_ENCODE_DEV: | ||
419 | return exp_sb(exp)->s_type->fs_flags & FS_REQUIRES_DEV; | ||
420 | case FSID_NUM: | ||
421 | return exp->ex_flags & NFSEXP_FSID; | ||
422 | case FSID_UUID8: | ||
423 | case FSID_UUID16: | ||
424 | if (!is_root_export(exp)) | ||
425 | return 0; | ||
426 | /* fall through */ | ||
427 | case FSID_UUID4_INUM: | ||
428 | case FSID_UUID16_INUM: | ||
429 | return exp->ex_uuid != NULL; | ||
430 | } | ||
431 | return 1; | ||
432 | } | ||
425 | 433 | ||
426 | /* Choose filehandle version and fsid type based on | 434 | |
427 | * the reference filehandle (if it is in the same export) | 435 | static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp, struct svc_fh *ref_fh) |
428 | * or the export options. | 436 | { |
429 | */ | 437 | u8 version; |
430 | retry: | 438 | u8 fsid_type; |
439 | retry: | ||
431 | version = 1; | 440 | version = 1; |
432 | if (ref_fh && ref_fh->fh_export == exp) { | 441 | if (ref_fh && ref_fh->fh_export == exp) { |
433 | version = ref_fh->fh_handle.fh_version; | 442 | version = ref_fh->fh_handle.fh_version; |
434 | fsid_type = ref_fh->fh_handle.fh_fsid_type; | 443 | fsid_type = ref_fh->fh_handle.fh_fsid_type; |
435 | 444 | ||
436 | if (ref_fh == fhp) | ||
437 | fh_put(ref_fh); | ||
438 | ref_fh = NULL; | 445 | ref_fh = NULL; |
439 | 446 | ||
440 | switch (version) { | 447 | switch (version) { |
@@ -447,58 +454,66 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
447 | goto retry; | 454 | goto retry; |
448 | } | 455 | } |
449 | 456 | ||
450 | /* Need to check that this type works for this | 457 | /* |
451 | * export point. As the fsid -> filesystem mapping | 458 | * As the fsid -> filesystem mapping was guided by |
452 | * was guided by user-space, there is no guarantee | 459 | * user-space, there is no guarantee that the filesystem |
453 | * that the filesystem actually supports that fsid | 460 | * actually supports that fsid type. If it doesn't we |
454 | * type. If it doesn't we loop around again without | 461 | * loop around again without ref_fh set. |
455 | * ref_fh set. | ||
456 | */ | 462 | */ |
457 | switch(fsid_type) { | 463 | if (!fsid_type_ok_for_exp(fsid_type, exp)) |
458 | case FSID_DEV: | 464 | goto retry; |
459 | if (!old_valid_dev(ex_dev)) | ||
460 | goto retry; | ||
461 | /* FALL THROUGH */ | ||
462 | case FSID_MAJOR_MINOR: | ||
463 | case FSID_ENCODE_DEV: | ||
464 | if (!(exp->ex_path.dentry->d_inode->i_sb->s_type->fs_flags | ||
465 | & FS_REQUIRES_DEV)) | ||
466 | goto retry; | ||
467 | break; | ||
468 | case FSID_NUM: | ||
469 | if (! (exp->ex_flags & NFSEXP_FSID)) | ||
470 | goto retry; | ||
471 | break; | ||
472 | case FSID_UUID8: | ||
473 | case FSID_UUID16: | ||
474 | if (!root_export) | ||
475 | goto retry; | ||
476 | /* fall through */ | ||
477 | case FSID_UUID4_INUM: | ||
478 | case FSID_UUID16_INUM: | ||
479 | if (exp->ex_uuid == NULL) | ||
480 | goto retry; | ||
481 | break; | ||
482 | } | ||
483 | } else if (exp->ex_flags & NFSEXP_FSID) { | 465 | } else if (exp->ex_flags & NFSEXP_FSID) { |
484 | fsid_type = FSID_NUM; | 466 | fsid_type = FSID_NUM; |
485 | } else if (exp->ex_uuid) { | 467 | } else if (exp->ex_uuid) { |
486 | if (fhp->fh_maxsize >= 64) { | 468 | if (fhp->fh_maxsize >= 64) { |
487 | if (root_export) | 469 | if (is_root_export(exp)) |
488 | fsid_type = FSID_UUID16; | 470 | fsid_type = FSID_UUID16; |
489 | else | 471 | else |
490 | fsid_type = FSID_UUID16_INUM; | 472 | fsid_type = FSID_UUID16_INUM; |
491 | } else { | 473 | } else { |
492 | if (root_export) | 474 | if (is_root_export(exp)) |
493 | fsid_type = FSID_UUID8; | 475 | fsid_type = FSID_UUID8; |
494 | else | 476 | else |
495 | fsid_type = FSID_UUID4_INUM; | 477 | fsid_type = FSID_UUID4_INUM; |
496 | } | 478 | } |
497 | } else if (!old_valid_dev(ex_dev)) | 479 | } else if (!old_valid_dev(exp_sb(exp)->s_dev)) |
498 | /* for newer device numbers, we must use a newer fsid format */ | 480 | /* for newer device numbers, we must use a newer fsid format */ |
499 | fsid_type = FSID_ENCODE_DEV; | 481 | fsid_type = FSID_ENCODE_DEV; |
500 | else | 482 | else |
501 | fsid_type = FSID_DEV; | 483 | fsid_type = FSID_DEV; |
484 | fhp->fh_handle.fh_version = version; | ||
485 | if (version) | ||
486 | fhp->fh_handle.fh_fsid_type = fsid_type; | ||
487 | } | ||
488 | |||
489 | __be32 | ||
490 | fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | ||
491 | struct svc_fh *ref_fh) | ||
492 | { | ||
493 | /* ref_fh is a reference file handle. | ||
494 | * if it is non-null and for the same filesystem, then we should compose | ||
495 | * a filehandle which is of the same version, where possible. | ||
496 | * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca | ||
497 | * Then create a 32byte filehandle using nfs_fhbase_old | ||
498 | * | ||
499 | */ | ||
500 | |||
501 | struct inode * inode = dentry->d_inode; | ||
502 | struct dentry *parent = dentry->d_parent; | ||
503 | __u32 *datap; | ||
504 | dev_t ex_dev = exp_sb(exp)->s_dev; | ||
505 | |||
506 | dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", | ||
507 | MAJOR(ex_dev), MINOR(ex_dev), | ||
508 | (long) exp->ex_path.dentry->d_inode->i_ino, | ||
509 | parent->d_name.name, dentry->d_name.name, | ||
510 | (inode ? inode->i_ino : 0)); | ||
511 | |||
512 | /* Choose filehandle version and fsid type based on | ||
513 | * the reference filehandle (if it is in the same export) | ||
514 | * or the export options. | ||
515 | */ | ||
516 | set_version_and_fsid_type(fhp, exp, ref_fh); | ||
502 | 517 | ||
503 | if (ref_fh == fhp) | 518 | if (ref_fh == fhp) |
504 | fh_put(ref_fh); | 519 | fh_put(ref_fh); |
@@ -516,7 +531,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
516 | fhp->fh_export = exp; | 531 | fhp->fh_export = exp; |
517 | cache_get(&exp->h); | 532 | cache_get(&exp->h); |
518 | 533 | ||
519 | if (version == 0xca) { | 534 | if (fhp->fh_handle.fh_version == 0xca) { |
520 | /* old style filehandle please */ | 535 | /* old style filehandle please */ |
521 | memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); | 536 | memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); |
522 | fhp->fh_handle.fh_size = NFS_FHSIZE; | 537 | fhp->fh_handle.fh_size = NFS_FHSIZE; |
@@ -530,22 +545,22 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
530 | _fh_update_old(dentry, exp, &fhp->fh_handle); | 545 | _fh_update_old(dentry, exp, &fhp->fh_handle); |
531 | } else { | 546 | } else { |
532 | int len; | 547 | int len; |
533 | fhp->fh_handle.fh_version = 1; | ||
534 | fhp->fh_handle.fh_auth_type = 0; | 548 | fhp->fh_handle.fh_auth_type = 0; |
535 | datap = fhp->fh_handle.fh_auth+0; | 549 | datap = fhp->fh_handle.fh_auth+0; |
536 | fhp->fh_handle.fh_fsid_type = fsid_type; | 550 | mk_fsid(fhp->fh_handle.fh_fsid_type, datap, ex_dev, |
537 | mk_fsid(fsid_type, datap, ex_dev, | ||
538 | exp->ex_path.dentry->d_inode->i_ino, | 551 | exp->ex_path.dentry->d_inode->i_ino, |
539 | exp->ex_fsid, exp->ex_uuid); | 552 | exp->ex_fsid, exp->ex_uuid); |
540 | 553 | ||
541 | len = key_len(fsid_type); | 554 | len = key_len(fhp->fh_handle.fh_fsid_type); |
542 | datap += len/4; | 555 | datap += len/4; |
543 | fhp->fh_handle.fh_size = 4 + len; | 556 | fhp->fh_handle.fh_size = 4 + len; |
544 | 557 | ||
545 | if (inode) | 558 | if (inode) |
546 | _fh_update(fhp, exp, dentry); | 559 | _fh_update(fhp, exp, dentry); |
547 | if (fhp->fh_handle.fh_fileid_type == 255) | 560 | if (fhp->fh_handle.fh_fileid_type == 255) { |
561 | fh_put(fhp); | ||
548 | return nfserr_opnotsupp; | 562 | return nfserr_opnotsupp; |
563 | } | ||
549 | } | 564 | } |
550 | 565 | ||
551 | return 0; | 566 | return 0; |
@@ -639,8 +654,7 @@ enum fsid_source fsid_source(struct svc_fh *fhp) | |||
639 | case FSID_DEV: | 654 | case FSID_DEV: |
640 | case FSID_ENCODE_DEV: | 655 | case FSID_ENCODE_DEV: |
641 | case FSID_MAJOR_MINOR: | 656 | case FSID_MAJOR_MINOR: |
642 | if (fhp->fh_export->ex_path.dentry->d_inode->i_sb->s_type->fs_flags | 657 | if (exp_sb(fhp->fh_export)->s_type->fs_flags & FS_REQUIRES_DEV) |
643 | & FS_REQUIRES_DEV) | ||
644 | return FSIDSOURCE_DEV; | 658 | return FSIDSOURCE_DEV; |
645 | break; | 659 | break; |
646 | case FSID_NUM: | 660 | case FSID_NUM: |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 24d58adfe5f..67ea83eedd4 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/nfsd/syscall.h> | 34 | #include <linux/nfsd/syscall.h> |
35 | #include <linux/lockd/bind.h> | 35 | #include <linux/lockd/bind.h> |
36 | #include <linux/nfsacl.h> | 36 | #include <linux/nfsacl.h> |
37 | #include <linux/seq_file.h> | ||
37 | 38 | ||
38 | #define NFSDDBG_FACILITY NFSDDBG_SVC | 39 | #define NFSDDBG_FACILITY NFSDDBG_SVC |
39 | 40 | ||
@@ -66,6 +67,16 @@ struct timeval nfssvc_boot; | |||
66 | DEFINE_MUTEX(nfsd_mutex); | 67 | DEFINE_MUTEX(nfsd_mutex); |
67 | struct svc_serv *nfsd_serv; | 68 | struct svc_serv *nfsd_serv; |
68 | 69 | ||
70 | /* | ||
71 | * nfsd_drc_lock protects nfsd_drc_max_pages and nfsd_drc_pages_used. | ||
72 | * nfsd_drc_max_pages limits the total amount of memory available for | ||
73 | * version 4.1 DRC caches. | ||
74 | * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage. | ||
75 | */ | ||
76 | spinlock_t nfsd_drc_lock; | ||
77 | unsigned int nfsd_drc_max_mem; | ||
78 | unsigned int nfsd_drc_mem_used; | ||
79 | |||
69 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | 80 | #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) |
70 | static struct svc_stat nfsd_acl_svcstats; | 81 | static struct svc_stat nfsd_acl_svcstats; |
71 | static struct svc_version * nfsd_acl_version[] = { | 82 | static struct svc_version * nfsd_acl_version[] = { |
@@ -235,13 +246,12 @@ void nfsd_reset_versions(void) | |||
235 | */ | 246 | */ |
236 | static void set_max_drc(void) | 247 | static void set_max_drc(void) |
237 | { | 248 | { |
238 | /* The percent of nr_free_buffer_pages used by the V4.1 server DRC */ | 249 | #define NFSD_DRC_SIZE_SHIFT 10 |
239 | #define NFSD_DRC_SIZE_SHIFT 7 | 250 | nfsd_drc_max_mem = (nr_free_buffer_pages() |
240 | nfsd_serv->sv_drc_max_pages = nr_free_buffer_pages() | 251 | >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; |
241 | >> NFSD_DRC_SIZE_SHIFT; | 252 | nfsd_drc_mem_used = 0; |
242 | nfsd_serv->sv_drc_pages_used = 0; | 253 | spin_lock_init(&nfsd_drc_lock); |
243 | dprintk("%s svc_drc_max_pages %u\n", __func__, | 254 | dprintk("%s nfsd_drc_max_mem %u \n", __func__, nfsd_drc_max_mem); |
244 | nfsd_serv->sv_drc_max_pages); | ||
245 | } | 255 | } |
246 | 256 | ||
247 | int nfsd_create_serv(void) | 257 | int nfsd_create_serv(void) |
@@ -401,7 +411,9 @@ nfsd_svc(unsigned short port, int nrservs) | |||
401 | error = nfsd_racache_init(2*nrservs); | 411 | error = nfsd_racache_init(2*nrservs); |
402 | if (error<0) | 412 | if (error<0) |
403 | goto out; | 413 | goto out; |
404 | nfs4_state_start(); | 414 | error = nfs4_state_start(); |
415 | if (error) | ||
416 | goto out; | ||
405 | 417 | ||
406 | nfsd_reset_versions(); | 418 | nfsd_reset_versions(); |
407 | 419 | ||
@@ -569,10 +581,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
569 | + rqstp->rq_res.head[0].iov_len; | 581 | + rqstp->rq_res.head[0].iov_len; |
570 | rqstp->rq_res.head[0].iov_len += sizeof(__be32); | 582 | rqstp->rq_res.head[0].iov_len += sizeof(__be32); |
571 | 583 | ||
572 | /* NFSv4.1 DRC requires statp */ | ||
573 | if (rqstp->rq_vers == 4) | ||
574 | nfsd4_set_statp(rqstp, statp); | ||
575 | |||
576 | /* Now call the procedure handler, and encode NFS status. */ | 584 | /* Now call the procedure handler, and encode NFS status. */ |
577 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 585 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
578 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); | 586 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); |
@@ -607,7 +615,25 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
607 | 615 | ||
608 | int nfsd_pool_stats_open(struct inode *inode, struct file *file) | 616 | int nfsd_pool_stats_open(struct inode *inode, struct file *file) |
609 | { | 617 | { |
610 | if (nfsd_serv == NULL) | 618 | int ret; |
619 | mutex_lock(&nfsd_mutex); | ||
620 | if (nfsd_serv == NULL) { | ||
621 | mutex_unlock(&nfsd_mutex); | ||
611 | return -ENODEV; | 622 | return -ENODEV; |
612 | return svc_pool_stats_open(nfsd_serv, file); | 623 | } |
624 | /* bump up the psudo refcount while traversing */ | ||
625 | svc_get(nfsd_serv); | ||
626 | ret = svc_pool_stats_open(nfsd_serv, file); | ||
627 | mutex_unlock(&nfsd_mutex); | ||
628 | return ret; | ||
629 | } | ||
630 | |||
631 | int nfsd_pool_stats_release(struct inode *inode, struct file *file) | ||
632 | { | ||
633 | int ret = seq_release(inode, file); | ||
634 | mutex_lock(&nfsd_mutex); | ||
635 | /* this function really, really should have been called svc_put() */ | ||
636 | svc_destroy(nfsd_serv); | ||
637 | mutex_unlock(&nfsd_mutex); | ||
638 | return ret; | ||
613 | } | 639 | } |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8fa09bfbcba..a293f027326 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -89,6 +89,12 @@ struct raparm_hbucket { | |||
89 | #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) | 89 | #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) |
90 | static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; | 90 | static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; |
91 | 91 | ||
92 | static inline int | ||
93 | nfsd_v4client(struct svc_rqst *rq) | ||
94 | { | ||
95 | return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; | ||
96 | } | ||
97 | |||
92 | /* | 98 | /* |
93 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed | 99 | * Called from nfsd_lookup and encode_dirent. Check if we have crossed |
94 | * a mount point. | 100 | * a mount point. |
@@ -115,7 +121,8 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
115 | path_put(&path); | 121 | path_put(&path); |
116 | goto out; | 122 | goto out; |
117 | } | 123 | } |
118 | if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { | 124 | if (nfsd_v4client(rqstp) || |
125 | (exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { | ||
119 | /* successfully crossed mount point */ | 126 | /* successfully crossed mount point */ |
120 | /* | 127 | /* |
121 | * This is subtle: path.dentry is *not* on path.mnt | 128 | * This is subtle: path.dentry is *not* on path.mnt |
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index c668bca579c..6a2711f4c32 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c | |||
@@ -46,7 +46,7 @@ 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 const struct address_space_operations def_btnode_aops = { |
50 | .sync_page = block_sync_page, | 50 | .sync_page = block_sync_page, |
51 | }; | 51 | }; |
52 | 52 | ||
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index 6bd84a0d823..fc8278c77cd 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c | |||
@@ -151,7 +151,7 @@ struct file_operations nilfs_file_operations = { | |||
151 | .splice_read = generic_file_splice_read, | 151 | .splice_read = generic_file_splice_read, |
152 | }; | 152 | }; |
153 | 153 | ||
154 | struct inode_operations nilfs_file_inode_operations = { | 154 | const struct inode_operations nilfs_file_inode_operations = { |
155 | .truncate = nilfs_truncate, | 155 | .truncate = nilfs_truncate, |
156 | .setattr = nilfs_setattr, | 156 | .setattr = nilfs_setattr, |
157 | .permission = nilfs_permission, | 157 | .permission = nilfs_permission, |
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 1b3c2bb20da..e6de0a27ab5 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c | |||
@@ -52,7 +52,7 @@ | |||
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 const struct address_space_operations def_gcinode_aops = { |
56 | .sync_page = block_sync_page, | 56 | .sync_page = block_sync_page, |
57 | }; | 57 | }; |
58 | 58 | ||
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 807e584b163..2d2c501deb5 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -238,7 +238,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
238 | return size; | 238 | return size; |
239 | } | 239 | } |
240 | 240 | ||
241 | struct address_space_operations nilfs_aops = { | 241 | const struct address_space_operations nilfs_aops = { |
242 | .writepage = nilfs_writepage, | 242 | .writepage = nilfs_writepage, |
243 | .readpage = nilfs_readpage, | 243 | .readpage = nilfs_readpage, |
244 | .sync_page = block_sync_page, | 244 | .sync_page = block_sync_page, |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 156bf6091a9..b18c4998f8d 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
@@ -427,12 +427,12 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) | |||
427 | } | 427 | } |
428 | 428 | ||
429 | 429 | ||
430 | static struct address_space_operations def_mdt_aops = { | 430 | static const struct address_space_operations def_mdt_aops = { |
431 | .writepage = nilfs_mdt_write_page, | 431 | .writepage = nilfs_mdt_write_page, |
432 | .sync_page = block_sync_page, | 432 | .sync_page = block_sync_page, |
433 | }; | 433 | }; |
434 | 434 | ||
435 | static struct inode_operations def_mdt_iops; | 435 | static const struct inode_operations def_mdt_iops; |
436 | static struct file_operations def_mdt_fops; | 436 | static struct file_operations def_mdt_fops; |
437 | 437 | ||
438 | /* | 438 | /* |
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index df70dadb336..ed02e886fa7 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c | |||
@@ -448,7 +448,7 @@ out: | |||
448 | return err; | 448 | return err; |
449 | } | 449 | } |
450 | 450 | ||
451 | struct inode_operations nilfs_dir_inode_operations = { | 451 | const struct inode_operations nilfs_dir_inode_operations = { |
452 | .create = nilfs_create, | 452 | .create = nilfs_create, |
453 | .lookup = nilfs_lookup, | 453 | .lookup = nilfs_lookup, |
454 | .link = nilfs_link, | 454 | .link = nilfs_link, |
@@ -462,12 +462,12 @@ struct inode_operations nilfs_dir_inode_operations = { | |||
462 | .permission = nilfs_permission, | 462 | .permission = nilfs_permission, |
463 | }; | 463 | }; |
464 | 464 | ||
465 | struct inode_operations nilfs_special_inode_operations = { | 465 | const struct inode_operations nilfs_special_inode_operations = { |
466 | .setattr = nilfs_setattr, | 466 | .setattr = nilfs_setattr, |
467 | .permission = nilfs_permission, | 467 | .permission = nilfs_permission, |
468 | }; | 468 | }; |
469 | 469 | ||
470 | struct inode_operations nilfs_symlink_inode_operations = { | 470 | const struct inode_operations nilfs_symlink_inode_operations = { |
471 | .readlink = generic_readlink, | 471 | .readlink = generic_readlink, |
472 | .follow_link = page_follow_link_light, | 472 | .follow_link = page_follow_link_light, |
473 | .put_link = page_put_link, | 473 | .put_link = page_put_link, |
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 724c63766e8..bad7368782d 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -295,12 +295,12 @@ void nilfs_clear_gcdat_inode(struct the_nilfs *); | |||
295 | * Inodes and files operations | 295 | * Inodes and files operations |
296 | */ | 296 | */ |
297 | extern struct file_operations nilfs_dir_operations; | 297 | extern struct file_operations nilfs_dir_operations; |
298 | extern struct inode_operations nilfs_file_inode_operations; | 298 | extern const struct inode_operations nilfs_file_inode_operations; |
299 | extern struct file_operations nilfs_file_operations; | 299 | extern struct file_operations nilfs_file_operations; |
300 | extern struct address_space_operations nilfs_aops; | 300 | extern const struct address_space_operations nilfs_aops; |
301 | extern struct inode_operations nilfs_dir_inode_operations; | 301 | extern const struct inode_operations nilfs_dir_inode_operations; |
302 | extern struct inode_operations nilfs_special_inode_operations; | 302 | extern const struct inode_operations nilfs_special_inode_operations; |
303 | extern struct inode_operations nilfs_symlink_inode_operations; | 303 | extern const struct inode_operations nilfs_symlink_inode_operations; |
304 | 304 | ||
305 | /* | 305 | /* |
306 | * filesystem type | 306 | * filesystem type |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 55f3d6b6073..644e66727dd 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -504,7 +504,7 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
504 | return 0; | 504 | return 0; |
505 | } | 505 | } |
506 | 506 | ||
507 | static struct super_operations nilfs_sops = { | 507 | static const struct super_operations nilfs_sops = { |
508 | .alloc_inode = nilfs_alloc_inode, | 508 | .alloc_inode = nilfs_alloc_inode, |
509 | .destroy_inode = nilfs_destroy_inode, | 509 | .destroy_inode = nilfs_destroy_inode, |
510 | .dirty_inode = nilfs_dirty_inode, | 510 | .dirty_inode = nilfs_dirty_inode, |
@@ -560,7 +560,7 @@ nilfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, | |||
560 | nilfs_nfs_get_inode); | 560 | nilfs_nfs_get_inode); |
561 | } | 561 | } |
562 | 562 | ||
563 | static struct export_operations nilfs_export_ops = { | 563 | static const struct export_operations nilfs_export_ops = { |
564 | .fh_to_dentry = nilfs_fh_to_dentry, | 564 | .fh_to_dentry = nilfs_fh_to_dentry, |
565 | .fh_to_parent = nilfs_fh_to_parent, | 565 | .fh_to_parent = nilfs_fh_to_parent, |
566 | .get_parent = nilfs_get_parent, | 566 | .get_parent = nilfs_get_parent, |
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h index 50931b1ce4b..8b2549f672b 100644 --- a/fs/ntfs/layout.h +++ b/fs/ntfs/layout.h | |||
@@ -829,7 +829,7 @@ enum { | |||
829 | /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the | 829 | /* Note, FILE_ATTR_VALID_SET_FLAGS masks out the old DOS VolId, the |
830 | F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, | 830 | F_A_DEVICE, F_A_DIRECTORY, F_A_SPARSE_FILE, F_A_REPARSE_POINT, |
831 | F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask | 831 | F_A_COMPRESSED, and F_A_ENCRYPTED and preserves the rest. This mask |
832 | is used to to obtain all flags that are valid for setting. */ | 832 | is used to obtain all flags that are valid for setting. */ |
833 | /* | 833 | /* |
834 | * The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all | 834 | * The flag FILE_ATTR_DUP_FILENAME_INDEX_PRESENT is present in all |
835 | * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION | 835 | * FILENAME_ATTR attributes but not in the STANDARD_INFORMATION |
diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index cd0be3f5c3c..a44b14cbcee 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h | |||
@@ -47,7 +47,7 @@ static inline void *__ntfs_malloc(unsigned long size, gfp_t gfp_mask) | |||
47 | return kmalloc(PAGE_SIZE, gfp_mask & ~__GFP_HIGHMEM); | 47 | return kmalloc(PAGE_SIZE, gfp_mask & ~__GFP_HIGHMEM); |
48 | /* return (void *)__get_free_page(gfp_mask); */ | 48 | /* return (void *)__get_free_page(gfp_mask); */ |
49 | } | 49 | } |
50 | if (likely(size >> PAGE_SHIFT < num_physpages)) | 50 | if (likely((size >> PAGE_SHIFT) < totalram_pages)) |
51 | return __vmalloc(size, gfp_mask, PAGE_KERNEL); | 51 | return __vmalloc(size, gfp_mask, PAGE_KERNEL); |
52 | return NULL; | 52 | return NULL; |
53 | } | 53 | } |
diff --git a/fs/ocfs2/quota.h b/fs/ocfs2/quota.h index 3fb96fcd4c8..e5df9d170b0 100644 --- a/fs/ocfs2/quota.h +++ b/fs/ocfs2/quota.h | |||
@@ -109,7 +109,7 @@ void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex); | |||
109 | int ocfs2_read_quota_block(struct inode *inode, u64 v_block, | 109 | int ocfs2_read_quota_block(struct inode *inode, u64 v_block, |
110 | struct buffer_head **bh); | 110 | struct buffer_head **bh); |
111 | 111 | ||
112 | extern struct dquot_operations ocfs2_quota_operations; | 112 | extern const struct dquot_operations ocfs2_quota_operations; |
113 | extern struct quota_format_type ocfs2_quota_format; | 113 | extern struct quota_format_type ocfs2_quota_format; |
114 | 114 | ||
115 | int ocfs2_quota_setup(void); | 115 | int ocfs2_quota_setup(void); |
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index 44f2a5e1d04..3cf0ec0acdd 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
@@ -154,7 +154,7 @@ static int ocfs2_get_quota_block(struct inode *inode, int block, | |||
154 | err = -EIO; | 154 | err = -EIO; |
155 | mlog_errno(err); | 155 | mlog_errno(err); |
156 | } | 156 | } |
157 | return err;; | 157 | return err; |
158 | } | 158 | } |
159 | 159 | ||
160 | /* Read data from global quotafile - avoid pagecache and such because we cannot | 160 | /* Read data from global quotafile - avoid pagecache and such because we cannot |
@@ -849,7 +849,7 @@ static void ocfs2_destroy_dquot(struct dquot *dquot) | |||
849 | kmem_cache_free(ocfs2_dquot_cachep, dquot); | 849 | kmem_cache_free(ocfs2_dquot_cachep, dquot); |
850 | } | 850 | } |
851 | 851 | ||
852 | struct dquot_operations ocfs2_quota_operations = { | 852 | const struct dquot_operations ocfs2_quota_operations = { |
853 | .initialize = dquot_initialize, | 853 | .initialize = dquot_initialize, |
854 | .drop = dquot_drop, | 854 | .drop = dquot_drop, |
855 | .alloc_space = dquot_alloc_space, | 855 | .alloc_space = dquot_alloc_space, |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index a3f8871d21f..faca4720aa4 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -965,7 +965,7 @@ static int ocfs2_quota_off(struct super_block *sb, int type, int remount) | |||
965 | return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED); | 965 | return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED); |
966 | } | 966 | } |
967 | 967 | ||
968 | static struct quotactl_ops ocfs2_quotactl_ops = { | 968 | static const struct quotactl_ops ocfs2_quotactl_ops = { |
969 | .quota_on = ocfs2_quota_on, | 969 | .quota_on = ocfs2_quota_on, |
970 | .quota_off = ocfs2_quota_off, | 970 | .quota_off = ocfs2_quota_off, |
971 | .quota_sync = vfs_quota_sync, | 971 | .quota_sync = vfs_quota_sync, |
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index c7275cfbdcf..3680bae335b 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c | |||
@@ -489,7 +489,7 @@ out: | |||
489 | return ret; | 489 | return ret; |
490 | } | 490 | } |
491 | 491 | ||
492 | struct inode_operations omfs_dir_inops = { | 492 | const struct inode_operations omfs_dir_inops = { |
493 | .lookup = omfs_lookup, | 493 | .lookup = omfs_lookup, |
494 | .mkdir = omfs_mkdir, | 494 | .mkdir = omfs_mkdir, |
495 | .rename = omfs_rename, | 495 | .rename = omfs_rename, |
diff --git a/fs/omfs/file.c b/fs/omfs/file.c index d17e774eaf4..4845fbb18e6 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c | |||
@@ -333,11 +333,11 @@ struct file_operations omfs_file_operations = { | |||
333 | .splice_read = generic_file_splice_read, | 333 | .splice_read = generic_file_splice_read, |
334 | }; | 334 | }; |
335 | 335 | ||
336 | struct inode_operations omfs_file_inops = { | 336 | const struct inode_operations omfs_file_inops = { |
337 | .truncate = omfs_truncate | 337 | .truncate = omfs_truncate |
338 | }; | 338 | }; |
339 | 339 | ||
340 | struct address_space_operations omfs_aops = { | 340 | const struct address_space_operations omfs_aops = { |
341 | .readpage = omfs_readpage, | 341 | .readpage = omfs_readpage, |
342 | .readpages = omfs_readpages, | 342 | .readpages = omfs_readpages, |
343 | .writepage = omfs_writepage, | 343 | .writepage = omfs_writepage, |
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 379ae5fb441..f3b7c1541f3 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c | |||
@@ -278,7 +278,7 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
278 | return 0; | 278 | return 0; |
279 | } | 279 | } |
280 | 280 | ||
281 | static struct super_operations omfs_sops = { | 281 | static const struct super_operations omfs_sops = { |
282 | .write_inode = omfs_write_inode, | 282 | .write_inode = omfs_write_inode, |
283 | .delete_inode = omfs_delete_inode, | 283 | .delete_inode = omfs_delete_inode, |
284 | .put_super = omfs_put_super, | 284 | .put_super = omfs_put_super, |
diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h index 2bc0f067040..df71039945a 100644 --- a/fs/omfs/omfs.h +++ b/fs/omfs/omfs.h | |||
@@ -45,15 +45,15 @@ extern int omfs_clear_range(struct super_block *sb, u64 block, int count); | |||
45 | 45 | ||
46 | /* dir.c */ | 46 | /* dir.c */ |
47 | extern struct file_operations omfs_dir_operations; | 47 | extern struct file_operations omfs_dir_operations; |
48 | extern struct inode_operations omfs_dir_inops; | 48 | extern const struct inode_operations omfs_dir_inops; |
49 | extern int omfs_make_empty(struct inode *inode, struct super_block *sb); | 49 | extern int omfs_make_empty(struct inode *inode, struct super_block *sb); |
50 | extern int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, | 50 | extern int omfs_is_bad(struct omfs_sb_info *sbi, struct omfs_header *header, |
51 | u64 fsblock); | 51 | u64 fsblock); |
52 | 52 | ||
53 | /* file.c */ | 53 | /* file.c */ |
54 | extern struct file_operations omfs_file_operations; | 54 | extern struct file_operations omfs_file_operations; |
55 | extern struct inode_operations omfs_file_inops; | 55 | extern const struct inode_operations omfs_file_inops; |
56 | extern struct address_space_operations omfs_aops; | 56 | extern const struct address_space_operations omfs_aops; |
57 | extern void omfs_make_empty_table(struct buffer_head *bh, int offset); | 57 | extern void omfs_make_empty_table(struct buffer_head *bh, int offset); |
58 | extern int omfs_shrink_inode(struct inode *inode); | 58 | extern int omfs_shrink_inode(struct inode *inode); |
59 | 59 | ||
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index fbeaddf595d..7b685e10cba 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -581,7 +581,7 @@ try_scan: | |||
581 | } | 581 | } |
582 | 582 | ||
583 | if (from + size > get_capacity(disk)) { | 583 | if (from + size > get_capacity(disk)) { |
584 | struct block_device_operations *bdops = disk->fops; | 584 | const struct block_device_operations *bdops = disk->fops; |
585 | unsigned long long capacity; | 585 | unsigned long long capacity; |
586 | 586 | ||
587 | printk(KERN_WARNING | 587 | printk(KERN_WARNING |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 6f742f6658a..55c4c805a75 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -447,7 +447,7 @@ static int proc_oom_score(struct task_struct *task, char *buffer) | |||
447 | 447 | ||
448 | do_posix_clock_monotonic_gettime(&uptime); | 448 | do_posix_clock_monotonic_gettime(&uptime); |
449 | read_lock(&tasklist_lock); | 449 | read_lock(&tasklist_lock); |
450 | points = badness(task, uptime.tv_sec); | 450 | points = badness(task->group_leader, uptime.tv_sec); |
451 | read_unlock(&tasklist_lock); | 451 | read_unlock(&tasklist_lock); |
452 | return sprintf(buffer, "%lu\n", points); | 452 | return sprintf(buffer, "%lu\n", points); |
453 | } | 453 | } |
@@ -999,11 +999,17 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf, | |||
999 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | 999 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); |
1000 | char buffer[PROC_NUMBUF]; | 1000 | char buffer[PROC_NUMBUF]; |
1001 | size_t len; | 1001 | size_t len; |
1002 | int oom_adjust; | 1002 | int oom_adjust = OOM_DISABLE; |
1003 | unsigned long flags; | ||
1003 | 1004 | ||
1004 | if (!task) | 1005 | if (!task) |
1005 | return -ESRCH; | 1006 | return -ESRCH; |
1006 | oom_adjust = task->oomkilladj; | 1007 | |
1008 | if (lock_task_sighand(task, &flags)) { | ||
1009 | oom_adjust = task->signal->oom_adj; | ||
1010 | unlock_task_sighand(task, &flags); | ||
1011 | } | ||
1012 | |||
1007 | put_task_struct(task); | 1013 | put_task_struct(task); |
1008 | 1014 | ||
1009 | len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); | 1015 | len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust); |
@@ -1015,32 +1021,44 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1015 | size_t count, loff_t *ppos) | 1021 | size_t count, loff_t *ppos) |
1016 | { | 1022 | { |
1017 | struct task_struct *task; | 1023 | struct task_struct *task; |
1018 | char buffer[PROC_NUMBUF], *end; | 1024 | char buffer[PROC_NUMBUF]; |
1019 | int oom_adjust; | 1025 | long oom_adjust; |
1026 | unsigned long flags; | ||
1027 | int err; | ||
1020 | 1028 | ||
1021 | memset(buffer, 0, sizeof(buffer)); | 1029 | memset(buffer, 0, sizeof(buffer)); |
1022 | if (count > sizeof(buffer) - 1) | 1030 | if (count > sizeof(buffer) - 1) |
1023 | count = sizeof(buffer) - 1; | 1031 | count = sizeof(buffer) - 1; |
1024 | if (copy_from_user(buffer, buf, count)) | 1032 | if (copy_from_user(buffer, buf, count)) |
1025 | return -EFAULT; | 1033 | return -EFAULT; |
1026 | oom_adjust = simple_strtol(buffer, &end, 0); | 1034 | |
1035 | err = strict_strtol(strstrip(buffer), 0, &oom_adjust); | ||
1036 | if (err) | ||
1037 | return -EINVAL; | ||
1027 | if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && | 1038 | if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && |
1028 | oom_adjust != OOM_DISABLE) | 1039 | oom_adjust != OOM_DISABLE) |
1029 | return -EINVAL; | 1040 | return -EINVAL; |
1030 | if (*end == '\n') | 1041 | |
1031 | end++; | ||
1032 | task = get_proc_task(file->f_path.dentry->d_inode); | 1042 | task = get_proc_task(file->f_path.dentry->d_inode); |
1033 | if (!task) | 1043 | if (!task) |
1034 | return -ESRCH; | 1044 | return -ESRCH; |
1035 | if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) { | 1045 | if (!lock_task_sighand(task, &flags)) { |
1046 | put_task_struct(task); | ||
1047 | return -ESRCH; | ||
1048 | } | ||
1049 | |||
1050 | if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { | ||
1051 | unlock_task_sighand(task, &flags); | ||
1036 | put_task_struct(task); | 1052 | put_task_struct(task); |
1037 | return -EACCES; | 1053 | return -EACCES; |
1038 | } | 1054 | } |
1039 | task->oomkilladj = oom_adjust; | 1055 | |
1056 | task->signal->oom_adj = oom_adjust; | ||
1057 | |||
1058 | unlock_task_sighand(task, &flags); | ||
1040 | put_task_struct(task); | 1059 | put_task_struct(task); |
1041 | if (end - buffer == 0) | 1060 | |
1042 | return -EIO; | 1061 | return count; |
1043 | return end - buffer; | ||
1044 | } | 1062 | } |
1045 | 1063 | ||
1046 | static const struct file_operations proc_oom_adjust_operations = { | 1064 | static const struct file_operations proc_oom_adjust_operations = { |
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index 59b43a06887..f06f45b4218 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
@@ -328,43 +328,12 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) | |||
328 | return -EFAULT; | 328 | return -EFAULT; |
329 | } else if (is_vmalloc_addr((void *)start)) { | 329 | } else if (is_vmalloc_addr((void *)start)) { |
330 | char * elf_buf; | 330 | char * elf_buf; |
331 | struct vm_struct *m; | ||
332 | unsigned long curstart = start; | ||
333 | unsigned long cursize = tsz; | ||
334 | 331 | ||
335 | elf_buf = kzalloc(tsz, GFP_KERNEL); | 332 | elf_buf = kzalloc(tsz, GFP_KERNEL); |
336 | if (!elf_buf) | 333 | if (!elf_buf) |
337 | return -ENOMEM; | 334 | return -ENOMEM; |
338 | 335 | vread(elf_buf, (char *)start, tsz); | |
339 | read_lock(&vmlist_lock); | 336 | /* we have to zero-fill user buffer even if no read */ |
340 | for (m=vmlist; m && cursize; m=m->next) { | ||
341 | unsigned long vmstart; | ||
342 | unsigned long vmsize; | ||
343 | unsigned long msize = m->size - PAGE_SIZE; | ||
344 | |||
345 | if (((unsigned long)m->addr + msize) < | ||
346 | curstart) | ||
347 | continue; | ||
348 | if ((unsigned long)m->addr > (curstart + | ||
349 | cursize)) | ||
350 | break; | ||
351 | vmstart = (curstart < (unsigned long)m->addr ? | ||
352 | (unsigned long)m->addr : curstart); | ||
353 | if (((unsigned long)m->addr + msize) > | ||
354 | (curstart + cursize)) | ||
355 | vmsize = curstart + cursize - vmstart; | ||
356 | else | ||
357 | vmsize = (unsigned long)m->addr + | ||
358 | msize - vmstart; | ||
359 | curstart = vmstart + vmsize; | ||
360 | cursize -= vmsize; | ||
361 | /* don't dump ioremap'd stuff! (TA) */ | ||
362 | if (m->flags & VM_IOREMAP) | ||
363 | continue; | ||
364 | memcpy(elf_buf + (vmstart - start), | ||
365 | (char *)vmstart, vmsize); | ||
366 | } | ||
367 | read_unlock(&vmlist_lock); | ||
368 | if (copy_to_user(buffer, elf_buf, tsz)) { | 337 | if (copy_to_user(buffer, elf_buf, tsz)) { |
369 | kfree(elf_buf); | 338 | kfree(elf_buf); |
370 | return -EFAULT; | 339 | return -EFAULT; |
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index d5c410d47fa..171e052c07b 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c | |||
@@ -81,9 +81,11 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
81 | "Writeback: %8lu kB\n" | 81 | "Writeback: %8lu kB\n" |
82 | "AnonPages: %8lu kB\n" | 82 | "AnonPages: %8lu kB\n" |
83 | "Mapped: %8lu kB\n" | 83 | "Mapped: %8lu kB\n" |
84 | "Shmem: %8lu kB\n" | ||
84 | "Slab: %8lu kB\n" | 85 | "Slab: %8lu kB\n" |
85 | "SReclaimable: %8lu kB\n" | 86 | "SReclaimable: %8lu kB\n" |
86 | "SUnreclaim: %8lu kB\n" | 87 | "SUnreclaim: %8lu kB\n" |
88 | "KernelStack: %8lu kB\n" | ||
87 | "PageTables: %8lu kB\n" | 89 | "PageTables: %8lu kB\n" |
88 | #ifdef CONFIG_QUICKLIST | 90 | #ifdef CONFIG_QUICKLIST |
89 | "Quicklists: %8lu kB\n" | 91 | "Quicklists: %8lu kB\n" |
@@ -124,10 +126,12 @@ static int meminfo_proc_show(struct seq_file *m, void *v) | |||
124 | K(global_page_state(NR_WRITEBACK)), | 126 | K(global_page_state(NR_WRITEBACK)), |
125 | K(global_page_state(NR_ANON_PAGES)), | 127 | K(global_page_state(NR_ANON_PAGES)), |
126 | K(global_page_state(NR_FILE_MAPPED)), | 128 | K(global_page_state(NR_FILE_MAPPED)), |
129 | K(global_page_state(NR_SHMEM)), | ||
127 | K(global_page_state(NR_SLAB_RECLAIMABLE) + | 130 | K(global_page_state(NR_SLAB_RECLAIMABLE) + |
128 | global_page_state(NR_SLAB_UNRECLAIMABLE)), | 131 | global_page_state(NR_SLAB_UNRECLAIMABLE)), |
129 | K(global_page_state(NR_SLAB_RECLAIMABLE)), | 132 | K(global_page_state(NR_SLAB_RECLAIMABLE)), |
130 | K(global_page_state(NR_SLAB_UNRECLAIMABLE)), | 133 | K(global_page_state(NR_SLAB_UNRECLAIMABLE)), |
134 | global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024, | ||
131 | K(global_page_state(NR_PAGETABLE)), | 135 | K(global_page_state(NR_PAGETABLE)), |
132 | #ifdef CONFIG_QUICKLIST | 136 | #ifdef CONFIG_QUICKLIST |
133 | K(quicklist_total_size()), | 137 | K(quicklist_total_size()), |
diff --git a/fs/proc/page.c b/fs/proc/page.c index 2707c6c7a20..2281c2cbfe2 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/compiler.h> | 2 | #include <linux/compiler.h> |
3 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
4 | #include <linux/init.h> | 4 | #include <linux/init.h> |
5 | #include <linux/ksm.h> | ||
5 | #include <linux/mm.h> | 6 | #include <linux/mm.h> |
6 | #include <linux/mmzone.h> | 7 | #include <linux/mmzone.h> |
7 | #include <linux/proc_fs.h> | 8 | #include <linux/proc_fs.h> |
@@ -95,6 +96,8 @@ static const struct file_operations proc_kpagecount_operations = { | |||
95 | #define KPF_UNEVICTABLE 18 | 96 | #define KPF_UNEVICTABLE 18 |
96 | #define KPF_NOPAGE 20 | 97 | #define KPF_NOPAGE 20 |
97 | 98 | ||
99 | #define KPF_KSM 21 | ||
100 | |||
98 | /* kernel hacking assistances | 101 | /* kernel hacking assistances |
99 | * WARNING: subject to change, never rely on them! | 102 | * WARNING: subject to change, never rely on them! |
100 | */ | 103 | */ |
@@ -137,6 +140,8 @@ static u64 get_uflags(struct page *page) | |||
137 | u |= 1 << KPF_MMAP; | 140 | u |= 1 << KPF_MMAP; |
138 | if (PageAnon(page)) | 141 | if (PageAnon(page)) |
139 | u |= 1 << KPF_ANON; | 142 | u |= 1 << KPF_ANON; |
143 | if (PageKsm(page)) | ||
144 | u |= 1 << KPF_KSM; | ||
140 | 145 | ||
141 | /* | 146 | /* |
142 | * compound pages: export both head/tail info | 147 | * compound pages: export both head/tail info |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 9bd8be1d235..59e98fea34a 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -465,6 +465,10 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, | |||
465 | return 0; | 465 | return 0; |
466 | } | 466 | } |
467 | 467 | ||
468 | #define CLEAR_REFS_ALL 1 | ||
469 | #define CLEAR_REFS_ANON 2 | ||
470 | #define CLEAR_REFS_MAPPED 3 | ||
471 | |||
468 | static ssize_t clear_refs_write(struct file *file, const char __user *buf, | 472 | static ssize_t clear_refs_write(struct file *file, const char __user *buf, |
469 | size_t count, loff_t *ppos) | 473 | size_t count, loff_t *ppos) |
470 | { | 474 | { |
@@ -472,13 +476,15 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf, | |||
472 | char buffer[PROC_NUMBUF], *end; | 476 | char buffer[PROC_NUMBUF], *end; |
473 | struct mm_struct *mm; | 477 | struct mm_struct *mm; |
474 | struct vm_area_struct *vma; | 478 | struct vm_area_struct *vma; |
479 | int type; | ||
475 | 480 | ||
476 | memset(buffer, 0, sizeof(buffer)); | 481 | memset(buffer, 0, sizeof(buffer)); |
477 | if (count > sizeof(buffer) - 1) | 482 | if (count > sizeof(buffer) - 1) |
478 | count = sizeof(buffer) - 1; | 483 | count = sizeof(buffer) - 1; |
479 | if (copy_from_user(buffer, buf, count)) | 484 | if (copy_from_user(buffer, buf, count)) |
480 | return -EFAULT; | 485 | return -EFAULT; |
481 | if (!simple_strtol(buffer, &end, 0)) | 486 | type = simple_strtol(buffer, &end, 0); |
487 | if (type < CLEAR_REFS_ALL || type > CLEAR_REFS_MAPPED) | ||
482 | return -EINVAL; | 488 | return -EINVAL; |
483 | if (*end == '\n') | 489 | if (*end == '\n') |
484 | end++; | 490 | end++; |
@@ -494,9 +500,23 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf, | |||
494 | down_read(&mm->mmap_sem); | 500 | down_read(&mm->mmap_sem); |
495 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | 501 | for (vma = mm->mmap; vma; vma = vma->vm_next) { |
496 | clear_refs_walk.private = vma; | 502 | clear_refs_walk.private = vma; |
497 | if (!is_vm_hugetlb_page(vma)) | 503 | if (is_vm_hugetlb_page(vma)) |
498 | walk_page_range(vma->vm_start, vma->vm_end, | 504 | continue; |
499 | &clear_refs_walk); | 505 | /* |
506 | * Writing 1 to /proc/pid/clear_refs affects all pages. | ||
507 | * | ||
508 | * Writing 2 to /proc/pid/clear_refs only affects | ||
509 | * Anonymous pages. | ||
510 | * | ||
511 | * Writing 3 to /proc/pid/clear_refs only affects file | ||
512 | * mapped pages. | ||
513 | */ | ||
514 | if (type == CLEAR_REFS_ANON && vma->vm_file) | ||
515 | continue; | ||
516 | if (type == CLEAR_REFS_MAPPED && !vma->vm_file) | ||
517 | continue; | ||
518 | walk_page_range(vma->vm_start, vma->vm_end, | ||
519 | &clear_refs_walk); | ||
500 | } | 520 | } |
501 | flush_tlb_mm(mm); | 521 | flush_tlb_mm(mm); |
502 | up_read(&mm->mmap_sem); | 522 | up_read(&mm->mmap_sem); |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 38f7bd559f3..39b49c42a7e 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
@@ -1839,7 +1839,7 @@ EXPORT_SYMBOL(dquot_commit_info); | |||
1839 | /* | 1839 | /* |
1840 | * Definitions of diskquota operations. | 1840 | * Definitions of diskquota operations. |
1841 | */ | 1841 | */ |
1842 | struct dquot_operations dquot_operations = { | 1842 | const struct dquot_operations dquot_operations = { |
1843 | .initialize = dquot_initialize, | 1843 | .initialize = dquot_initialize, |
1844 | .drop = dquot_drop, | 1844 | .drop = dquot_drop, |
1845 | .alloc_space = dquot_alloc_space, | 1845 | .alloc_space = dquot_alloc_space, |
@@ -2461,7 +2461,7 @@ out: | |||
2461 | } | 2461 | } |
2462 | EXPORT_SYMBOL(vfs_set_dqinfo); | 2462 | EXPORT_SYMBOL(vfs_set_dqinfo); |
2463 | 2463 | ||
2464 | struct quotactl_ops vfs_quotactl_ops = { | 2464 | const struct quotactl_ops vfs_quotactl_ops = { |
2465 | .quota_on = vfs_quota_on, | 2465 | .quota_on = vfs_quota_on, |
2466 | .quota_off = vfs_quota_off, | 2466 | .quota_off = vfs_quota_off, |
2467 | .quota_sync = vfs_quota_sync, | 2467 | .quota_sync = vfs_quota_sync, |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 7adea74d6a8..f0ad05f3802 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -612,7 +612,7 @@ static int reiserfs_mark_dquot_dirty(struct dquot *); | |||
612 | static int reiserfs_write_info(struct super_block *, int); | 612 | static int reiserfs_write_info(struct super_block *, int); |
613 | static int reiserfs_quota_on(struct super_block *, int, int, char *, int); | 613 | static int reiserfs_quota_on(struct super_block *, int, int, char *, int); |
614 | 614 | ||
615 | static struct dquot_operations reiserfs_quota_operations = { | 615 | static const struct dquot_operations reiserfs_quota_operations = { |
616 | .initialize = dquot_initialize, | 616 | .initialize = dquot_initialize, |
617 | .drop = dquot_drop, | 617 | .drop = dquot_drop, |
618 | .alloc_space = dquot_alloc_space, | 618 | .alloc_space = dquot_alloc_space, |
@@ -629,7 +629,7 @@ static struct dquot_operations reiserfs_quota_operations = { | |||
629 | .destroy_dquot = dquot_destroy, | 629 | .destroy_dquot = dquot_destroy, |
630 | }; | 630 | }; |
631 | 631 | ||
632 | static struct quotactl_ops reiserfs_qctl_operations = { | 632 | static const struct quotactl_ops reiserfs_qctl_operations = { |
633 | .quota_on = reiserfs_quota_on, | 633 | .quota_on = reiserfs_quota_on, |
634 | .quota_off = vfs_quota_off, | 634 | .quota_off = vfs_quota_off, |
635 | .quota_sync = vfs_quota_sync, | 635 | .quota_sync = vfs_quota_sync, |
diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 4ab3c03d8f9..47f132df0c3 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c | |||
@@ -284,7 +284,7 @@ static const struct file_operations romfs_dir_operations = { | |||
284 | .readdir = romfs_readdir, | 284 | .readdir = romfs_readdir, |
285 | }; | 285 | }; |
286 | 286 | ||
287 | static struct inode_operations romfs_dir_inode_operations = { | 287 | static const struct inode_operations romfs_dir_inode_operations = { |
288 | .lookup = romfs_lookup, | 288 | .lookup = romfs_lookup, |
289 | }; | 289 | }; |
290 | 290 | ||
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index cb5fc57e370..6c197ef53ad 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include "squashfs.h" | 44 | #include "squashfs.h" |
45 | 45 | ||
46 | static struct file_system_type squashfs_fs_type; | 46 | static struct file_system_type squashfs_fs_type; |
47 | static struct super_operations squashfs_super_ops; | 47 | static const struct super_operations squashfs_super_ops; |
48 | 48 | ||
49 | static int supported_squashfs_filesystem(short major, short minor, short comp) | 49 | static int supported_squashfs_filesystem(short major, short minor, short comp) |
50 | { | 50 | { |
@@ -444,7 +444,7 @@ static struct file_system_type squashfs_fs_type = { | |||
444 | .fs_flags = FS_REQUIRES_DEV | 444 | .fs_flags = FS_REQUIRES_DEV |
445 | }; | 445 | }; |
446 | 446 | ||
447 | static struct super_operations squashfs_super_ops = { | 447 | static const struct super_operations squashfs_super_ops = { |
448 | .alloc_inode = squashfs_alloc_inode, | 448 | .alloc_inode = squashfs_alloc_inode, |
449 | .destroy_inode = squashfs_destroy_inode, | 449 | .destroy_inode = squashfs_destroy_inode, |
450 | .statfs = squashfs_statfs, | 450 | .statfs = squashfs_statfs, |
diff --git a/fs/super.c b/fs/super.c index b03fea8fbfb..0e7207b9815 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -54,7 +54,7 @@ DEFINE_SPINLOCK(sb_lock); | |||
54 | static struct super_block *alloc_super(struct file_system_type *type) | 54 | static struct super_block *alloc_super(struct file_system_type *type) |
55 | { | 55 | { |
56 | struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); | 56 | struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); |
57 | static struct super_operations default_op; | 57 | static const struct super_operations default_op; |
58 | 58 | ||
59 | if (s) { | 59 | if (s) { |
60 | if (security_sb_alloc(s)) { | 60 | if (security_sb_alloc(s)) { |
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 7998cc37825..195830f4756 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c | |||
@@ -79,7 +79,7 @@ enum { | |||
79 | }; | 79 | }; |
80 | 80 | ||
81 | static const struct inode_operations none_inode_operations; | 81 | static const struct inode_operations none_inode_operations; |
82 | static struct address_space_operations none_address_operations; | 82 | static const struct address_space_operations none_address_operations; |
83 | static const struct file_operations none_file_operations; | 83 | static const struct file_operations none_file_operations; |
84 | 84 | ||
85 | /** | 85 | /** |
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/linux-2.6/xfs_quotaops.c index cb6e2cca214..9e41f91aa26 100644 --- a/fs/xfs/linux-2.6/xfs_quotaops.c +++ b/fs/xfs/linux-2.6/xfs_quotaops.c | |||
@@ -150,7 +150,7 @@ xfs_fs_set_xquota( | |||
150 | return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq); | 150 | return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq); |
151 | } | 151 | } |
152 | 152 | ||
153 | struct quotactl_ops xfs_quotactl_operations = { | 153 | const struct quotactl_ops xfs_quotactl_operations = { |
154 | .quota_sync = xfs_fs_quota_sync, | 154 | .quota_sync = xfs_fs_quota_sync, |
155 | .get_xstate = xfs_fs_get_xstate, | 155 | .get_xstate = xfs_fs_get_xstate, |
156 | .set_xstate = xfs_fs_set_xstate, | 156 | .set_xstate = xfs_fs_set_xstate, |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 5d7c60ac77b..bdd41c8c342 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -67,7 +67,7 @@ | |||
67 | #include <linux/freezer.h> | 67 | #include <linux/freezer.h> |
68 | #include <linux/parser.h> | 68 | #include <linux/parser.h> |
69 | 69 | ||
70 | static struct super_operations xfs_super_operations; | 70 | static const struct super_operations xfs_super_operations; |
71 | static kmem_zone_t *xfs_ioend_zone; | 71 | static kmem_zone_t *xfs_ioend_zone; |
72 | mempool_t *xfs_ioend_pool; | 72 | mempool_t *xfs_ioend_pool; |
73 | 73 | ||
@@ -1536,7 +1536,7 @@ xfs_fs_get_sb( | |||
1536 | mnt); | 1536 | mnt); |
1537 | } | 1537 | } |
1538 | 1538 | ||
1539 | static struct super_operations xfs_super_operations = { | 1539 | static const struct super_operations xfs_super_operations = { |
1540 | .alloc_inode = xfs_fs_alloc_inode, | 1540 | .alloc_inode = xfs_fs_alloc_inode, |
1541 | .destroy_inode = xfs_fs_destroy_inode, | 1541 | .destroy_inode = xfs_fs_destroy_inode, |
1542 | .write_inode = xfs_fs_write_inode, | 1542 | .write_inode = xfs_fs_write_inode, |
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 5a2ea3a2178..18175ebd58e 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h | |||
@@ -93,7 +93,7 @@ extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); | |||
93 | 93 | ||
94 | extern const struct export_operations xfs_export_operations; | 94 | extern const struct export_operations xfs_export_operations; |
95 | extern struct xattr_handler *xfs_xattr_handlers[]; | 95 | extern struct xattr_handler *xfs_xattr_handlers[]; |
96 | extern struct quotactl_ops xfs_quotactl_operations; | 96 | extern const struct quotactl_ops xfs_quotactl_operations; |
97 | 97 | ||
98 | #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) | 98 | #define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) |
99 | 99 | ||
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h index c4ea51b55dc..f52ac276277 100644 --- a/fs/xfs/xfs_fs.h +++ b/fs/xfs/xfs_fs.h | |||
@@ -117,7 +117,7 @@ struct getbmapx { | |||
117 | #define BMV_IF_VALID \ | 117 | #define BMV_IF_VALID \ |
118 | (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|BMV_IF_DELALLOC) | 118 | (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC|BMV_IF_DELALLOC) |
119 | 119 | ||
120 | /* bmv_oflags values - returned for for each non-header segment */ | 120 | /* bmv_oflags values - returned for each non-header segment */ |
121 | #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ | 121 | #define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ |
122 | #define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ | 122 | #define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ |
123 | #define BMV_OF_LAST 0x4 /* segment is the last in the file */ | 123 | #define BMV_OF_LAST 0x4 /* segment is the last in the file */ |