Skip to content

Commit 407e9c6

Browse files
committed
vfs: move the generic write and copy checks out of mm
The generic write check helpers also don't have much to do with the page cache, so move them to the vfs. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
1 parent 1b2c54d commit 407e9c6

3 files changed

Lines changed: 143 additions & 146 deletions

File tree

fs/read_write.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,6 +1701,59 @@ static ssize_t do_copy_file_range(struct file *file_in, loff_t pos_in,
17011701
flags);
17021702
}
17031703

1704+
/*
1705+
* Performs necessary checks before doing a file copy
1706+
*
1707+
* Can adjust amount of bytes to copy via @req_count argument.
1708+
* Returns appropriate error code that caller should return or
1709+
* zero in case the copy should be allowed.
1710+
*/
1711+
static int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
1712+
struct file *file_out, loff_t pos_out,
1713+
size_t *req_count, unsigned int flags)
1714+
{
1715+
struct inode *inode_in = file_inode(file_in);
1716+
struct inode *inode_out = file_inode(file_out);
1717+
uint64_t count = *req_count;
1718+
loff_t size_in;
1719+
int ret;
1720+
1721+
ret = generic_file_rw_checks(file_in, file_out);
1722+
if (ret)
1723+
return ret;
1724+
1725+
/* Don't touch certain kinds of inodes */
1726+
if (IS_IMMUTABLE(inode_out))
1727+
return -EPERM;
1728+
1729+
if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
1730+
return -ETXTBSY;
1731+
1732+
/* Ensure offsets don't wrap. */
1733+
if (pos_in + count < pos_in || pos_out + count < pos_out)
1734+
return -EOVERFLOW;
1735+
1736+
/* Shorten the copy to EOF */
1737+
size_in = i_size_read(inode_in);
1738+
if (pos_in >= size_in)
1739+
count = 0;
1740+
else
1741+
count = min(count, size_in - (uint64_t)pos_in);
1742+
1743+
ret = generic_write_check_limits(file_out, pos_out, &count);
1744+
if (ret)
1745+
return ret;
1746+
1747+
/* Don't allow overlapped copying within the same file. */
1748+
if (inode_in == inode_out &&
1749+
pos_out + count > pos_in &&
1750+
pos_out < pos_in + count)
1751+
return -EINVAL;
1752+
1753+
*req_count = count;
1754+
return 0;
1755+
}
1756+
17041757
/*
17051758
* copy_file_range() differs from regular file read and write in that it
17061759
* specifically allows return partial success. When it does so is up to
@@ -1832,3 +1885,93 @@ SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
18321885
out2:
18331886
return ret;
18341887
}
1888+
1889+
/*
1890+
* Don't operate on ranges the page cache doesn't support, and don't exceed the
1891+
* LFS limits. If pos is under the limit it becomes a short access. If it
1892+
* exceeds the limit we return -EFBIG.
1893+
*/
1894+
int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count)
1895+
{
1896+
struct inode *inode = file->f_mapping->host;
1897+
loff_t max_size = inode->i_sb->s_maxbytes;
1898+
loff_t limit = rlimit(RLIMIT_FSIZE);
1899+
1900+
if (limit != RLIM_INFINITY) {
1901+
if (pos >= limit) {
1902+
send_sig(SIGXFSZ, current, 0);
1903+
return -EFBIG;
1904+
}
1905+
*count = min(*count, limit - pos);
1906+
}
1907+
1908+
if (!(file->f_flags & O_LARGEFILE))
1909+
max_size = MAX_NON_LFS;
1910+
1911+
if (unlikely(pos >= max_size))
1912+
return -EFBIG;
1913+
1914+
*count = min(*count, max_size - pos);
1915+
1916+
return 0;
1917+
}
1918+
1919+
/*
1920+
* Performs necessary checks before doing a write
1921+
*
1922+
* Can adjust writing position or amount of bytes to write.
1923+
* Returns appropriate error code that caller should return or
1924+
* zero in case that write should be allowed.
1925+
*/
1926+
ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
1927+
{
1928+
struct file *file = iocb->ki_filp;
1929+
struct inode *inode = file->f_mapping->host;
1930+
loff_t count;
1931+
int ret;
1932+
1933+
if (IS_SWAPFILE(inode))
1934+
return -ETXTBSY;
1935+
1936+
if (!iov_iter_count(from))
1937+
return 0;
1938+
1939+
/* FIXME: this is for backwards compatibility with 2.4 */
1940+
if (iocb->ki_flags & IOCB_APPEND)
1941+
iocb->ki_pos = i_size_read(inode);
1942+
1943+
if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
1944+
return -EINVAL;
1945+
1946+
count = iov_iter_count(from);
1947+
ret = generic_write_check_limits(file, iocb->ki_pos, &count);
1948+
if (ret)
1949+
return ret;
1950+
1951+
iov_iter_truncate(from, count);
1952+
return iov_iter_count(from);
1953+
}
1954+
EXPORT_SYMBOL(generic_write_checks);
1955+
1956+
/*
1957+
* Performs common checks before doing a file copy/clone
1958+
* from @file_in to @file_out.
1959+
*/
1960+
int generic_file_rw_checks(struct file *file_in, struct file *file_out)
1961+
{
1962+
struct inode *inode_in = file_inode(file_in);
1963+
struct inode *inode_out = file_inode(file_out);
1964+
1965+
/* Don't copy dirs, pipes, sockets... */
1966+
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
1967+
return -EISDIR;
1968+
if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
1969+
return -EINVAL;
1970+
1971+
if (!(file_in->f_mode & FMODE_READ) ||
1972+
!(file_out->f_mode & FMODE_WRITE) ||
1973+
(file_out->f_flags & O_APPEND))
1974+
return -EBADF;
1975+
1976+
return 0;
1977+
}

