diff options
author | Michal Marek <mmarek@suse.cz> | 2010-08-04 07:59:13 -0400 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2010-08-04 07:59:13 -0400 |
commit | 772320e84588dcbe1600ffb83e5f328f2209ac2a (patch) | |
tree | a7de21b79340aeaa17c58126f6b801b82c77b53a /mm/shmem.c | |
parent | 1ce53adf13a54375d2a5c7cdbe341b2558389615 (diff) | |
parent | 9fe6206f400646a2322096b56c59891d530e8d51 (diff) |
Merge commit 'v2.6.35' into kbuild/kbuild
Conflicts:
arch/powerpc/Makefile
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 143 |
1 files changed, 99 insertions, 44 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index eef4ebea5158..f65f84062db5 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -433,8 +433,6 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long | |||
433 | 433 | ||
434 | spin_unlock(&info->lock); | 434 | spin_unlock(&info->lock); |
435 | page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping)); | 435 | page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping)); |
436 | if (page) | ||
437 | set_page_private(page, 0); | ||
438 | spin_lock(&info->lock); | 436 | spin_lock(&info->lock); |
439 | 437 | ||
440 | if (!page) { | 438 | if (!page) { |
@@ -729,10 +727,11 @@ done2: | |||
729 | if (inode->i_mapping->nrpages && (info->flags & SHMEM_PAGEIN)) { | 727 | if (inode->i_mapping->nrpages && (info->flags & SHMEM_PAGEIN)) { |
730 | /* | 728 | /* |
731 | * Call truncate_inode_pages again: racing shmem_unuse_inode | 729 | * Call truncate_inode_pages again: racing shmem_unuse_inode |
732 | * may have swizzled a page in from swap since vmtruncate or | 730 | * may have swizzled a page in from swap since |
733 | * generic_delete_inode did it, before we lowered next_index. | 731 | * truncate_pagecache or generic_delete_inode did it, before we |
734 | * Also, though shmem_getpage checks i_size before adding to | 732 | * lowered next_index. Also, though shmem_getpage checks |
735 | * cache, no recheck after: so fix the narrow window there too. | 733 | * i_size before adding to cache, no recheck after: so fix the |
734 | * narrow window there too. | ||
736 | * | 735 | * |
737 | * Recalling truncate_inode_pages_range and unmap_mapping_range | 736 | * Recalling truncate_inode_pages_range and unmap_mapping_range |
738 | * every time for punch_hole (which never got a chance to clear | 737 | * every time for punch_hole (which never got a chance to clear |
@@ -762,19 +761,17 @@ done2: | |||
762 | } | 761 | } |
763 | } | 762 | } |
764 | 763 | ||
765 | static void shmem_truncate(struct inode *inode) | ||
766 | { | ||
767 | shmem_truncate_range(inode, inode->i_size, (loff_t)-1); | ||
768 | } | ||
769 | |||
770 | static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | 764 | static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) |
771 | { | 765 | { |
772 | struct inode *inode = dentry->d_inode; | 766 | struct inode *inode = dentry->d_inode; |
773 | struct page *page = NULL; | 767 | loff_t newsize = attr->ia_size; |
774 | int error; | 768 | int error; |
775 | 769 | ||
776 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { | 770 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE) |
777 | if (attr->ia_size < inode->i_size) { | 771 | && newsize != inode->i_size) { |
772 | struct page *page = NULL; | ||
773 | |||
774 | if (newsize < inode->i_size) { | ||
778 | /* | 775 | /* |
779 | * If truncating down to a partial page, then | 776 | * If truncating down to a partial page, then |
780 | * if that page is already allocated, hold it | 777 | * if that page is already allocated, hold it |
@@ -782,9 +779,9 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
782 | * truncate_partial_page cannnot miss it were | 779 | * truncate_partial_page cannnot miss it were |
783 | * it assigned to swap. | 780 | * it assigned to swap. |
784 | */ | 781 | */ |
785 | if (attr->ia_size & (PAGE_CACHE_SIZE-1)) { | 782 | if (newsize & (PAGE_CACHE_SIZE-1)) { |
786 | (void) shmem_getpage(inode, | 783 | (void) shmem_getpage(inode, |
787 | attr->ia_size>>PAGE_CACHE_SHIFT, | 784 | newsize >> PAGE_CACHE_SHIFT, |
788 | &page, SGP_READ, NULL); | 785 | &page, SGP_READ, NULL); |
789 | if (page) | 786 | if (page) |
790 | unlock_page(page); | 787 | unlock_page(page); |
@@ -796,24 +793,29 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
796 | * if it's being fully truncated to zero-length: the | 793 | * if it's being fully truncated to zero-length: the |
797 | * nrpages check is efficient enough in that case. | 794 | * nrpages check is efficient enough in that case. |
798 | */ | 795 | */ |
799 | if (attr->ia_size) { | 796 | if (newsize) { |
800 | struct shmem_inode_info *info = SHMEM_I(inode); | 797 | struct shmem_inode_info *info = SHMEM_I(inode); |
801 | spin_lock(&info->lock); | 798 | spin_lock(&info->lock); |
802 | info->flags &= ~SHMEM_PAGEIN; | 799 | info->flags &= ~SHMEM_PAGEIN; |
803 | spin_unlock(&info->lock); | 800 | spin_unlock(&info->lock); |
804 | } | 801 | } |
805 | } | 802 | } |
803 | |||
804 | error = simple_setsize(inode, newsize); | ||
805 | if (page) | ||
806 | page_cache_release(page); | ||
807 | if (error) | ||
808 | return error; | ||
809 | shmem_truncate_range(inode, newsize, (loff_t)-1); | ||
806 | } | 810 | } |
807 | 811 | ||
808 | error = inode_change_ok(inode, attr); | 812 | error = inode_change_ok(inode, attr); |
809 | if (!error) | 813 | if (!error) |
810 | error = inode_setattr(inode, attr); | 814 | generic_setattr(inode, attr); |
811 | #ifdef CONFIG_TMPFS_POSIX_ACL | 815 | #ifdef CONFIG_TMPFS_POSIX_ACL |
812 | if (!error && (attr->ia_valid & ATTR_MODE)) | 816 | if (!error && (attr->ia_valid & ATTR_MODE)) |
813 | error = generic_acl_chmod(inode); | 817 | error = generic_acl_chmod(inode); |
814 | #endif | 818 | #endif |
815 | if (page) | ||
816 | page_cache_release(page); | ||
817 | return error; | 819 | return error; |
818 | } | 820 | } |
819 | 821 | ||
@@ -821,11 +823,11 @@ static void shmem_delete_inode(struct inode *inode) | |||
821 | { | 823 | { |
822 | struct shmem_inode_info *info = SHMEM_I(inode); | 824 | struct shmem_inode_info *info = SHMEM_I(inode); |
823 | 825 | ||
824 | if (inode->i_op->truncate == shmem_truncate) { | 826 | if (inode->i_mapping->a_ops == &shmem_aops) { |
825 | truncate_inode_pages(inode->i_mapping, 0); | 827 | truncate_inode_pages(inode->i_mapping, 0); |
826 | shmem_unacct_size(info->flags, inode->i_size); | 828 | shmem_unacct_size(info->flags, inode->i_size); |
827 | inode->i_size = 0; | 829 | inode->i_size = 0; |
828 | shmem_truncate(inode); | 830 | shmem_truncate_range(inode, 0, (loff_t)-1); |
829 | if (!list_empty(&info->swaplist)) { | 831 | if (!list_empty(&info->swaplist)) { |
830 | mutex_lock(&shmem_swaplist_mutex); | 832 | mutex_lock(&shmem_swaplist_mutex); |
831 | list_del_init(&info->swaplist); | 833 | list_del_init(&info->swaplist); |
@@ -1545,8 +1547,8 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma) | |||
1545 | return 0; | 1547 | return 0; |
1546 | } | 1548 | } |
1547 | 1549 | ||
1548 | static struct inode *shmem_get_inode(struct super_block *sb, int mode, | 1550 | static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir, |
1549 | dev_t dev, unsigned long flags) | 1551 | int mode, dev_t dev, unsigned long flags) |
1550 | { | 1552 | { |
1551 | struct inode *inode; | 1553 | struct inode *inode; |
1552 | struct shmem_inode_info *info; | 1554 | struct shmem_inode_info *info; |
@@ -1557,9 +1559,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, int mode, | |||
1557 | 1559 | ||
1558 | inode = new_inode(sb); | 1560 | inode = new_inode(sb); |
1559 | if (inode) { | 1561 | if (inode) { |
1560 | inode->i_mode = mode; | 1562 | inode_init_owner(inode, dir, mode); |
1561 | inode->i_uid = current_fsuid(); | ||
1562 | inode->i_gid = current_fsgid(); | ||
1563 | inode->i_blocks = 0; | 1563 | inode->i_blocks = 0; |
1564 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; | 1564 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; |
1565 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 1565 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
@@ -1814,7 +1814,7 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1814 | struct inode *inode; | 1814 | struct inode *inode; |
1815 | int error = -ENOSPC; | 1815 | int error = -ENOSPC; |
1816 | 1816 | ||
1817 | inode = shmem_get_inode(dir->i_sb, mode, dev, VM_NORESERVE); | 1817 | inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE); |
1818 | if (inode) { | 1818 | if (inode) { |
1819 | error = security_inode_init_security(inode, dir, NULL, NULL, | 1819 | error = security_inode_init_security(inode, dir, NULL, NULL, |
1820 | NULL); | 1820 | NULL); |
@@ -1833,11 +1833,6 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1833 | #else | 1833 | #else |
1834 | error = 0; | 1834 | error = 0; |
1835 | #endif | 1835 | #endif |
1836 | if (dir->i_mode & S_ISGID) { | ||
1837 | inode->i_gid = dir->i_gid; | ||
1838 | if (S_ISDIR(mode)) | ||
1839 | inode->i_mode |= S_ISGID; | ||
1840 | } | ||
1841 | dir->i_size += BOGO_DIRENT_SIZE; | 1836 | dir->i_size += BOGO_DIRENT_SIZE; |
1842 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; | 1837 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; |
1843 | d_instantiate(dentry, inode); | 1838 | d_instantiate(dentry, inode); |
@@ -1957,7 +1952,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s | |||
1957 | if (len > PAGE_CACHE_SIZE) | 1952 | if (len > PAGE_CACHE_SIZE) |
1958 | return -ENAMETOOLONG; | 1953 | return -ENAMETOOLONG; |
1959 | 1954 | ||
1960 | inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE); | 1955 | inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE); |
1961 | if (!inode) | 1956 | if (!inode) |
1962 | return -ENOSPC; | 1957 | return -ENOSPC; |
1963 | 1958 | ||
@@ -1992,8 +1987,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s | |||
1992 | unlock_page(page); | 1987 | unlock_page(page); |
1993 | page_cache_release(page); | 1988 | page_cache_release(page); |
1994 | } | 1989 | } |
1995 | if (dir->i_mode & S_ISGID) | ||
1996 | inode->i_gid = dir->i_gid; | ||
1997 | dir->i_size += BOGO_DIRENT_SIZE; | 1990 | dir->i_size += BOGO_DIRENT_SIZE; |
1998 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; | 1991 | dir->i_ctime = dir->i_mtime = CURRENT_TIME; |
1999 | d_instantiate(dentry, inode); | 1992 | d_instantiate(dentry, inode); |
@@ -2033,7 +2026,6 @@ static const struct inode_operations shmem_symlink_inline_operations = { | |||
2033 | }; | 2026 | }; |
2034 | 2027 | ||
2035 | static const struct inode_operations shmem_symlink_inode_operations = { | 2028 | static const struct inode_operations shmem_symlink_inode_operations = { |
2036 | .truncate = shmem_truncate, | ||
2037 | .readlink = generic_readlink, | 2029 | .readlink = generic_readlink, |
2038 | .follow_link = shmem_follow_link, | 2030 | .follow_link = shmem_follow_link, |
2039 | .put_link = shmem_put_link, | 2031 | .put_link = shmem_put_link, |
@@ -2071,14 +2063,14 @@ static int shmem_xattr_security_set(struct dentry *dentry, const char *name, | |||
2071 | size, flags); | 2063 | size, flags); |
2072 | } | 2064 | } |
2073 | 2065 | ||
2074 | static struct xattr_handler shmem_xattr_security_handler = { | 2066 | static const struct xattr_handler shmem_xattr_security_handler = { |
2075 | .prefix = XATTR_SECURITY_PREFIX, | 2067 | .prefix = XATTR_SECURITY_PREFIX, |
2076 | .list = shmem_xattr_security_list, | 2068 | .list = shmem_xattr_security_list, |
2077 | .get = shmem_xattr_security_get, | 2069 | .get = shmem_xattr_security_get, |
2078 | .set = shmem_xattr_security_set, | 2070 | .set = shmem_xattr_security_set, |
2079 | }; | 2071 | }; |
2080 | 2072 | ||
2081 | static struct xattr_handler *shmem_xattr_handlers[] = { | 2073 | static const struct xattr_handler *shmem_xattr_handlers[] = { |
2082 | &generic_acl_access_handler, | 2074 | &generic_acl_access_handler, |
2083 | &generic_acl_default_handler, | 2075 | &generic_acl_default_handler, |
2084 | &shmem_xattr_security_handler, | 2076 | &shmem_xattr_security_handler, |
@@ -2366,7 +2358,7 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) | |||
2366 | sb->s_flags |= MS_POSIXACL; | 2358 | sb->s_flags |= MS_POSIXACL; |
2367 | #endif | 2359 | #endif |
2368 | 2360 | ||
2369 | inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE); | 2361 | inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE); |
2370 | if (!inode) | 2362 | if (!inode) |
2371 | goto failed; | 2363 | goto failed; |
2372 | inode->i_uid = sbinfo->uid; | 2364 | inode->i_uid = sbinfo->uid; |
@@ -2444,14 +2436,13 @@ static const struct file_operations shmem_file_operations = { | |||
2444 | .write = do_sync_write, | 2436 | .write = do_sync_write, |
2445 | .aio_read = shmem_file_aio_read, | 2437 | .aio_read = shmem_file_aio_read, |
2446 | .aio_write = generic_file_aio_write, | 2438 | .aio_write = generic_file_aio_write, |
2447 | .fsync = simple_sync_file, | 2439 | .fsync = noop_fsync, |
2448 | .splice_read = generic_file_splice_read, | 2440 | .splice_read = generic_file_splice_read, |
2449 | .splice_write = generic_file_splice_write, | 2441 | .splice_write = generic_file_splice_write, |
2450 | #endif | 2442 | #endif |
2451 | }; | 2443 | }; |
2452 | 2444 | ||
2453 | static const struct inode_operations shmem_inode_operations = { | 2445 | static const struct inode_operations shmem_inode_operations = { |
2454 | .truncate = shmem_truncate, | ||
2455 | .setattr = shmem_notify_change, | 2446 | .setattr = shmem_notify_change, |
2456 | .truncate_range = shmem_truncate_range, | 2447 | .truncate_range = shmem_truncate_range, |
2457 | #ifdef CONFIG_TMPFS_POSIX_ACL | 2448 | #ifdef CONFIG_TMPFS_POSIX_ACL |
@@ -2570,6 +2561,45 @@ out4: | |||
2570 | return error; | 2561 | return error; |
2571 | } | 2562 | } |
2572 | 2563 | ||
2564 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | ||
2565 | /** | ||
2566 | * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file | ||
2567 | * @inode: the inode to be searched | ||
2568 | * @pgoff: the offset to be searched | ||
2569 | * @pagep: the pointer for the found page to be stored | ||
2570 | * @ent: the pointer for the found swap entry to be stored | ||
2571 | * | ||
2572 | * If a page is found, refcount of it is incremented. Callers should handle | ||
2573 | * these refcount. | ||
2574 | */ | ||
2575 | void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff, | ||
2576 | struct page **pagep, swp_entry_t *ent) | ||
2577 | { | ||
2578 | swp_entry_t entry = { .val = 0 }, *ptr; | ||
2579 | struct page *page = NULL; | ||
2580 | struct shmem_inode_info *info = SHMEM_I(inode); | ||
2581 | |||
2582 | if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) | ||
2583 | goto out; | ||
2584 | |||
2585 | spin_lock(&info->lock); | ||
2586 | ptr = shmem_swp_entry(info, pgoff, NULL); | ||
2587 | #ifdef CONFIG_SWAP | ||
2588 | if (ptr && ptr->val) { | ||
2589 | entry.val = ptr->val; | ||
2590 | page = find_get_page(&swapper_space, entry.val); | ||
2591 | } else | ||
2592 | #endif | ||
2593 | page = find_get_page(inode->i_mapping, pgoff); | ||
2594 | if (ptr) | ||
2595 | shmem_swp_unmap(ptr); | ||
2596 | spin_unlock(&info->lock); | ||
2597 | out: | ||
2598 | *pagep = page; | ||
2599 | *ent = entry; | ||
2600 | } | ||
2601 | #endif | ||
2602 | |||
2573 | #else /* !CONFIG_SHMEM */ | 2603 | #else /* !CONFIG_SHMEM */ |
2574 | 2604 | ||
2575 | /* | 2605 | /* |
@@ -2609,9 +2639,34 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user) | |||
2609 | return 0; | 2639 | return 0; |
2610 | } | 2640 | } |
2611 | 2641 | ||
2642 | #ifdef CONFIG_CGROUP_MEM_RES_CTLR | ||
2643 | /** | ||
2644 | * mem_cgroup_get_shmem_target - find a page or entry assigned to the shmem file | ||
2645 | * @inode: the inode to be searched | ||
2646 | * @pgoff: the offset to be searched | ||
2647 | * @pagep: the pointer for the found page to be stored | ||
2648 | * @ent: the pointer for the found swap entry to be stored | ||
2649 | * | ||
2650 | * If a page is found, refcount of it is incremented. Callers should handle | ||
2651 | * these refcount. | ||
2652 | */ | ||
2653 | void mem_cgroup_get_shmem_target(struct inode *inode, pgoff_t pgoff, | ||
2654 | struct page **pagep, swp_entry_t *ent) | ||
2655 | { | ||
2656 | struct page *page = NULL; | ||
2657 | |||
2658 | if ((pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) | ||
2659 | goto out; | ||
2660 | page = find_get_page(inode->i_mapping, pgoff); | ||
2661 | out: | ||
2662 | *pagep = page; | ||
2663 | *ent = (swp_entry_t){ .val = 0 }; | ||
2664 | } | ||
2665 | #endif | ||
2666 | |||
2612 | #define shmem_vm_ops generic_file_vm_ops | 2667 | #define shmem_vm_ops generic_file_vm_ops |
2613 | #define shmem_file_operations ramfs_file_operations | 2668 | #define shmem_file_operations ramfs_file_operations |
2614 | #define shmem_get_inode(sb, mode, dev, flags) ramfs_get_inode(sb, mode, dev) | 2669 | #define shmem_get_inode(sb, dir, mode, dev, flags) ramfs_get_inode(sb, dir, mode, dev) |
2615 | #define shmem_acct_size(flags, size) 0 | 2670 | #define shmem_acct_size(flags, size) 0 |
2616 | #define shmem_unacct_size(flags, size) do {} while (0) | 2671 | #define shmem_unacct_size(flags, size) do {} while (0) |
2617 | #define SHMEM_MAX_BYTES MAX_LFS_FILESIZE | 2672 | #define SHMEM_MAX_BYTES MAX_LFS_FILESIZE |
@@ -2655,7 +2710,7 @@ struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags | |||
2655 | path.mnt = mntget(shm_mnt); | 2710 | path.mnt = mntget(shm_mnt); |
2656 | 2711 | ||
2657 | error = -ENOSPC; | 2712 | error = -ENOSPC; |
2658 | inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags); | 2713 | inode = shmem_get_inode(root->d_sb, NULL, S_IFREG | S_IRWXUGO, 0, flags); |
2659 | if (!inode) | 2714 | if (!inode) |
2660 | goto put_dentry; | 2715 | goto put_dentry; |
2661 | 2716 | ||