diff options
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 69 |
1 files changed, 34 insertions, 35 deletions
diff --git a/mm/memory.c b/mm/memory.c index bc137751da7f..b7cb2e01705f 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1909,50 +1909,49 @@ EXPORT_SYMBOL(unmap_mapping_range); | |||
1909 | */ | 1909 | */ |
1910 | int vmtruncate(struct inode * inode, loff_t offset) | 1910 | int vmtruncate(struct inode * inode, loff_t offset) |
1911 | { | 1911 | { |
1912 | struct address_space *mapping = inode->i_mapping; | 1912 | if (inode->i_size < offset) { |
1913 | unsigned long limit; | 1913 | unsigned long limit; |
1914 | |||
1915 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
1916 | if (limit != RLIM_INFINITY && offset > limit) | ||
1917 | goto out_sig; | ||
1918 | if (offset > inode->i_sb->s_maxbytes) | ||
1919 | goto out_big; | ||
1920 | i_size_write(inode, offset); | ||
1921 | } else { | ||
1922 | struct address_space *mapping = inode->i_mapping; | ||
1914 | 1923 | ||
1915 | if (inode->i_size < offset) | 1924 | /* |
1916 | goto do_expand; | 1925 | * truncation of in-use swapfiles is disallowed - it would |
1917 | /* | 1926 | * cause subsequent swapout to scribble on the now-freed |
1918 | * truncation of in-use swapfiles is disallowed - it would cause | 1927 | * blocks. |
1919 | * subsequent swapout to scribble on the now-freed blocks. | 1928 | */ |
1920 | */ | 1929 | if (IS_SWAPFILE(inode)) |
1921 | if (IS_SWAPFILE(inode)) | 1930 | return -ETXTBSY; |
1922 | goto out_busy; | 1931 | i_size_write(inode, offset); |
1923 | i_size_write(inode, offset); | 1932 | |
1933 | /* | ||
1934 | * unmap_mapping_range is called twice, first simply for | ||
1935 | * efficiency so that truncate_inode_pages does fewer | ||
1936 | * single-page unmaps. However after this first call, and | ||
1937 | * before truncate_inode_pages finishes, it is possible for | ||
1938 | * private pages to be COWed, which remain after | ||
1939 | * truncate_inode_pages finishes, hence the second | ||
1940 | * unmap_mapping_range call must be made for correctness. | ||
1941 | */ | ||
1942 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
1943 | truncate_inode_pages(mapping, offset); | ||
1944 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
1945 | } | ||
1924 | 1946 | ||
1925 | /* | ||
1926 | * unmap_mapping_range is called twice, first simply for efficiency | ||
1927 | * so that truncate_inode_pages does fewer single-page unmaps. However | ||
1928 | * after this first call, and before truncate_inode_pages finishes, | ||
1929 | * it is possible for private pages to be COWed, which remain after | ||
1930 | * truncate_inode_pages finishes, hence the second unmap_mapping_range | ||
1931 | * call must be made for correctness. | ||
1932 | */ | ||
1933 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
1934 | truncate_inode_pages(mapping, offset); | ||
1935 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
1936 | goto out_truncate; | ||
1937 | |||
1938 | do_expand: | ||
1939 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | ||
1940 | if (limit != RLIM_INFINITY && offset > limit) | ||
1941 | goto out_sig; | ||
1942 | if (offset > inode->i_sb->s_maxbytes) | ||
1943 | goto out_big; | ||
1944 | i_size_write(inode, offset); | ||
1945 | |||
1946 | out_truncate: | ||
1947 | if (inode->i_op && inode->i_op->truncate) | 1947 | if (inode->i_op && inode->i_op->truncate) |
1948 | inode->i_op->truncate(inode); | 1948 | inode->i_op->truncate(inode); |
1949 | return 0; | 1949 | return 0; |
1950 | |||
1950 | out_sig: | 1951 | out_sig: |
1951 | send_sig(SIGXFSZ, current, 0); | 1952 | send_sig(SIGXFSZ, current, 0); |
1952 | out_big: | 1953 | out_big: |
1953 | return -EFBIG; | 1954 | return -EFBIG; |
1954 | out_busy: | ||
1955 | return -ETXTBSY; | ||
1956 | } | 1955 | } |
1957 | EXPORT_SYMBOL(vmtruncate); | 1956 | EXPORT_SYMBOL(vmtruncate); |
1958 | 1957 | ||