include/linux/fs.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,9 +3012,6 @@ extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *);
30123012
extern int generic_write_check_limits(struct file *file, loff_t pos,
30133013
loff_t *count);
30143014
extern int generic_file_rw_checks(struct file *file_in, struct file *file_out);
3015-
extern int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
3016-
struct file *file_out, loff_t pos_out,
3017-
size_t *count, unsigned int flags);
30183015
extern ssize_t generic_file_buffered_read(struct kiocb *iocb,
30193016
struct iov_iter *to, ssize_t already_read);
30203017
extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *);

mm/filemap.c

Lines changed: 0 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -3093,149 +3093,6 @@ struct page *read_cache_page_gfp(struct address_space *mapping,
30933093
}
30943094
EXPORT_SYMBOL(read_cache_page_gfp);
30953095

3096-
/*
3097-
* Don't operate on ranges the page cache doesn't support, and don't exceed the
3098-
* LFS limits. If pos is under the limit it becomes a short access. If it
3099-
* exceeds the limit we return -EFBIG.
3100-
*/
3101-
int generic_write_check_limits(struct file *file, loff_t pos, loff_t *count)
3102-
{
3103-
struct inode *inode = file->f_mapping->host;
3104-
loff_t max_size = inode->i_sb->s_maxbytes;
3105-
loff_t limit = rlimit(RLIMIT_FSIZE);
3106-
3107-
if (limit != RLIM_INFINITY) {
3108-
if (pos >= limit) {
3109-
send_sig(SIGXFSZ, current, 0);
3110-
return -EFBIG;
3111-
}
3112-
*count = min(*count, limit - pos);
3113-
}
3114-
3115-
if (!(file->f_flags & O_LARGEFILE))
3116-
max_size = MAX_NON_LFS;
3117-
3118-
if (unlikely(pos >= max_size))
3119-
return -EFBIG;
3120-
3121-
*count = min(*count, max_size - pos);
3122-
3123-
return 0;
3124-
}
3125-
3126-
/*
3127-
* Performs necessary checks before doing a write
3128-
*
3129-
* Can adjust writing position or amount of bytes to write.
3130-
* Returns appropriate error code that caller should return or
3131-
* zero in case that write should be allowed.
3132-
*/
3133-
inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from)
3134-
{
3135-
struct file *file = iocb->ki_filp;
3136-
struct inode *inode = file->f_mapping->host;
3137-
loff_t count;
3138-
int ret;
3139-
3140-
if (IS_SWAPFILE(inode))
3141-
return -ETXTBSY;
3142-
3143-
if (!iov_iter_count(from))
3144-
return 0;
3145-
3146-
/* FIXME: this is for backwards compatibility with 2.4 */
3147-
if (iocb->ki_flags & IOCB_APPEND)
3148-
iocb->ki_pos = i_size_read(inode);
3149-
3150-
if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
3151-
return -EINVAL;
3152-
3153-
count = iov_iter_count(from);
3154-
ret = generic_write_check_limits(file, iocb->ki_pos, &count);
3155-
if (ret)
3156-
return ret;
3157-
3158-
iov_iter_truncate(from, count);
3159-
return iov_iter_count(from);
3160-
}
3161-
EXPORT_SYMBOL(generic_write_checks);
3162-
3163-
/*
3164-
* Performs common checks before doing a file copy/clone
3165-
* from @file_in to @file_out.
3166-
*/
3167-
int generic_file_rw_checks(struct file *file_in, struct file *file_out)
3168-
{
3169-
struct inode *inode_in = file_inode(file_in);
3170-
struct inode *inode_out = file_inode(file_out);
3171-
3172-
/* Don't copy dirs, pipes, sockets... */
3173-
if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
3174-
return -EISDIR;
3175-
if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
3176-
return -EINVAL;
3177-
3178-
if (!(file_in->f_mode & FMODE_READ) ||
3179-
!(file_out->f_mode & FMODE_WRITE) ||
3180-
(file_out->f_flags & O_APPEND))
3181-
return -EBADF;
3182-
3183-
return 0;
3184-
}
3185-
3186-
/*
3187-
* Performs necessary checks before doing a file copy
3188-
*
3189-
* Can adjust amount of bytes to copy via @req_count argument.
3190-
* Returns appropriate error code that caller should return or
3191-
* zero in case the copy should be allowed.
3192-
*/
3193-
int generic_copy_file_checks(struct file *file_in, loff_t pos_in,
3194-
struct file *file_out, loff_t pos_out,
3195-
size_t *req_count, unsigned int flags)
3196-
{
3197-
struct inode *inode_in = file_inode(file_in);
3198-
struct inode *inode_out = file_inode(file_out);
3199-
uint64_t count = *req_count;
3200-
loff_t size_in;
3201-
int ret;
3202-
3203-
ret = generic_file_rw_checks(file_in, file_out);
3204-
if (ret)
3205-
return ret;
3206-
3207-
/* Don't touch certain kinds of inodes */
3208-
if (IS_IMMUTABLE(inode_out))
3209-
return -EPERM;
3210-
3211-
if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out))
3212-
return -ETXTBSY;
3213-
3214-
/* Ensure offsets don't wrap. */
3215-
if (pos_in + count < pos_in || pos_out + count < pos_out)
3216-
return -EOVERFLOW;
3217-
3218-
/* Shorten the copy to EOF */
3219-
size_in = i_size_read(inode_in);
3220-
if (pos_in >= size_in)
3221-
count = 0;
3222-
else
3223-
count = min(count, size_in - (uint64_t)pos_in);
3224-
3225-
ret = generic_write_check_limits(file_out, pos_out, &count);
3226-
if (ret)
3227-
return ret;
3228-
3229-
/* Don't allow overlapped copying within the same file. */
3230-
if (inode_in == inode_out &&
3231-
pos_out + count > pos_in &&
3232-
pos_out < pos_in + count)
3233-
return -EINVAL;
3234-
3235-
*req_count = count;
3236-
return 0;
3237-
}
3238-
32393096
int pagecache_write_begin(struct file *file, struct address_space *mapping,
32403097
loff_t pos, unsigned len, unsigned flags,
32413098
struct page **pagep, void **fsdata)

0 commit comments

Comments
 (0)