// SPDX-License-Identifier: GPL-2.0-only /* * linux/fs/nfs/file.c * * Copyright (C) 1992 Rick Sladkey * * Changes Copyright (C) 1994 by Florian La Roche * - Do not copy data too often around in the kernel. * - In nfs_file_read the return value of kmalloc wasn't checked. * - Put in a better version of read look-ahead buffering. Original idea * and implementation by Wai S Kok elekokws@ee.nus.sg. * * Expire cache on write to a file by Wai S Kok (Oct 1994). * * Total rewrite of read side for new NFS buffer cache.. Linus. * * nfs regular file handling functions
*/
/** * nfs_revalidate_file_size - Revalidate the file size * @inode: pointer to inode struct * @filp: pointer to struct file * * Revalidates the file length. This is basically a wrapper around * nfs_revalidate_inode() that takes into account the fact that we may * have cached writes (in which case we don't care about the server's * idea of what the file length is), or O_DIRECT (in which case we * shouldn't trust the cache).
*/ staticint nfs_revalidate_file_size(struct inode *inode, struct file *filp)
{ struct nfs_server *server = NFS_SERVER(inode);
if (filp->f_flags & O_DIRECT) goto force_reval; if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_SIZE)) goto force_reval; return 0;
force_reval: return __nfs_revalidate_inode(server, inode);
}
/* * Flush all dirty pages, and check for write errors.
*/ staticint
nfs_file_flush(struct file *file, fl_owner_t id)
{ struct inode *inode = file_inode(file);
errseq_t since;
dprintk("NFS: flush(%pD2)\n", file);
nfs_inc_stats(inode, NFSIOS_VFSFLUSH); if ((file->f_mode & FMODE_WRITE) == 0) return 0;
/* Flush writes to the server and return any errors */
since = filemap_sample_wb_err(file->f_mapping);
nfs_wb_all(inode); return filemap_check_wb_err(file->f_mapping, since);
}
dprintk("NFS: splice_read(%pD2, %zu@%llu)\n", in, len, *ppos);
result = nfs_start_io_read(inode); if (result) return result;
result = nfs_revalidate_mapping(inode, in->f_mapping); if (!result) {
result = filemap_splice_read(in, ppos, pipe, len, flags); if (result > 0)
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result);
}
nfs_end_io_read(inode); return result;
}
EXPORT_SYMBOL_GPL(nfs_file_splice_read);
int
nfs_file_mmap_prepare(struct vm_area_desc *desc)
{ struct file *file = desc->file; struct inode *inode = file_inode(file); int status;
dprintk("NFS: mmap(%pD2)\n", file);
/* Note: generic_file_mmap_prepare() returns ENOSYS on nommu systems * so we call that before revalidating the mapping
*/
status = generic_file_mmap_prepare(desc); if (!status) {
desc->vm_ops = &nfs_file_vm_ops;
status = nfs_revalidate_mapping(inode, file->f_mapping);
} return status;
}
EXPORT_SYMBOL_GPL(nfs_file_mmap_prepare);
/* * Flush any dirty pages for this process, and check for write errors. * The return status from this call provides a reliable indication of * whether any write errors occurred for this process.
*/ staticint
nfs_file_fsync_commit(struct file *file, int datasync)
{ struct inode *inode = file_inode(file); int ret, ret2;
/* * Decide whether a read/modify/write cycle may be more efficient * then a modify/write/read cycle when writing to a page in the * page cache. * * Some pNFS layout drivers can only read/write at a certain block * granularity like all block devices and therefore we must perform * read/modify/write whenever a page hasn't read yet and the data * to be written there is not aligned to a block boundary and/or * smaller than the block size. * * The modify/write/read cycle may occur if a page is read before * being completely filled by the writer. In this situation, the * page must be completely written to stable storage on the server * before it can be refilled by reading in the page from the server. * This can lead to expensive, small, FILE_SYNC mode writes being * done. * * It may be more efficient to read the page first if the file is * open for reading in addition to writing, the page is not marked * as Uptodate, it is not dirty or waiting to be committed, * indicating that it was previously allocated and then modified, * that there were valid bytes of data in that range of the file, * and that the new data won't completely replace the old data in * that range of the file.
*/ staticbool nfs_folio_is_full_write(struct folio *folio, loff_t pos, unsignedint len)
{ unsignedint pglen = nfs_folio_length(folio); unsignedint offset = offset_in_folio(folio, pos); unsignedint end = offset + len;
return !pglen || (end >= pglen && !offset);
}
staticbool nfs_want_read_modify_write(struct file *file, struct folio *folio,
loff_t pos, unsignedint len)
{ /* * Up-to-date pages, those with ongoing or full-page write * don't need read/modify/write
*/ if (folio_test_uptodate(folio) || folio_test_private(folio) ||
nfs_folio_is_full_write(folio, pos, len)) returnfalse;
if (pnfs_ld_read_whole_page(file_inode(file))) returntrue; /* Open for reading too? */ if (file->f_mode & FMODE_READ) returntrue; returnfalse;
}
/* * This does the "real" work of the write. We must allocate and lock the * page to be sent back to the generic routine, which then copies the * data from user space. * * If the writer ends up delaying the write, the writer needs to * increment the page use counts until he is done with the page.
*/ staticint nfs_write_begin(conststruct kiocb *iocb, struct address_space *mapping,
loff_t pos, unsigned len, struct folio **foliop, void **fsdata)
{
fgf_t fgp = FGP_WRITEBEGIN; struct folio *folio; struct file *file = iocb->ki_filp; int once_thru = 0; int ret;
/* * Zero any uninitialised parts of the page, and then mark the page * as up to date if it turns out that we're extending the file.
*/ if (!folio_test_uptodate(folio)) {
size_t fsize = folio_size(folio); unsigned pglen = nfs_folio_length(folio); unsigned end = offset + copied;
status = nfs_update_folio(file, folio, offset, copied);
folio_unlock(folio);
folio_put(folio);
if (status < 0) return status;
NFS_I(mapping->host)->write_io += copied;
if (nfs_ctx_key_to_expire(ctx, mapping->host))
nfs_wb_all(mapping->host);
return copied;
}
/* * Partially or wholly invalidate a page * - Release the private state associated with a page if undergoing complete * page invalidation * - Called if either PG_private or PG_fscache is set on the page * - Caller holds page lock
*/ staticvoid nfs_invalidate_folio(struct folio *folio, size_t offset,
size_t length)
{ struct inode *inode = folio->mapping->host;
dfprintk(PAGECACHE, "NFS: invalidate_folio(%lu, %zu, %zu)\n",
folio->index, offset, length);
/* Cancel any unstarted writes on this page */ if (offset != 0 || length < folio_size(folio))
nfs_wb_folio(inode, folio); else
nfs_wb_folio_cancel(inode, folio);
folio_wait_private_2(folio); /* [DEPRECATED] */
trace_nfs_invalidate_folio(inode, folio_pos(folio) + offset, length);
}
/* * Attempt to release the private state associated with a folio * - Called if either private or fscache flags are set on the folio * - Caller holds folio lock * - Return true (may release folio) or false (may not)
*/ staticbool nfs_release_folio(struct folio *folio, gfp_t gfp)
{
dfprintk(PAGECACHE, "NFS: release_folio(%p)\n", folio);
/* If the private flag is set, then the folio is not freeable */ if (folio_test_private(folio)) { if ((current_gfp_context(gfp) & GFP_KERNEL) != GFP_KERNEL ||
current_is_kswapd() || current_is_kcompactd()) returnfalse; if (nfs_wb_folio(folio->mapping->host, folio) < 0) returnfalse;
} return nfs_fscache_release_folio(folio, gfp);
}
/* * Check if an unstable folio is currently being committed and * if so, have the VM treat it as if the folio is under writeback * so it will not block due to folios that will shortly be freeable.
*/
nfsi = NFS_I(mapping->host); if (atomic_read(&nfsi->commit_info.rpcs_out)) {
*writeback = true; return;
}
/* * If the private flag is set, then the folio is not freeable * and as the inode is not being committed, it's not going to * be cleaned in the near future so treat it as dirty
*/ if (folio_test_private(folio))
*dirty = true;
}
/* * Attempt to clear the private state associated with a page when an error * occurs that requires the cached contents of an inode to be written back or * destroyed * - Called if either PG_private or fscache is set on the page * - Caller holds page lock * - Return 0 if successful, -error otherwise
*/ staticint nfs_launder_folio(struct folio *folio)
{ struct inode *inode = folio->mapping->host; int ret;
/* * Notification that a PTE pointing to an NFS page is about to be made * writable, implying that someone is about to modify the page through a * shared-writable mapping
*/ static vm_fault_t nfs_vm_page_mkwrite(struct vm_fault *vmf)
{ struct file *filp = vmf->vma->vm_file; struct inode *inode = file_inode(filp); unsigned pagelen;
vm_fault_t ret = VM_FAULT_NOPAGE; struct address_space *mapping; struct folio *folio = page_folio(vmf->page);
/* make sure the cache has finished storing the page */ if (folio_test_private_2(folio) && /* [DEPRECATED] */
folio_wait_private_2_killable(folio) < 0) {
ret = VM_FAULT_RETRY; goto out;
}
if (IS_SWAPFILE(inode)) goto out_swapfile; /* * O_APPEND implies that we must revalidate the file length.
*/ if (iocb->ki_flags & IOCB_APPEND || iocb->ki_pos > i_size_read(inode)) {
result = nfs_revalidate_file_size(inode, file); if (result) return result;
}
nfs_clear_invalid_mapping(file->f_mapping);
since = filemap_sample_wb_err(file->f_mapping);
error = nfs_start_io_write(inode); if (error) return error;
result = generic_write_checks(iocb, from); if (result > 0)
result = generic_perform_write(iocb, from);
nfs_end_io_write(inode); if (result <= 0) goto out;
written = result;
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written);
if (mntflags & NFS_MOUNT_WRITE_EAGER) {
result = filemap_fdatawrite_range(file->f_mapping,
iocb->ki_pos - written,
iocb->ki_pos - 1); if (result < 0) goto out;
} if (mntflags & NFS_MOUNT_WRITE_WAIT) {
filemap_fdatawait_range(file->f_mapping,
iocb->ki_pos - written,
iocb->ki_pos - 1);
}
result = generic_write_sync(iocb, written); if (result < 0) return result;
out: /* Return error values */
error = filemap_check_wb_err(file->f_mapping, since); switch (error) { default: break; case -EDQUOT: case -EFBIG: case -ENOSPC:
nfs_wb_all(inode);
error = file_check_and_advance_wb_err(file); if (error < 0)
result = error;
} return result;
out_swapfile:
printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); return -ETXTBSY;
}
EXPORT_SYMBOL_GPL(nfs_file_write);
staticint
do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{ struct inode *inode = filp->f_mapping->host; int status = 0; unsignedint saved_type = fl->c.flc_type;
/* Try local locking first */
posix_test_lock(filp, fl); if (fl->c.flc_type != F_UNLCK) { /* found a conflict */ goto out;
}
fl->c.flc_type = saved_type;
if (nfs_have_read_or_write_delegation(inode)) goto out_noconflict;
staticint
do_unlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{ struct inode *inode = filp->f_mapping->host; struct nfs_lock_context *l_ctx; int status;
/* * Flush all pending writes before doing anything * with locks..
*/
nfs_wb_all(inode);
l_ctx = nfs_get_lock_context(nfs_file_open_context(filp)); if (!IS_ERR(l_ctx)) {
status = nfs_iocounter_wait(l_ctx);
nfs_put_lock_context(l_ctx); /* NOTE: special case * If we're signalled while cleaning up locks on process exit, we * still need to complete the unlock.
*/ if (status < 0 && !(fl->c.flc_flags & FL_CLOSE)) return status;
}
/* * Use local locking if mounted with "-onolock" or with appropriate * "-olocal_lock="
*/ if (!is_local)
status = NFS_PROTO(inode)->lock(filp, cmd, fl); else
status = locks_lock_file_wait(filp, fl); return status;
}
staticint
do_setlk(struct file *filp, int cmd, struct file_lock *fl, int is_local)
{ struct inode *inode = filp->f_mapping->host; int status;
/* * Flush all pending writes before doing anything * with locks..
*/
status = nfs_sync_mapping(filp->f_mapping); if (status != 0) goto out;
/* * Use local locking if mounted with "-onolock" or with appropriate * "-olocal_lock="
*/ if (!is_local)
status = NFS_PROTO(inode)->lock(filp, cmd, fl); else
status = locks_lock_file_wait(filp, fl); if (status < 0) goto out;
/* * Invalidate cache to prevent missing any changes. If * the file is mapped, clear the page cache as well so * those mappings will be loaded. * * This makes locking act as a cache coherency point.
*/
nfs_sync_mapping(filp->f_mapping); if (!nfs_have_read_or_write_delegation(inode)) {
nfs_zap_caches(inode); if (mapping_mapped(filp->f_mapping))
nfs_revalidate_mapping(inode, filp->f_mapping);
}
out: return status;
}
/* * Lock a (portion of) a file
*/ int nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
{ struct inode *inode = filp->f_mapping->host; int ret = -ENOLCK; int is_local = 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.