![Linus Torvalds](/assets/img/avatar_default.png)
Highlights include: Stable fixes: - Fix an uninitialised pointer Oops in the writeback error path - Fix a bogus warning (and early exit from the loop) in nfs_generic_pgio Features: - Add NFSv4.2 SEEK feature and client support for lseek(SEEK_HOLE/SEEK_DATA) Other fixes: - pnfs: replace broken pnfs_put_lseg_async - Remove dead prototype for nfs4_insert_deviceid_node -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUP4dhAAoJEGcL54qWCgDy1+EQAKpFVKDjGEik5V1ye492mGbS moP3zvJtGTfwoK+eCV4HqIj0oFh06RqoQc5z4vc0MKd3uuxXgPFj/wmJef48CWot 1BKoDWItzZZlBAJsE0+0i6EWZ05tAZv7Fr9ial6VwchpNAih1K/NPcBix/jEwWYl WEFhKyGiN6UNhWfL0nXgvyQPD5tevvkr+5qv0A8dm8HGTEBlGhbzt4sfiUbWHPMD jCVsHBZNOeZQrFwVzMx+LCZaBwb+xeRAs0Pg1U51MetpwnNce9737M9oetbzgkI5 cSACmvo76osaerC2Avxj4t713xeqfur4YRwIajamkUxWbcjXm3vaAQmE744meJOO IOkIrmiGfMnJHw3f5CFnsAXcXmGu16umRqTexzz5iCqZ65ZuKWgIxs9yzBCOK/Or f8nbGsCU2EaX8mJxf+esP4SzstxtqHRtkTj4f8D4wWm/W+PXYPCzCsI1q3rDni0U yNH2Z4gRWcGz6LVfL/9lDHldN5S4WLkJuZQJtyijcy1jYCjwEEUFbX1V41s85GFB QdQvZ7Cr4NqRyqvR7zyIdH1jTWt2N5mJytsmEbSGoXgBFzRDYCFXfSNjjJ2JfThl sGeWlP99uEVbTxCTTBbulFXqYrmiNN7mW61+qedqT2Oy5/YjJTSE4PCp1p2YWlx/ /c17q7jOq6cnbKcyu7cl =ekPm -----END PGP SIGNATURE----- Merge tag 'nfs-for-3.18-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs Pull NFS client updates from Trond Myklebust: "Highlights include: Stable fixes: - fix an uninitialised pointer Oops in the writeback error path - fix a bogus warning (and early exit from the loop) in nfs_generic_pgio() Features: - Add NFSv4.2 SEEK feature and client support for lseek(SEEK_HOLE/SEEK_DATA) Other fixes: - pnfs: replace broken pnfs_put_lseg_async - Remove dead prototype for nfs4_insert_deviceid_node" * tag 'nfs-for-3.18-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: NFS: Fix a bogus warning in nfs_generic_pgio NFS: Fix an uninitialised pointer Oops in the writeback error path NFSv4.1/pnfs: replace broken pnfs_put_lseg_async NFSv4: Remove dead prototype for nfs4_insert_deviceid_node() NFS: Implement SEEK
161 lines
3.5 KiB
C
161 lines
3.5 KiB
C
/*
|
|
* linux/fs/nfs/file.c
|
|
*
|
|
* Copyright (C) 1992 Rick Sladkey
|
|
*/
|
|
#include <linux/nfs_fs.h>
|
|
#include "internal.h"
|
|
#include "fscache.h"
|
|
#include "pnfs.h"
|
|
|
|
#ifdef CONFIG_NFS_V4_2
|
|
#include "nfs42.h"
|
|
#endif
|
|
|
|
#define NFSDBG_FACILITY NFSDBG_FILE
|
|
|
|
static int
|
|
nfs4_file_open(struct inode *inode, struct file *filp)
|
|
{
|
|
struct nfs_open_context *ctx;
|
|
struct dentry *dentry = filp->f_path.dentry;
|
|
struct dentry *parent = NULL;
|
|
struct inode *dir;
|
|
unsigned openflags = filp->f_flags;
|
|
struct iattr attr;
|
|
int opened = 0;
|
|
int err;
|
|
|
|
/*
|
|
* If no cached dentry exists or if it's negative, NFSv4 handled the
|
|
* opens in ->lookup() or ->create().
|
|
*
|
|
* We only get this far for a cached positive dentry. We skipped
|
|
* revalidation, so handle it here by dropping the dentry and returning
|
|
* -EOPENSTALE. The VFS will retry the lookup/create/open.
|
|
*/
|
|
|
|
dprintk("NFS: open file(%pd2)\n", dentry);
|
|
|
|
if ((openflags & O_ACCMODE) == 3)
|
|
openflags--;
|
|
|
|
/* We can't create new files here */
|
|
openflags &= ~(O_CREAT|O_EXCL);
|
|
|
|
parent = dget_parent(dentry);
|
|
dir = parent->d_inode;
|
|
|
|
ctx = alloc_nfs_open_context(filp->f_path.dentry, filp->f_mode);
|
|
err = PTR_ERR(ctx);
|
|
if (IS_ERR(ctx))
|
|
goto out;
|
|
|
|
attr.ia_valid = ATTR_OPEN;
|
|
if (openflags & O_TRUNC) {
|
|
attr.ia_valid |= ATTR_SIZE;
|
|
attr.ia_size = 0;
|
|
nfs_wb_all(inode);
|
|
}
|
|
|
|
inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened);
|
|
if (IS_ERR(inode)) {
|
|
err = PTR_ERR(inode);
|
|
switch (err) {
|
|
case -EPERM:
|
|
case -EACCES:
|
|
case -EDQUOT:
|
|
case -ENOSPC:
|
|
case -EROFS:
|
|
goto out_put_ctx;
|
|
default:
|
|
goto out_drop;
|
|
}
|
|
}
|
|
if (inode != dentry->d_inode)
|
|
goto out_drop;
|
|
|
|
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
|
|
nfs_file_set_open_context(filp, ctx);
|
|
nfs_fscache_open_file(inode, filp);
|
|
err = 0;
|
|
|
|
out_put_ctx:
|
|
put_nfs_open_context(ctx);
|
|
out:
|
|
dput(parent);
|
|
return err;
|
|
|
|
out_drop:
|
|
d_drop(dentry);
|
|
err = -EOPENSTALE;
|
|
goto out_put_ctx;
|
|
}
|
|
|
|
static int
|
|
nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
|
{
|
|
int ret;
|
|
struct inode *inode = file_inode(file);
|
|
|
|
do {
|
|
ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
|
|
if (ret != 0)
|
|
break;
|
|
mutex_lock(&inode->i_mutex);
|
|
ret = nfs_file_fsync_commit(file, start, end, datasync);
|
|
if (!ret)
|
|
ret = pnfs_layoutcommit_inode(inode, true);
|
|
mutex_unlock(&inode->i_mutex);
|
|
/*
|
|
* 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);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_NFS_V4_2
|
|
static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
|
|
{
|
|
loff_t ret;
|
|
|
|
switch (whence) {
|
|
case SEEK_HOLE:
|
|
case SEEK_DATA:
|
|
ret = nfs42_proc_llseek(filep, offset, whence);
|
|
if (ret != -ENOTSUPP)
|
|
return ret;
|
|
default:
|
|
return nfs_file_llseek(filep, offset, whence);
|
|
}
|
|
}
|
|
#endif /* CONFIG_NFS_V4_2 */
|
|
|
|
const struct file_operations nfs4_file_operations = {
|
|
#ifdef CONFIG_NFS_V4_2
|
|
.llseek = nfs4_file_llseek,
|
|
#else
|
|
.llseek = nfs_file_llseek,
|
|
#endif
|
|
.read = new_sync_read,
|
|
.write = new_sync_write,
|
|
.read_iter = nfs_file_read,
|
|
.write_iter = nfs_file_write,
|
|
.mmap = nfs_file_mmap,
|
|
.open = nfs4_file_open,
|
|
.flush = nfs_file_flush,
|
|
.release = nfs_file_release,
|
|
.fsync = nfs4_file_fsync,
|
|
.lock = nfs_lock,
|
|
.flock = nfs_flock,
|
|
.splice_read = nfs_file_splice_read,
|
|
.splice_write = iter_file_splice_write,
|
|
.check_flags = nfs_check_flags,
|
|
.setlease = simple_nosetlease,
|
|
};
|