cregit-Linux how code gets into the kernel

Release 4.11 fs/nfs/file.c

Directory: fs/nfs
/*
 *  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
 */

#include <linux/module.h>
#include <linux/time.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/gfp.h>
#include <linux/swap.h>

#include <linux/uaccess.h>

#include "delegation.h"
#include "internal.h"
#include "iostat.h"
#include "fscache.h"
#include "pnfs.h"

#include "nfstrace.h"


#define NFSDBG_FACILITY		NFSDBG_FILE


static const struct vm_operations_struct nfs_file_vm_ops;

/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE

# define IS_SWAPFILE(inode)	(0)
#endif


int nfs_check_flags(int flags) { if ((flags & (O_APPEND | O_DIRECT)) == (O_APPEND | O_DIRECT)) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton1648.48%133.33%
Matthew Wilcox927.27%133.33%
Linus Torvalds824.24%133.33%
Total33100.00%3100.00%

EXPORT_SYMBOL_GPL(nfs_check_flags); /* * Open file */
static int nfs_file_open(struct inode *inode, struct file *filp) { int res; dprintk("NFS: open file(%pD2)\n", filp); nfs_inc_stats(inode, NFSIOS_VFSOPEN); res = nfs_check_flags(filp->f_flags); if (res) return res; res = nfs_open(inode, filp); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust3049.18%330.00%
Chuck Lever1422.95%440.00%
Matthew Wilcox1016.39%110.00%
Andrew Morton69.84%110.00%
Al Viro11.64%110.00%
Total61100.00%10100.00%


int nfs_file_release(struct inode *inode, struct file *filp) { dprintk("NFS: release(%pD2)\n", filp); nfs_inc_stats(inode, NFSIOS_VFSRELEASE); nfs_file_clear_open_context(filp); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust1951.35%228.57%
Chuck Lever1232.43%228.57%
Anna Schumaker410.81%114.29%
Al Viro12.70%114.29%
Rakib Mullick12.70%114.29%
Total37100.00%7100.00%

EXPORT_SYMBOL_GPL(nfs_file_release); /** * nfs_revalidate_size - Revalidate the file size * @inode - pointer to inode struct * @file - 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). */
static int 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_REVAL_PAGECACHE)) goto force_reval; return 0; force_reval: return __nfs_revalidate_inode(server, inode); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust62100.00%4100.00%
Total62100.00%4100.00%


loff_t nfs_file_llseek(struct file *filp, loff_t offset, int whence) { dprintk("NFS: llseek file(%pD2, %lld, %d)\n", filp, offset, whence); /* * whence == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate * the cached file length */ if (whence != SEEK_SET && whence != SEEK_CUR) { struct inode *inode = filp->f_mapping->host; int retval = nfs_revalidate_file_size(inode, filp); if (retval < 0) return (loff_t)retval; } return generic_file_llseek(filp, offset, whence); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust6173.49%330.00%
Chuck Lever910.84%220.00%
Andrew Morton67.23%110.00%
Josef Bacik44.82%110.00%
Andi Kleen22.41%220.00%
Al Viro11.20%110.00%
Total83100.00%10100.00%

EXPORT_SYMBOL_GPL(nfs_file_llseek); /* * Flush all dirty pages, and check for write errors. */
static int nfs_file_flush(struct file *file, fl_owner_t id) { struct inode *inode = file_inode(file); 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 */ return vfs_fsync(file, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust2235.48%535.71%
Linus Torvalds (pre-git)1930.65%535.71%
Chuck Lever1219.35%214.29%
Al Viro69.68%17.14%
Miklos Szeredi34.84%17.14%
Total62100.00%14100.00%


ssize_t nfs_file_read(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = file_inode(iocb->ki_filp); ssize_t result; if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_read(iocb, to); dprintk("NFS: read(%pD2, %zu@%lu)\n", iocb->ki_filp, iov_iter_count(to), (unsigned long) iocb->ki_pos); nfs_start_io_read(inode); result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); if (!result) { result = generic_file_read_iter(iocb, to); if (result > 0) nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); } nfs_end_io_read(inode); return result; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5241.60%630.00%
Trond Myklebust2923.20%420.00%
Al Viro2016.00%525.00%
Chuck Lever1814.40%210.00%
Benjamin LaHaise32.40%15.00%
Rakib Mullick21.60%15.00%
Badari Pulavarty10.80%15.00%
Total125100.00%20100.00%

EXPORT_SYMBOL_GPL(nfs_file_read);
int nfs_file_mmap(struct file * file, struct vm_area_struct * vma) { struct inode *inode = file_inode(file); int status; dprintk("NFS: mmap(%pD2)\n", file); /* Note: generic_file_mmap() returns ENOSYS on nommu systems * so we call that before revalidating the mapping */ status = generic_file_mmap(file, vma); if (!status) { vma->vm_ops = &nfs_file_vm_ops; status = nfs_revalidate_mapping(inode, file->f_mapping); } return status; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4663.01%654.55%
Trond Myklebust2027.40%327.27%
Al Viro68.22%19.09%
Chuck Lever11.37%19.09%
Total73100.00%11100.00%

EXPORT_SYMBOL_GPL(nfs_file_mmap); /* * 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. * * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to * disk, but it retrieves and clears ctx->error after synching, despite * the two being set at the same time in nfs_context_set_write_error(). * This is because the former is used to notify the _next_ call to * nfs_file_write() that a write error occurred, and hence cause it to * fall back to doing a synchronous write. */
static int nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync) { struct nfs_open_context *ctx = nfs_file_open_context(file); struct inode *inode = file_inode(file); int have_error, do_resend, status; int ret = 0; dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync); nfs_inc_stats(inode, NFSIOS_VFSFSYNC); do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags); have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); status = nfs_commit_inode(inode, FLUSH_SYNC); have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); if (have_error) { ret = xchg(&ctx->error, 0); if (ret) goto out; } if (status < 0) { ret = status; goto out; } do_resend |= test_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags); if (do_resend) ret = -EAGAIN; out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust12368.72%527.78%
Linus Torvalds (pre-git)2513.97%422.22%
Chuck Lever105.59%316.67%
Al Viro63.35%15.56%
Josef Bacik63.35%15.56%
Bryan Schumaker42.23%15.56%
Junjiro R. Okajima31.68%15.56%
Andy Adamson10.56%15.56%
Christoph Hellwig10.56%15.56%
Total179100.00%18100.00%


int nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) { int ret; struct inode *inode = file_inode(file); trace_nfs_fsync_enter(inode); do { ret = filemap_write_and_wait_range(inode->i_mapping, start, end); if (ret != 0) break; ret = nfs_file_fsync_commit(file, start, end, datasync); if (!ret) ret = pnfs_sync_inode(inode, !!datasync); /* * If nfs_file_fsync_commit detected a server reboot, then * resend all dirty pages that might have been covered by * the NFS_CONTEXT_RESEND_WRITES flag */ start = 0; end = LLONG_MAX; } while (ret == -EAGAIN); trace_nfs_fsync_exit(inode, ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Bryan Schumaker4639.66%19.09%
Trond Myklebust4135.34%545.45%
Christoph Hellwig1613.79%19.09%
Andy Adamson86.90%19.09%
Al Viro32.59%19.09%
Linus Torvalds (pre-git)21.72%218.18%
Total116100.00%11100.00%

EXPORT_SYMBOL_GPL(nfs_file_fsync); /* * 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. * * 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. */
static int nfs_want_read_modify_write(struct file *file, struct page *page, loff_t pos, unsigned len) { unsigned int pglen = nfs_page_length(page); unsigned int offset = pos & (PAGE_SIZE - 1); unsigned int end = offset + len; if (pnfs_ld_read_whole_page(file->f_mapping->host)) { if (!PageUptodate(page)) return 1; return 0; } if ((file->f_mode & FMODE_READ) && /* open for read? */ !PageUptodate(page) && /* Uptodate? */ !PagePrivate(page) && /* i/o request already? */ pglen && /* valid bytes of file? */ (end < pglen || offset)) /* replace all valid bytes? */ return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Peter Staubach9376.86%133.33%
Christoph Hellwig2722.31%133.33%
Kirill A. Shutemov10.83%133.33%
Total121100.00%3100.00%

/* * 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. */
static int nfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { int ret; pgoff_t index = pos >> PAGE_SHIFT; struct page *page; int once_thru = 0; dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n", file, mapping->host->i_ino, len, (long long) pos); start: page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; ret = nfs_flush_incompatible(file, page); if (ret) { unlock_page(page); put_page(page); } else if (!once_thru && nfs_want_read_modify_write(file, page, pos, len)) { once_thru = 1; ret = nfs_readpage(file, page); put_page(page); if (!ret) goto start; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin7441.34%225.00%
Peter Staubach5430.17%112.50%
Linus Torvalds (pre-git)2513.97%225.00%
Chuck Lever2212.29%112.50%
Kirill A. Shutemov31.68%112.50%
Niels de Vos10.56%112.50%
Total179100.00%8100.00%


static int nfs_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) { unsigned offset = pos & (PAGE_SIZE - 1); struct nfs_open_context *ctx = nfs_file_open_context(file); int status; dfprintk(PAGECACHE, "NFS: write_end(%pD2(%lu), %u@%lld)\n", file, mapping->host->i_ino, len, (long long) pos); /* * 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 (!PageUptodate(page)) { unsigned pglen = nfs_page_length(page); unsigned end = offset + copied; if (pglen == 0) { zero_user_segments(page, 0, offset, end, PAGE_SIZE); SetPageUptodate(page); } else if (end >= pglen) { zero_user_segment(page, end, PAGE_SIZE); if (offset == 0) SetPageUptodate(page); } else zero_user_segment(page, pglen, PAGE_SIZE); } status = nfs_updatepage(file, page, offset, copied); unlock_page(page); put_page(page); if (status < 0) return status; NFS_I(mapping->host)->write_io += copied; if (nfs_ctx_key_to_expire(ctx, mapping->host)) { status = nfs_wb_all(mapping->host); if (status < 0) return status; } return copied; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust8734.94%18.33%
Andy Adamson4819.28%216.67%
Nicholas Piggin4216.87%18.33%
Linus Torvalds (pre-git)3313.25%216.67%
Chuck Lever2811.24%216.67%
Kirill A. Shutemov52.01%18.33%
Scott Mayhew41.61%18.33%
Niels de Vos10.40%18.33%
Al Viro10.40%18.33%
Total249100.00%12100.00%

/* * 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 */
static void nfs_invalidate_page(struct page *page, unsigned int offset, unsigned int length) { dfprintk(PAGECACHE, "NFS: invalidate_page(%p, %u, %u)\n", page, offset, length); if (offset != 0 || length < PAGE_SIZE) return; /* Cancel any unstarted writes on this page */ nfs_wb_page_cancel(page_file_mapping(page)->host, page); nfs_fscache_invalidate_page(page, page->mapping->host); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust3044.78%545.45%
Lukas Czerner1116.42%19.09%
David Howells1116.42%19.09%
Chuck Lever1014.93%19.09%
Mel Gorman34.48%19.09%
Kirill A. Shutemov11.49%19.09%
Neil Brown11.49%19.09%
Total67100.00%11100.00%

/* * Attempt to release the private state associated with a page * - Called if either PG_private or PG_fscache is set on the page * - Caller holds page lock * - Return true (may release page) or false (may not) */
static int nfs_release_page(struct page *page, gfp_t gfp) { dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); /* If PagePrivate() is set, then the page is not freeable */ if (PagePrivate(page)) return 0; return nfs_fscache_release_page(page, gfp); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust1842.86%360.00%
David Howells1535.71%120.00%
Chuck Lever921.43%120.00%
Total42100.00%5100.00%


static void nfs_check_dirty_writeback(struct page *page, bool *dirty, bool *writeback) { struct nfs_inode *nfsi; struct address_space *mapping = page_file_mapping(page); if (!mapping || PageSwapCache(page)) return; /* * Check if an unstable page is currently being committed and * if so, have the VM treat it as if the page is under writeback * so it will not block due to pages that will shortly be freeable. */ nfsi = NFS_I(mapping->host); if (atomic_read(&nfsi->commit_info.rpcs_out)) { *writeback = true; return; } /* * If PagePrivate() is set, then the page 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 (PagePrivate(page)) *dirty = true; }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman8495.45%150.00%
Trond Myklebust44.55%150.00%
Total88100.00%2100.00%

/* * 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 */
static int nfs_launder_page(struct page *page) { struct inode *inode = page_file_mapping(page)->host; struct nfs_inode *nfsi = NFS_I(inode); dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n", inode->i_ino, (long long)page_offset(page)); nfs_fscache_wait_on_page_write(nfsi, page); return nfs_wb_launder_page(inode, page); }

Contributors

PersonTokensPropCommitsCommitProp
Chuck Lever2942.65%114.29%
Trond Myklebust1826.47%342.86%
David Howells1725.00%114.29%
Mel Gorman34.41%114.29%
Peng Tao11.47%114.29%
Total68100.00%7100.00%


static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file, sector_t *span) { struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host); *span = sis->pages; return rpc_clnt_swap_activate(clnt); }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman3063.83%133.33%
Jeff Layton1736.17%266.67%
Total47100.00%3100.00%


static void nfs_swap_deactivate(struct file *file) { struct rpc_clnt *clnt = NFS_CLIENT(file->f_mapping->host); rpc_clnt_swap_deactivate(clnt); }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman2170.00%133.33%
Jeff Layton930.00%266.67%
Total30100.00%3100.00%

const struct address_space_operations nfs_file_aops = { .readpage = nfs_readpage, .readpages = nfs_readpages, .set_page_dirty = __set_page_dirty_nobuffers, .writepage = nfs_writepage, .writepages = nfs_writepages, .write_begin = nfs_write_begin, .write_end = nfs_write_end, .invalidatepage = nfs_invalidate_page, .releasepage = nfs_release_page, .direct_IO = nfs_direct_IO, #ifdef CONFIG_MIGRATION .migratepage = nfs_migrate_page, #endif .launder_page = nfs_launder_page, .is_dirty_writeback = nfs_check_dirty_writeback, .error_remove_page = generic_error_remove_page, .swap_activate = nfs_swap_activate, .swap_deactivate = nfs_swap_deactivate, }; /* * 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 int nfs_vm_page_mkwrite(struct vm_fault *vmf) { struct page *page = vmf->page; struct file *filp = vmf->vma->vm_file; struct inode *inode = file_inode(filp); unsigned pagelen; int ret = VM_FAULT_NOPAGE; struct address_space *mapping; dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n", filp, filp->f_mapping->host->i_ino, (long long)page_offset(page)); sb_start_pagefault(inode->i_sb); /* make sure the cache has finished storing the page */ nfs_fscache_wait_on_page_write(NFS_I(inode), page); wait_on_bit_action(&NFS_I(inode)->flags, NFS_INO_INVALIDATING, nfs_wait_bit_killable, TASK_KILLABLE); lock_page(page); mapping = page_file_mapping(page); if (mapping != inode->i_mapping) goto out_unlock; wait_on_page_writeback(page); pagelen = nfs_page_length(page); if (pagelen == 0) goto out_unlock; ret = VM_FAULT_LOCKED; if (nfs_flush_incompatible(filp, page) == 0 && nfs_updatepage(filp, page, 0, pagelen) == 0) goto out; ret = VM_FAULT_SIGBUS; out_unlock: unlock_page(page); out: sb_end_pagefault(inode->i_sb); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust13061.03%746.67%
Nicholas Piggin3014.08%213.33%
Chuck Lever2913.62%16.67%
David Howells104.69%16.67%
Al Viro83.76%16.67%
Mel Gorman31.41%16.67%
Dave Jiang20.94%16.67%
Niels de Vos10.47%16.67%
Total213100.00%15100.00%

static const struct vm_operations_struct nfs_file_vm_ops = { .fault = filemap_fault, .map_pages = filemap_map_pages, .page_mkwrite = nfs_vm_page_mkwrite, };
static int nfs_need_check_write(struct file *filp, struct inode *inode) { struct nfs_open_context *ctx; ctx = nfs_file_open_context(filp); if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags) || nfs_ctx_key_to_expire(ctx, inode)) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust4686.79%360.00%
Andy Adamson59.43%120.00%
Scott Mayhew23.77%120.00%
Total53100.00%5100.00%


ssize_t nfs_file_write(struct kiocb *iocb, struct iov_iter *from) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); unsigned long written = 0; ssize_t result; result = nfs_key_timeout_notify(file, inode); if (result) return result; if (iocb->ki_flags & IOCB_DIRECT) return nfs_file_direct_write(iocb, from); dprintk("NFS: write(%pD2, %zu@%Ld)\n", file, iov_iter_count(from), (long long) iocb->ki_pos); if (IS_SWAPFILE(inode)) goto out_swapfile; /* * O_APPEND implies that we must revalidate the file length. */ if (iocb->ki_flags & IOCB_APPEND) { result = nfs_revalidate_file_size(inode, file); if (result) goto out; } nfs_start_io_write(inode); result = generic_write_checks(iocb, from); if (result > 0) { current->backing_dev_info = inode_to_bdi(inode); result = generic_perform_write(file, from, iocb->ki_pos); current->backing_dev_info = NULL; } nfs_end_io_write(inode); if (result <= 0) goto out; result = generic_write_sync(iocb, result); if (result < 0) goto out; written = result; iocb->ki_pos += written; /* Return error values */ if (nfs_need_check_write(file, inode)) { int err = vfs_fsync(file, 0); if (err < 0) result = err; } nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); out: return result; out_swapfile: printk(KERN_INFO "NFS: attempt to write to active swap file!\n"); return -EBUSY; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust13046.10%1035.71%
Linus Torvalds (pre-git)8128.72%828.57%
Al Viro258.87%517.86%
Chuck Lever248.51%27.14%
Andy Adamson155.32%13.57%
Benjamin LaHaise51.77%13.57%
Badari Pulavarty20.71%13.57%
Total282100.00%28100.00%

EXPORT_SYMBOL_GPL(nfs_file_write);
static int do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) { struct inode *inode = filp->f_mapping->host; int status = 0; unsigned int saved_type = fl->fl_type; /* Try local locking first */ posix_test_lock(filp, fl); if (fl->fl_type != F_UNLCK) { /* found a conflict */ goto out; } fl->fl_type = saved_type; if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) goto out_noconflict; if (is_local) goto out_noconflict; status = NFS_PROTO(inode)->lock(filp, cmd, fl); out: return status; out_noconflict: fl->fl_type = F_UNLCK; goto out; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust9673.85%337.50%
Sergey Vlasov1410.77%112.50%
J. Bruce Fields96.92%112.50%
Bryan Schumaker64.62%112.50%
Suresh Jayaraman43.08%112.50%
Andy Adamson10.77%112.50%
Total130100.00%8100.00%


static int 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.. */ vfs_fsync(filp, 0); 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); if (status < 0) return status; } /* NOTE: special case * If we're signalled while cleaning up locks on process exit, we * still need to complete the unlock. */ /* * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust12095.24%466.67%
Suresh Jayaraman53.97%116.67%
Jeff Layton10.79%116.67%
Total126100.00%6100.00%


static int 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; /* * Revalidate the cache if the server has time stamps granular * enough to detect subsecond changes. Otherwise, clear the * cache to prevent missing any changes. * * This makes locking act as a cache coherency point. */ nfs_sync_mapping(filp->f_mapping); if (!NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) nfs_zap_mapping(inode, filp->f_mapping); out: return status; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust11787.97%660.00%
Bryan Schumaker64.51%110.00%
Suresh Jayaraman53.76%110.00%
Ricardo Labiaga43.01%110.00%
Jeff Layton10.75%110.00%
Total133100.00%10100.00%

