概述
posix_fadvise是linux上对文件进行预取的系统调用,其中第四个参数int advice为预取的方式,主要有以下几种:
POSIX_FADV_NORMAL 无特别建议 重置预读大小为默认值
POSIX_FADV_SEQUENTIAL 将要进行顺序操作 设预读大小为默认值的2 倍
POSIX_FADV_RANDOM 将要进行随机操作 将预读大小清零(禁止预读)
POSIX_FADV_NOREUSE 指定的数据将只访问一次 (暂无动作)
POSIX_FADV_WILLNEED 指定的数据即将被访问 立即预读数据到page cache
POSIX_FADV_DONTNEED 指定的数据近期不会被访问 立即从page cache 中丢弃数据
其中,POSIX_FADV_NORMAL、POSIX_FADV_SEQUENTIAL、POSIX_FADV_RANDOM 是用来调整预取窗口的大小,POSIX_FADV_WILLNEED则可以将指定范围的磁盘文件读入到page cache中,POSIX_FADV_DONTNEED则将指定的磁盘文件中数据从page cache中换出。
在kernel源码的mm/fadvise.c中,如下所示:
SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
{
struct file *file = fget(fd);
struct address_space *mapping;
struct backing_dev_info *bdi;
loff_t endbyte; /* inclusive */
pgoff_t start_index;
pgoff_t end_index;
unsigned long nrpages;
int ret = 0;
/* 判断由文件描述符获得的file指针是否有效 */
if (!file)
return -EBADF;
/* 判断是否是管道 */
if (S_ISFIFO(file->f_path.dentry->d_inode->i_mode)) {
ret = -ESPIPE;
goto out;
}
mapping = file->f_mapping;
if (!mapping || len < 0) {
ret = -EINVAL;
goto out;
}
if (mapping->a_ops->get_xip_mem) {
switch (advice) {
case POSIX_FADV_NORMAL:
case POSIX_FADV_RANDOM:
case POSIX_FADV_SEQUENTIAL:
case POSIX_FADV_WILLNEED:
case POSIX_FADV_NOREUSE:
case POSIX_FADV_DONTNEED:
/* no bad return value, but ignore advice */
break;
default:
ret = -EINVAL;
}
goto out;
}
/* Careful about overflows. Len == 0 means "as much as possible" */
endbyte = offset + len;
if (!len || endbyte < len)
endbyte = -1;
else
endbyte--; /* inclusive */
bdi = mapping->backing_dev_info;
switch (advice) {
case POSIX_FADV_NORMAL:
/* 将预取窗口调整为设备默认的大小 */
file->f_ra.ra_pages = bdi->ra_pages;
spin_lock(&file->f_lock);
file->f_mode &= ~FMODE_RANDOM;
spin_unlock(&file->f_lock);
break;
case POSIX_FADV_RANDOM:
/* 将文件的访问模式设为random即不做预取 */
spin_lock(&file->f_lock);
file->f_mode |= FMODE_RANDOM;
spin_unlock(&file->f_lock);
break;
case POSIX_FADV_SEQUENTIAL:
/* 将预取窗口设为默认值的2倍 */
file->f_ra.ra_pages = bdi->ra_pages * 2;
spin_lock(&file->f_lock);
file->f_mode &= ~FMODE_RANDOM;
spin_unlock(&file->f_lock);
break;
case POSIX_FADV_WILLNEED:
/* 强制读取文件指定范围内的数据 */
if (!mapping->a_ops->readpage) {
ret = -EINVAL;
break;
}
/* First and last PARTIAL page! */
/* 获得起始页、结束页的编号 */
start_index = offset >> PAGE_CACHE_SHIFT;
end_index = endbyte >> PAGE_CACHE_SHIFT;
/* Careful about overflow on the "+1" */
/* 计算需要读取的页数,并+1向上取整 */
nrpages = end_index - start_index + 1;
if (!nrpages)
nrpages = ~0UL;
/* 强制读取指定范围的数据 */
ret = force_page_cache_readahead(mapping, file,
start_index,
nrpages);
if (ret > 0)
ret = 0;
break;
case POSIX_FADV_NOREUSE:
/* 没有实现,no use 没用 */
break;
case POSIX_FADV_DONTNEED:
/* 将指定范围内的数据从page cache中换出 */
if (!bdi_write_congested(mapping->backing_dev_info))
filemap_flush(mapping);
/* First and last FULL page! */
/* 计算数据的起始页、结束页的编号 */
start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
end_index = (endbyte >> PAGE_CACHE_SHIFT);
if (end_index >= start_index)
/* 将指定页从page cache中换出*/
invalidate_mapping_pages(mapping, start_index,
end_index);
break;
default:
ret = -EINVAL;
}
out:
fput(file);
return ret;
}
最后
以上就是怕孤单电源为你收集整理的posix_fadvise源码分析的全部内容,希望文章能够帮你解决posix_fadvise源码分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复