/* * 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; dprintk("NFS: lock(%pD2, t=%x, fl=%x, r=%lld:%lld)\n", filp, fl->fl_type, fl->fl_flags, (long long)fl->fl_start, (long long)fl->fl_end); nfs_inc_stats(inode, NFSIOS_VFSLOCK); /* No mandatory locks over NFS */ if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) goto out_err; if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FCNTL) is_local = 1; if (NFS_PROTO(inode)->lock_check_bounds != NULL) { ret = NFS_PROTO(inode)->lock_check_bounds(fl); if (ret < 0) goto out_err; } if (IS_GETLK(cmd)) ret = do_getlk(filp, cmd, fl, is_local); else if (fl->fl_type == F_UNLCK) ret = do_unlk(filp, cmd, fl, is_local); else ret = do_setlk(filp, cmd, fl, is_local); out_err: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust8742.44%420.00%
Linus Torvalds (pre-git)6833.17%630.00%
Suresh Jayaraman2612.68%15.00%
Chuck Lever73.41%210.00%
ASANO Masahiro62.93%15.00%
Andrew Morton41.95%210.00%
Pavel Emelyanov31.46%15.00%
Linus Torvalds31.46%210.00%
Al Viro10.49%15.00%
Total205100.00%20100.00%

EXPORT_SYMBOL_GPL(nfs_lock); /* * Lock a (portion of) a file */
int nfs_flock(struct file *filp, int cmd, struct file_lock *fl) { struct inode *inode = filp->f_mapping->host; int is_local = 0; dprintk("NFS: flock(%pD2, t=%x, fl=%x)\n", filp, fl->fl_type, fl->fl_flags); if (!(fl->fl_flags & FL_FLOCK)) return -ENOLCK; /* * The NFSv4 protocol doesn't support LOCK_MAND, which is not part of * any standard. In principle we might be able to support LOCK_MAND * on NFSv2/3 since NLMv3/4 support DOS share modes, but for now the * NFS code is not set up for it. */ if (fl->fl_type & LOCK_MAND) return -EINVAL; if (NFS_SERVER(inode)->flags & NFS_MOUNT_LOCAL_FLOCK) is_local = 1; /* We're simulating flock() locks using posix locks on the server */ if (fl->fl_type == F_UNLCK) return do_unlk(filp, cmd, fl, is_local); return do_setlk(filp, cmd, fl, is_local); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust6148.80%327.27%
Suresh Jayaraman3528.00%19.09%
Jeff Layton1310.40%19.09%
Linus Torvalds (pre-git)129.60%327.27%
Andrew Morton21.60%19.09%
Al Viro10.80%19.09%
Linus Torvalds10.80%19.09%
Total125100.00%11100.00%

EXPORT_SYMBOL_GPL(nfs_flock); const struct file_operations nfs_file_operations = { .llseek = nfs_file_llseek, .read_iter = nfs_file_read, .write_iter = nfs_file_write, .mmap = nfs_file_mmap, .open = nfs_file_open, .flush = nfs_file_flush, .release = nfs_file_release, .fsync = nfs_file_fsync, .lock = nfs_lock, .flock = nfs_flock, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .check_flags = nfs_check_flags, .setlease = simple_nosetlease, }; EXPORT_SYMBOL_GPL(nfs_file_operations);

Overall Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust141342.51%6435.56%
Linus Torvalds (pre-git)42512.79%2614.44%
Chuck Lever2487.46%126.67%
Mel Gorman1594.78%31.67%
Nicholas Piggin1514.54%31.67%
Peter Staubach1484.45%10.56%
Jeff Layton1153.46%63.33%
Bryan Schumaker1103.31%42.22%
Al Viro842.53%116.11%
Andy Adamson782.35%42.22%
Suresh Jayaraman752.26%10.56%
David Howells601.81%21.11%
Christoph Hellwig531.59%31.67%
Andrew Morton341.02%42.22%
Matthew Wilcox190.57%10.56%
Kirill A. Shutemov150.45%21.11%
Sergey Vlasov140.42%10.56%
Linus Torvalds130.39%42.22%
Lukas Czerner110.33%10.56%
Art Haas100.30%10.56%
Josef Bacik100.30%21.11%
J. Bruce Fields90.27%10.56%
Benjamin LaHaise80.24%10.56%
Andi Kleen70.21%31.67%
ASANO Masahiro60.18%10.56%
Scott Mayhew60.18%10.56%
Chao Yu50.15%10.56%
Ricardo Labiaga40.12%10.56%
Alexey Dobriyan40.12%21.11%
Anna Schumaker40.12%10.56%
Miklos Szeredi30.09%10.56%
Pavel Emelyanov30.09%10.56%
Niels de Vos30.09%10.56%
Badari Pulavarty30.09%10.56%
Junjiro R. Okajima30.09%10.56%
Rakib Mullick30.09%10.56%
Tejun Heo20.06%10.56%
Dave Jiang20.06%10.56%
Peng Tao10.03%10.56%
Lucas De Marchi10.03%10.56%
Neil Brown10.03%10.56%
Dave Jones10.03%10.56%
Total3324100.00%180100.00%
Directory: fs/nfs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.