Merge branch 'devel' into for-linus
This commit is contained in:
@@ -38,19 +38,10 @@ static struct svc_program nfs4_callback_program;
|
||||
|
||||
unsigned int nfs_callback_set_tcpport;
|
||||
unsigned short nfs_callback_tcpport;
|
||||
unsigned short nfs_callback_tcpport6;
|
||||
static const int nfs_set_port_min = 0;
|
||||
static const int nfs_set_port_max = 65535;
|
||||
|
||||
/*
|
||||
* If the kernel has IPv6 support available, always listen for
|
||||
* both AF_INET and AF_INET6 requests.
|
||||
*/
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
static const sa_family_t nfs_callback_family = AF_INET6;
|
||||
#else
|
||||
static const sa_family_t nfs_callback_family = AF_INET;
|
||||
#endif
|
||||
|
||||
static int param_set_port(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
char *endp;
|
||||
@@ -116,19 +107,29 @@ int nfs_callback_up(void)
|
||||
mutex_lock(&nfs_callback_mutex);
|
||||
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
|
||||
goto out;
|
||||
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
|
||||
nfs_callback_family, NULL);
|
||||
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
|
||||
ret = -ENOMEM;
|
||||
if (!serv)
|
||||
goto out_err;
|
||||
|
||||
ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport,
|
||||
SVC_SOCK_ANONYMOUS);
|
||||
ret = svc_create_xprt(serv, "tcp", PF_INET,
|
||||
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
|
||||
if (ret <= 0)
|
||||
goto out_err;
|
||||
nfs_callback_tcpport = ret;
|
||||
dprintk("NFS: Callback listener port = %u (af %u)\n",
|
||||
nfs_callback_tcpport, nfs_callback_family);
|
||||
nfs_callback_tcpport, PF_INET);
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
ret = svc_create_xprt(serv, "tcp", PF_INET6,
|
||||
nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS);
|
||||
if (ret > 0) {
|
||||
nfs_callback_tcpport6 = ret;
|
||||
dprintk("NFS: Callback listener port = %u (af %u)\n",
|
||||
nfs_callback_tcpport6, PF_INET6);
|
||||
} else if (ret != -EAFNOSUPPORT)
|
||||
goto out_err;
|
||||
#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
|
||||
|
||||
nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]);
|
||||
if (IS_ERR(nfs_callback_info.rqst)) {
|
||||
|
@@ -72,5 +72,6 @@ extern void nfs_callback_down(void);
|
||||
|
||||
extern unsigned int nfs_callback_set_tcpport;
|
||||
extern unsigned short nfs_callback_tcpport;
|
||||
extern unsigned short nfs_callback_tcpport6;
|
||||
|
||||
#endif /* __LINUX_FS_NFS_CALLBACK_H */
|
||||
|
118
fs/nfs/client.c
118
fs/nfs/client.c
@@ -224,38 +224,6 @@ void nfs_put_client(struct nfs_client *clp)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped)
|
||||
{
|
||||
switch (sa->sa_family) {
|
||||
default:
|
||||
return NULL;
|
||||
case AF_INET6:
|
||||
return &((const struct sockaddr_in6 *)sa)->sin6_addr;
|
||||
break;
|
||||
case AF_INET:
|
||||
ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr,
|
||||
addr_mapped);
|
||||
return addr_mapped;
|
||||
}
|
||||
}
|
||||
|
||||
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
const struct in6_addr *addr1;
|
||||
const struct in6_addr *addr2;
|
||||
struct in6_addr addr1_mapped;
|
||||
struct in6_addr addr2_mapped;
|
||||
|
||||
addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped);
|
||||
if (likely(addr1 != NULL)) {
|
||||
addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped);
|
||||
if (likely(addr2 != NULL))
|
||||
return ipv6_addr_equal(addr1, addr2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if two ip6 socket addresses refer to the same socket by
|
||||
* comparing relevant fields. The padding bytes specifically, are not
|
||||
@@ -267,38 +235,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
|
||||
*
|
||||
* The caller should ensure both socket addresses are AF_INET6.
|
||||
*/
|
||||
static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1;
|
||||
const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2;
|
||||
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
|
||||
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
|
||||
|
||||
if (!ipv6_addr_equal(&saddr1->sin6_addr,
|
||||
&saddr1->sin6_addr))
|
||||
if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
|
||||
sin1->sin6_scope_id != sin2->sin6_scope_id)
|
||||
return 0;
|
||||
if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL &&
|
||||
saddr1->sin6_scope_id != saddr2->sin6_scope_id)
|
||||
return 0;
|
||||
return saddr1->sin6_port == saddr2->sin6_port;
|
||||
}
|
||||
#else
|
||||
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1,
|
||||
const struct sockaddr_in *sa2)
|
||||
{
|
||||
return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET))
|
||||
return 0;
|
||||
return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
|
||||
(const struct sockaddr_in *)sa2);
|
||||
return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr);
|
||||
}
|
||||
|
||||
static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
|
||||
const struct sockaddr * sa2)
|
||||
#else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */
|
||||
static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -311,20 +262,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
|
||||
*
|
||||
* The caller should ensure both socket addresses are AF_INET.
|
||||
*/
|
||||
static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
|
||||
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
|
||||
|
||||
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
|
||||
}
|
||||
|
||||
static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
|
||||
const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
|
||||
|
||||
return nfs_sockaddr_match_ipaddr6(sa1, sa2) &&
|
||||
(sin1->sin6_port == sin2->sin6_port);
|
||||
}
|
||||
|
||||
static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1;
|
||||
const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2;
|
||||
const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
|
||||
const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
|
||||
|
||||
if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr)
|
||||
return 0;
|
||||
return saddr1->sin_port == saddr2->sin_port;
|
||||
return nfs_sockaddr_match_ipaddr4(sa1, sa2) &&
|
||||
(sin1->sin_port == sin2->sin_port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if two socket addresses represent the same actual socket,
|
||||
* by comparing (only) relevant fields.
|
||||
* by comparing (only) relevant fields, excluding the port number.
|
||||
*/
|
||||
static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
{
|
||||
if (sa1->sa_family != sa2->sa_family)
|
||||
return 0;
|
||||
|
||||
switch (sa1->sa_family) {
|
||||
case AF_INET:
|
||||
return nfs_sockaddr_match_ipaddr4(sa1, sa2);
|
||||
case AF_INET6:
|
||||
return nfs_sockaddr_match_ipaddr6(sa1, sa2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if two socket addresses represent the same actual socket,
|
||||
* by comparing (only) relevant fields, including the port number.
|
||||
*/
|
||||
static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
|
||||
const struct sockaddr *sa2)
|
||||
|
@@ -1624,8 +1624,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
} else if (atomic_read(&new_dentry->d_count) > 1)
|
||||
/* dentry still busy? */
|
||||
goto out;
|
||||
} else
|
||||
nfs_drop_nlink(new_inode);
|
||||
}
|
||||
|
||||
go_ahead:
|
||||
/*
|
||||
@@ -1638,10 +1637,8 @@ go_ahead:
|
||||
}
|
||||
nfs_inode_return_delegation(old_inode);
|
||||
|
||||
if (new_inode != NULL) {
|
||||
if (new_inode != NULL)
|
||||
nfs_inode_return_delegation(new_inode);
|
||||
d_delete(new_dentry);
|
||||
}
|
||||
|
||||
error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
|
||||
new_dir, &new_dentry->d_name);
|
||||
@@ -1650,6 +1647,8 @@ out:
|
||||
if (rehash)
|
||||
d_rehash(rehash);
|
||||
if (!error) {
|
||||
if (new_inode != NULL)
|
||||
nfs_drop_nlink(new_inode);
|
||||
d_move(old_dentry, new_dentry);
|
||||
nfs_set_verifier(new_dentry,
|
||||
nfs_save_change_attribute(new_dir));
|
||||
|
@@ -64,11 +64,7 @@ const struct file_operations nfs_file_operations = {
|
||||
.write = do_sync_write,
|
||||
.aio_read = nfs_file_read,
|
||||
.aio_write = nfs_file_write,
|
||||
#ifdef CONFIG_MMU
|
||||
.mmap = nfs_file_mmap,
|
||||
#else
|
||||
.mmap = generic_file_mmap,
|
||||
#endif
|
||||
.open = nfs_file_open,
|
||||
.flush = nfs_file_flush,
|
||||
.release = nfs_file_release,
|
||||
@@ -141,9 +137,6 @@ nfs_file_release(struct inode *inode, struct file *filp)
|
||||
dentry->d_parent->d_name.name,
|
||||
dentry->d_name.name);
|
||||
|
||||
/* Ensure that dirty pages are flushed out with the right creds */
|
||||
if (filp->f_mode & FMODE_WRITE)
|
||||
nfs_wb_all(dentry->d_inode);
|
||||
nfs_inc_stats(inode, NFSIOS_VFSRELEASE);
|
||||
return nfs_release(inode, filp);
|
||||
}
|
||||
@@ -235,7 +228,6 @@ nfs_file_flush(struct file *file, fl_owner_t id)
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(file);
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int status;
|
||||
|
||||
dprintk("NFS: flush(%s/%s)\n",
|
||||
dentry->d_parent->d_name.name,
|
||||
@@ -245,11 +237,8 @@ nfs_file_flush(struct file *file, fl_owner_t id)
|
||||
return 0;
|
||||
nfs_inc_stats(inode, NFSIOS_VFSFLUSH);
|
||||
|
||||
/* Ensure that data+attribute caches are up to date after close() */
|
||||
status = nfs_do_fsync(ctx, inode);
|
||||
if (!status)
|
||||
nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
||||
return status;
|
||||
/* Flush writes to the server and return any errors */
|
||||
return nfs_do_fsync(ctx, inode);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@@ -304,11 +293,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
|
||||
dprintk("NFS: mmap(%s/%s)\n",
|
||||
dentry->d_parent->d_name.name, dentry->d_name.name);
|
||||
|
||||
status = nfs_revalidate_mapping(inode, file->f_mapping);
|
||||
/* 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;
|
||||
vma->vm_flags |= VM_CAN_NONLINEAR;
|
||||
file_accessed(file);
|
||||
status = nfs_revalidate_mapping(inode, file->f_mapping);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -354,6 +345,15 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
file->f_path.dentry->d_name.name,
|
||||
mapping->host->i_ino, len, (long long) pos);
|
||||
|
||||
/*
|
||||
* Prevent starvation issues if someone is doing a consistency
|
||||
* sync-to-disk
|
||||
*/
|
||||
ret = wait_on_bit(&NFS_I(mapping->host)->flags, NFS_INO_FLUSHING,
|
||||
nfs_wait_bit_killable, TASK_KILLABLE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
page = grab_cache_page_write_begin(mapping, index, flags);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
@@ -156,7 +156,7 @@ int nfs4_path_walk(struct nfs_server *server,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fattr.type != NFDIR) {
|
||||
if (!S_ISDIR(fattr.mode)) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" getroot encountered non-directory\n");
|
||||
return -ENOTDIR;
|
||||
@@ -213,7 +213,7 @@ eat_dot_dir:
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (fattr.type != NFDIR) {
|
||||
if (!S_ISDIR(fattr.mode)) {
|
||||
printk(KERN_ERR "nfs4_get_root:"
|
||||
" lookupfh encountered non-directory\n");
|
||||
return -ENOTDIR;
|
||||
|
309
fs/nfs/inode.c
309
fs/nfs/inode.c
@@ -65,6 +65,18 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
|
||||
return nfs_fileid_to_ino_t(fattr->fileid);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
|
||||
* @word: long word containing the bit lock
|
||||
*/
|
||||
int nfs_wait_bit_killable(void *word)
|
||||
{
|
||||
if (fatal_signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
schedule();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_compat_user_ino64 - returns the user-visible inode number
|
||||
* @fileid: 64-bit fileid
|
||||
@@ -249,13 +261,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
struct inode *inode = ERR_PTR(-ENOENT);
|
||||
unsigned long hash;
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
|
||||
goto out_no_inode;
|
||||
|
||||
if (!fattr->nlink) {
|
||||
printk("NFS: Buggy server - nlink == 0!\n");
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
|
||||
goto out_no_inode;
|
||||
}
|
||||
|
||||
hash = nfs_fattr_to_ino_t(fattr);
|
||||
|
||||
@@ -291,7 +300,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
&& fattr->size <= NFS_LIMIT_READDIRPLUS)
|
||||
set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags);
|
||||
/* Deal with crossing mountpoints */
|
||||
if (!nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_FSID)
|
||||
&& !nfs_fsid_equal(&NFS_SB(sb)->fsid, &fattr->fsid)) {
|
||||
if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
|
||||
inode->i_op = &nfs_referral_inode_operations;
|
||||
else
|
||||
@@ -304,28 +314,45 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
|
||||
else
|
||||
init_special_inode(inode, inode->i_mode, fattr->rdev);
|
||||
|
||||
memset(&inode->i_atime, 0, sizeof(inode->i_atime));
|
||||
memset(&inode->i_mtime, 0, sizeof(inode->i_mtime));
|
||||
memset(&inode->i_ctime, 0, sizeof(inode->i_ctime));
|
||||
nfsi->change_attr = 0;
|
||||
inode->i_size = 0;
|
||||
inode->i_nlink = 0;
|
||||
inode->i_uid = -2;
|
||||
inode->i_gid = -2;
|
||||
inode->i_blocks = 0;
|
||||
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
|
||||
|
||||
nfsi->read_cache_jiffies = fattr->time_start;
|
||||
nfsi->attr_gencount = fattr->gencount;
|
||||
inode->i_atime = fattr->atime;
|
||||
inode->i_mtime = fattr->mtime;
|
||||
inode->i_ctime = fattr->ctime;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_V4)
|
||||
if (fattr->valid & NFS_ATTR_FATTR_ATIME)
|
||||
inode->i_atime = fattr->atime;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_MTIME)
|
||||
inode->i_mtime = fattr->mtime;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_CTIME)
|
||||
inode->i_ctime = fattr->ctime;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_CHANGE)
|
||||
nfsi->change_attr = fattr->change_attr;
|
||||
inode->i_size = nfs_size_to_loff_t(fattr->size);
|
||||
inode->i_nlink = fattr->nlink;
|
||||
inode->i_uid = fattr->uid;
|
||||
inode->i_gid = fattr->gid;
|
||||
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
|
||||
if (fattr->valid & NFS_ATTR_FATTR_SIZE)
|
||||
inode->i_size = nfs_size_to_loff_t(fattr->size);
|
||||
if (fattr->valid & NFS_ATTR_FATTR_NLINK)
|
||||
inode->i_nlink = fattr->nlink;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_OWNER)
|
||||
inode->i_uid = fattr->uid;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_GROUP)
|
||||
inode->i_gid = fattr->gid;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
|
||||
inode->i_blocks = fattr->du.nfs2.blocks;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
|
||||
/*
|
||||
* report the blocks in 512byte units
|
||||
*/
|
||||
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
|
||||
} else {
|
||||
inode->i_blocks = fattr->du.nfs2.blocks;
|
||||
}
|
||||
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
|
||||
nfsi->attrtimeo_timestamp = now;
|
||||
memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
|
||||
nfsi->access_cache = RB_ROOT;
|
||||
|
||||
unlock_new_inode(inode);
|
||||
@@ -514,6 +541,32 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_close_context - Common close_context() routine NFSv2/v3
|
||||
* @ctx: pointer to context
|
||||
* @is_sync: is this a synchronous close
|
||||
*
|
||||
* always ensure that the attributes are up to date if we're mounted
|
||||
* with close-to-open semantics
|
||||
*/
|
||||
void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct nfs_server *server;
|
||||
|
||||
if (!(ctx->mode & FMODE_WRITE))
|
||||
return;
|
||||
if (!is_sync)
|
||||
return;
|
||||
inode = ctx->path.dentry->d_inode;
|
||||
if (!list_empty(&NFS_I(inode)->open_files))
|
||||
return;
|
||||
server = NFS_SERVER(inode);
|
||||
if (server->flags & NFS_MOUNT_NOCTO)
|
||||
return;
|
||||
nfs_revalidate_inode(server, inode);
|
||||
}
|
||||
|
||||
static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred)
|
||||
{
|
||||
struct nfs_open_context *ctx;
|
||||
@@ -540,24 +593,15 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait)
|
||||
static void __put_nfs_open_context(struct nfs_open_context *ctx, int is_sync)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *inode = ctx->path.dentry->d_inode;
|
||||
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
inode = ctx->path.dentry->d_inode;
|
||||
if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
|
||||
return;
|
||||
list_del(&ctx->list);
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (ctx->state != NULL) {
|
||||
if (wait)
|
||||
nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
|
||||
else
|
||||
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
||||
}
|
||||
NFS_PROTO(inode)->close_context(ctx, is_sync);
|
||||
if (ctx->cred != NULL)
|
||||
put_rpccred(ctx->cred);
|
||||
path_put(&ctx->path);
|
||||
@@ -670,9 +714,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
|
||||
if (NFS_STALE(inode))
|
||||
goto out;
|
||||
|
||||
if (NFS_STALE(inode))
|
||||
goto out;
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
|
||||
status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), &fattr);
|
||||
if (status != 0) {
|
||||
@@ -815,25 +856,31 @@ static void nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_WCC_V4) != 0 &&
|
||||
nfsi->change_attr == fattr->pre_change_attr) {
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_PRECHANGE)
|
||||
&& (fattr->valid & NFS_ATTR_FATTR_CHANGE)
|
||||
&& nfsi->change_attr == fattr->pre_change_attr) {
|
||||
nfsi->change_attr = fattr->change_attr;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
|
||||
}
|
||||
/* If we have atomic WCC data, we may update some attributes */
|
||||
if ((fattr->valid & NFS_ATTR_WCC) != 0) {
|
||||
if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_PRECTIME)
|
||||
&& (fattr->valid & NFS_ATTR_FATTR_CTIME)
|
||||
&& timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
|
||||
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
|
||||
if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_PREMTIME)
|
||||
&& (fattr->valid & NFS_ATTR_FATTR_MTIME)
|
||||
&& timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) {
|
||||
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
nfsi->cache_validity |= NFS_INO_INVALID_DATA;
|
||||
}
|
||||
if (i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size) &&
|
||||
nfsi->npages == 0)
|
||||
i_size_write(inode, nfs_size_to_loff_t(fattr->size));
|
||||
}
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
|
||||
&& (fattr->valid & NFS_ATTR_FATTR_SIZE)
|
||||
&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
|
||||
&& nfsi->npages == 0)
|
||||
i_size_write(inode, nfs_size_to_loff_t(fattr->size));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -853,35 +900,39 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
|
||||
|
||||
|
||||
/* Has the inode gone and changed behind our back? */
|
||||
if (nfsi->fileid != fattr->fileid
|
||||
|| (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) {
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
|
||||
return -EIO;
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
|
||||
nfsi->change_attr != fattr->change_attr)
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
||||
|
||||
/* Verify a few of the more important attributes */
|
||||
if (!timespec_equal(&inode->i_mtime, &fattr->mtime))
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_MTIME) && !timespec_equal(&inode->i_mtime, &fattr->mtime))
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
||||
|
||||
cur_size = i_size_read(inode);
|
||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||
if (cur_size != new_isize && nfsi->npages == 0)
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
||||
cur_size = i_size_read(inode);
|
||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||
if (cur_size != new_isize && nfsi->npages == 0)
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
|
||||
}
|
||||
|
||||
/* Have any file permissions changed? */
|
||||
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
|
||||
|| inode->i_uid != fattr->uid
|
||||
|| inode->i_gid != fattr->gid)
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
|
||||
invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
|
||||
invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
|
||||
invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
|
||||
|
||||
/* Has the link count changed? */
|
||||
if (inode->i_nlink != fattr->nlink)
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_NLINK) && inode->i_nlink != fattr->nlink)
|
||||
invalid |= NFS_INO_INVALID_ATTR;
|
||||
|
||||
if (!timespec_equal(&inode->i_atime, &fattr->atime))
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_ATIME) && !timespec_equal(&inode->i_atime, &fattr->atime))
|
||||
invalid |= NFS_INO_INVALID_ATIME;
|
||||
|
||||
if (invalid != 0)
|
||||
@@ -893,11 +944,15 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
|
||||
|
||||
static int nfs_ctime_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
|
||||
{
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR_CTIME))
|
||||
return 0;
|
||||
return timespec_compare(&fattr->ctime, &inode->i_ctime) > 0;
|
||||
}
|
||||
|
||||
static int nfs_size_need_update(const struct inode *inode, const struct nfs_fattr *fattr)
|
||||
{
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR_SIZE))
|
||||
return 0;
|
||||
return nfs_size_to_loff_t(fattr->size) > i_size_read(inode);
|
||||
}
|
||||
|
||||
@@ -1033,20 +1088,31 @@ int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fa
|
||||
/* Don't do a WCC update if these attributes are already stale */
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) == 0 ||
|
||||
!nfs_inode_attrs_need_update(inode, fattr)) {
|
||||
fattr->valid &= ~(NFS_ATTR_WCC_V4|NFS_ATTR_WCC);
|
||||
fattr->valid &= ~(NFS_ATTR_FATTR_PRECHANGE
|
||||
| NFS_ATTR_FATTR_PRESIZE
|
||||
| NFS_ATTR_FATTR_PREMTIME
|
||||
| NFS_ATTR_FATTR_PRECTIME);
|
||||
goto out_noforce;
|
||||
}
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
|
||||
(fattr->valid & NFS_ATTR_WCC_V4) == 0) {
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) != 0 &&
|
||||
(fattr->valid & NFS_ATTR_FATTR_PRECHANGE) == 0) {
|
||||
fattr->pre_change_attr = NFS_I(inode)->change_attr;
|
||||
fattr->valid |= NFS_ATTR_WCC_V4;
|
||||
fattr->valid |= NFS_ATTR_FATTR_PRECHANGE;
|
||||
}
|
||||
if ((fattr->valid & NFS_ATTR_FATTR) != 0 &&
|
||||
(fattr->valid & NFS_ATTR_WCC) == 0) {
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_CTIME) != 0 &&
|
||||
(fattr->valid & NFS_ATTR_FATTR_PRECTIME) == 0) {
|
||||
memcpy(&fattr->pre_ctime, &inode->i_ctime, sizeof(fattr->pre_ctime));
|
||||
fattr->valid |= NFS_ATTR_FATTR_PRECTIME;
|
||||
}
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_MTIME) != 0 &&
|
||||
(fattr->valid & NFS_ATTR_FATTR_PREMTIME) == 0) {
|
||||
memcpy(&fattr->pre_mtime, &inode->i_mtime, sizeof(fattr->pre_mtime));
|
||||
fattr->valid |= NFS_ATTR_FATTR_PREMTIME;
|
||||
}
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_SIZE) != 0 &&
|
||||
(fattr->valid & NFS_ATTR_FATTR_PRESIZE) == 0) {
|
||||
fattr->pre_size = i_size_read(inode);
|
||||
fattr->valid |= NFS_ATTR_WCC;
|
||||
fattr->valid |= NFS_ATTR_FATTR_PRESIZE;
|
||||
}
|
||||
out_noforce:
|
||||
status = nfs_post_op_update_inode_locked(inode, fattr);
|
||||
@@ -1078,18 +1144,18 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
__func__, inode->i_sb->s_id, inode->i_ino,
|
||||
atomic_read(&inode->i_count), fattr->valid);
|
||||
|
||||
if (nfsi->fileid != fattr->fileid)
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid)
|
||||
goto out_fileid;
|
||||
|
||||
/*
|
||||
* Make sure the inode's type hasn't changed.
|
||||
*/
|
||||
if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
|
||||
goto out_changed;
|
||||
|
||||
server = NFS_SERVER(inode);
|
||||
/* Update the fsid? */
|
||||
if (S_ISDIR(inode->i_mode) &&
|
||||
if (S_ISDIR(inode->i_mode) && (fattr->valid & NFS_ATTR_FATTR_FSID) &&
|
||||
!nfs_fsid_equal(&server->fsid, &fattr->fsid) &&
|
||||
!test_bit(NFS_INO_MOUNTPOINT, &nfsi->flags))
|
||||
server->fsid = fattr->fsid;
|
||||
@@ -1099,14 +1165,27 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
*/
|
||||
nfsi->read_cache_jiffies = fattr->time_start;
|
||||
|
||||
nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ATIME
|
||||
| NFS_INO_REVAL_PAGECACHE);
|
||||
if ((fattr->valid & NFS_ATTR_FATTR_CHANGE) || (fattr->valid & (NFS_ATTR_FATTR_MTIME|NFS_ATTR_FATTR_CTIME)))
|
||||
nfsi->cache_validity &= ~(NFS_INO_INVALID_ATTR
|
||||
| NFS_INO_INVALID_ATIME
|
||||
| NFS_INO_REVAL_PAGECACHE);
|
||||
|
||||
/* Do atomic weak cache consistency updates */
|
||||
nfs_wcc_update_inode(inode, fattr);
|
||||
|
||||
/* More cache consistency checks */
|
||||
if (!(fattr->valid & NFS_ATTR_FATTR_V4)) {
|
||||
if (fattr->valid & NFS_ATTR_FATTR_CHANGE) {
|
||||
if (nfsi->change_attr != fattr->change_attr) {
|
||||
dprintk("NFS: change_attr change on server for file %s/%ld\n",
|
||||
inode->i_sb->s_id, inode->i_ino);
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
nfs_force_lookup_revalidate(inode);
|
||||
nfsi->change_attr = fattr->change_attr;
|
||||
}
|
||||
}
|
||||
|
||||
if (fattr->valid & NFS_ATTR_FATTR_MTIME) {
|
||||
/* NFSv2/v3: Check if the mtime agrees */
|
||||
if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
|
||||
dprintk("NFS: mtime change on server for file %s/%ld\n",
|
||||
@@ -1114,59 +1193,80 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
nfs_force_lookup_revalidate(inode);
|
||||
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
||||
}
|
||||
}
|
||||
if (fattr->valid & NFS_ATTR_FATTR_CTIME) {
|
||||
/* If ctime has changed we should definitely clear access+acl caches */
|
||||
if (!timespec_equal(&inode->i_ctime, &fattr->ctime))
|
||||
if (!timespec_equal(&inode->i_ctime, &fattr->ctime)) {
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
} else if (nfsi->change_attr != fattr->change_attr) {
|
||||
dprintk("NFS: change_attr change on server for file %s/%ld\n",
|
||||
inode->i_sb->s_id, inode->i_ino);
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
nfs_force_lookup_revalidate(inode);
|
||||
/* and probably clear data for a directory too as utimes can cause
|
||||
* havoc with our cache.
|
||||
*/
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
invalid |= NFS_INO_INVALID_DATA;
|
||||
nfs_force_lookup_revalidate(inode);
|
||||
}
|
||||
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if our cached file size is stale */
|
||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||
cur_isize = i_size_read(inode);
|
||||
if (new_isize != cur_isize) {
|
||||
/* Do we perhaps have any outstanding writes, or has
|
||||
* the file grown beyond our last write? */
|
||||
if (nfsi->npages == 0 || new_isize > cur_isize) {
|
||||
i_size_write(inode, new_isize);
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
|
||||
new_isize = nfs_size_to_loff_t(fattr->size);
|
||||
cur_isize = i_size_read(inode);
|
||||
if (new_isize != cur_isize) {
|
||||
/* Do we perhaps have any outstanding writes, or has
|
||||
* the file grown beyond our last write? */
|
||||
if (nfsi->npages == 0 || new_isize > cur_isize) {
|
||||
i_size_write(inode, new_isize);
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
|
||||
}
|
||||
dprintk("NFS: isize change on server for file %s/%ld\n",
|
||||
inode->i_sb->s_id, inode->i_ino);
|
||||
}
|
||||
dprintk("NFS: isize change on server for file %s/%ld\n",
|
||||
inode->i_sb->s_id, inode->i_ino);
|
||||
}
|
||||
|
||||
|
||||
memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
|
||||
memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
|
||||
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
|
||||
nfsi->change_attr = fattr->change_attr;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_ATIME)
|
||||
memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
|
||||
|
||||
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
|
||||
inode->i_uid != fattr->uid ||
|
||||
inode->i_gid != fattr->gid)
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_MODE) {
|
||||
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) {
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
inode->i_mode = fattr->mode;
|
||||
}
|
||||
}
|
||||
if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
|
||||
if (inode->i_uid != fattr->uid) {
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
inode->i_uid = fattr->uid;
|
||||
}
|
||||
}
|
||||
if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
|
||||
if (inode->i_gid != fattr->gid) {
|
||||
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
|
||||
inode->i_gid = fattr->gid;
|
||||
}
|
||||
}
|
||||
|
||||
if (inode->i_nlink != fattr->nlink)
|
||||
invalid |= NFS_INO_INVALID_ATTR;
|
||||
if (fattr->valid & NFS_ATTR_FATTR_NLINK) {
|
||||
if (inode->i_nlink != fattr->nlink) {
|
||||
invalid |= NFS_INO_INVALID_ATTR;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
invalid |= NFS_INO_INVALID_DATA;
|
||||
inode->i_nlink = fattr->nlink;
|
||||
}
|
||||
}
|
||||
|
||||
inode->i_mode = fattr->mode;
|
||||
inode->i_nlink = fattr->nlink;
|
||||
inode->i_uid = fattr->uid;
|
||||
inode->i_gid = fattr->gid;
|
||||
|
||||
if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
|
||||
if (fattr->valid & NFS_ATTR_FATTR_SPACE_USED) {
|
||||
/*
|
||||
* report the blocks in 512byte units
|
||||
*/
|
||||
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
|
||||
} else {
|
||||
inode->i_blocks = fattr->du.nfs2.blocks;
|
||||
}
|
||||
if (fattr->valid & NFS_ATTR_FATTR_BLOCKS_USED)
|
||||
inode->i_blocks = fattr->du.nfs2.blocks;
|
||||
|
||||
/* Update attrtimeo value if we're out of the unstable period */
|
||||
if (invalid & NFS_INO_INVALID_ATTR) {
|
||||
@@ -1274,7 +1374,6 @@ static void init_once(void *foo)
|
||||
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
|
||||
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
|
||||
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
|
||||
nfsi->ncommit = 0;
|
||||
nfsi->npages = 0;
|
||||
atomic_set(&nfsi->silly_count, 1);
|
||||
INIT_HLIST_HEAD(&nfsi->silly_list);
|
||||
|
@@ -152,6 +152,9 @@ extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
|
||||
extern struct rpc_procinfo nfs4_procedures[];
|
||||
#endif
|
||||
|
||||
/* proc.c */
|
||||
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
|
||||
|
||||
/* dir.c */
|
||||
extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
|
||||
|
||||
@@ -165,6 +168,7 @@ extern void nfs_clear_inode(struct inode *);
|
||||
extern void nfs4_clear_inode(struct inode *);
|
||||
#endif
|
||||
void nfs_zap_acl_cache(struct inode *inode);
|
||||
extern int nfs_wait_bit_killable(void *word);
|
||||
|
||||
/* super.c */
|
||||
void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
|
||||
|
@@ -120,8 +120,8 @@ xdr_decode_time(__be32 *p, struct timespec *timep)
|
||||
static __be32 *
|
||||
xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
|
||||
{
|
||||
u32 rdev;
|
||||
fattr->type = (enum nfs_ftype) ntohl(*p++);
|
||||
u32 rdev, type;
|
||||
type = ntohl(*p++);
|
||||
fattr->mode = ntohl(*p++);
|
||||
fattr->nlink = ntohl(*p++);
|
||||
fattr->uid = ntohl(*p++);
|
||||
@@ -136,10 +136,9 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
|
||||
p = xdr_decode_time(p, &fattr->atime);
|
||||
p = xdr_decode_time(p, &fattr->mtime);
|
||||
p = xdr_decode_time(p, &fattr->ctime);
|
||||
fattr->valid |= NFS_ATTR_FATTR;
|
||||
fattr->valid |= NFS_ATTR_FATTR_V2;
|
||||
fattr->rdev = new_decode_dev(rdev);
|
||||
if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
|
||||
fattr->type = NFFIFO;
|
||||
if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
|
||||
fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
|
||||
fattr->rdev = 0;
|
||||
}
|
||||
|
@@ -834,4 +834,5 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
|
||||
.commit_done = nfs3_commit_done,
|
||||
.lock = nfs3_proc_lock,
|
||||
.clear_acl_cache = nfs3_forget_cached_acls,
|
||||
.close_context = nfs_close_context,
|
||||
};
|
||||
|
@@ -91,19 +91,15 @@
|
||||
/*
|
||||
* Map file type to S_IFMT bits
|
||||
*/
|
||||
static struct {
|
||||
unsigned int mode;
|
||||
unsigned int nfs2type;
|
||||
} nfs_type2fmt[] = {
|
||||
{ 0, NFNON },
|
||||
{ S_IFREG, NFREG },
|
||||
{ S_IFDIR, NFDIR },
|
||||
{ S_IFBLK, NFBLK },
|
||||
{ S_IFCHR, NFCHR },
|
||||
{ S_IFLNK, NFLNK },
|
||||
{ S_IFSOCK, NFSOCK },
|
||||
{ S_IFIFO, NFFIFO },
|
||||
{ 0, NFBAD }
|
||||
static const umode_t nfs_type2fmt[] = {
|
||||
[NF3BAD] = 0,
|
||||
[NF3REG] = S_IFREG,
|
||||
[NF3DIR] = S_IFDIR,
|
||||
[NF3BLK] = S_IFBLK,
|
||||
[NF3CHR] = S_IFCHR,
|
||||
[NF3LNK] = S_IFLNK,
|
||||
[NF3SOCK] = S_IFSOCK,
|
||||
[NF3FIFO] = S_IFIFO,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -148,13 +144,12 @@ static __be32 *
|
||||
xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
|
||||
{
|
||||
unsigned int type, major, minor;
|
||||
int fmode;
|
||||
umode_t fmode;
|
||||
|
||||
type = ntohl(*p++);
|
||||
if (type >= NF3BAD)
|
||||
type = NF3BAD;
|
||||
fmode = nfs_type2fmt[type].mode;
|
||||
fattr->type = nfs_type2fmt[type].nfs2type;
|
||||
if (type > NF3FIFO)
|
||||
type = NF3NON;
|
||||
fmode = nfs_type2fmt[type];
|
||||
fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
|
||||
fattr->nlink = ntohl(*p++);
|
||||
fattr->uid = ntohl(*p++);
|
||||
@@ -177,7 +172,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
|
||||
p = xdr_decode_time3(p, &fattr->ctime);
|
||||
|
||||
/* Update the mode bits */
|
||||
fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
|
||||
fattr->valid |= NFS_ATTR_FATTR_V3;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -233,7 +228,9 @@ xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
|
||||
p = xdr_decode_hyper(p, &fattr->pre_size);
|
||||
p = xdr_decode_time3(p, &fattr->pre_mtime);
|
||||
p = xdr_decode_time3(p, &fattr->pre_ctime);
|
||||
fattr->valid |= NFS_ATTR_WCC;
|
||||
fattr->valid |= NFS_ATTR_FATTR_PRESIZE
|
||||
| NFS_ATTR_FATTR_PREMTIME
|
||||
| NFS_ATTR_FATTR_PRECTIME;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@@ -193,14 +193,6 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
|
||||
kunmap_atomic(start, KM_USER0);
|
||||
}
|
||||
|
||||
static int nfs4_wait_bit_killable(void *word)
|
||||
{
|
||||
if (fatal_signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
schedule();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs4_wait_clnt_recover(struct nfs_client *clp)
|
||||
{
|
||||
int res;
|
||||
@@ -208,7 +200,7 @@ static int nfs4_wait_clnt_recover(struct nfs_client *clp)
|
||||
might_sleep();
|
||||
|
||||
res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
|
||||
nfs4_wait_bit_killable, TASK_KILLABLE);
|
||||
nfs_wait_bit_killable, TASK_KILLABLE);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1439,7 +1431,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
|
||||
if (calldata->arg.seqid == NULL)
|
||||
goto out_free_calldata;
|
||||
calldata->arg.fmode = 0;
|
||||
calldata->arg.bitmask = server->attr_bitmask;
|
||||
calldata->arg.bitmask = server->cache_consistency_bitmask;
|
||||
calldata->res.fattr = &calldata->fattr;
|
||||
calldata->res.seqid = calldata->arg.seqid;
|
||||
calldata->res.server = server;
|
||||
@@ -1580,6 +1572,15 @@ out_drop:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
|
||||
{
|
||||
if (ctx->state == NULL)
|
||||
return;
|
||||
if (is_sync)
|
||||
nfs4_close_sync(&ctx->path, ctx->state, ctx->mode);
|
||||
else
|
||||
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
||||
}
|
||||
|
||||
static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
|
||||
{
|
||||
@@ -1600,6 +1601,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
||||
server->caps |= NFS_CAP_HARDLINKS;
|
||||
if (res.has_symlinks != 0)
|
||||
server->caps |= NFS_CAP_SYMLINKS;
|
||||
memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
|
||||
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
|
||||
server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
|
||||
server->acl_bitmask = res.acl_bitmask;
|
||||
}
|
||||
return status;
|
||||
@@ -2079,7 +2083,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
|
||||
struct nfs_removeargs *args = msg->rpc_argp;
|
||||
struct nfs_removeres *res = msg->rpc_resp;
|
||||
|
||||
args->bitmask = server->attr_bitmask;
|
||||
args->bitmask = server->cache_consistency_bitmask;
|
||||
res->server = server;
|
||||
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
|
||||
}
|
||||
@@ -2323,7 +2327,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
|
||||
.pages = &page,
|
||||
.pgbase = 0,
|
||||
.count = count,
|
||||
.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
|
||||
.bitmask = NFS_SERVER(dentry->d_inode)->cache_consistency_bitmask,
|
||||
};
|
||||
struct nfs4_readdir_res res;
|
||||
struct rpc_message msg = {
|
||||
@@ -2552,7 +2556,7 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(data->inode);
|
||||
|
||||
data->args.bitmask = server->attr_bitmask;
|
||||
data->args.bitmask = server->cache_consistency_bitmask;
|
||||
data->res.server = server;
|
||||
data->timestamp = jiffies;
|
||||
|
||||
@@ -2575,7 +2579,7 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(data->inode);
|
||||
|
||||
data->args.bitmask = server->attr_bitmask;
|
||||
data->args.bitmask = server->cache_consistency_bitmask;
|
||||
data->res.server = server;
|
||||
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
|
||||
}
|
||||
@@ -3678,6 +3682,19 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
|
||||
return len;
|
||||
}
|
||||
|
||||
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
|
||||
{
|
||||
if (!((fattr->valid & NFS_ATTR_FATTR_FILEID) &&
|
||||
(fattr->valid & NFS_ATTR_FATTR_FSID) &&
|
||||
(fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
|
||||
return;
|
||||
|
||||
fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
|
||||
NFS_ATTR_FATTR_NLINK;
|
||||
fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
|
||||
fattr->nlink = 2;
|
||||
}
|
||||
|
||||
int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
|
||||
struct nfs4_fs_locations *fs_locations, struct page *page)
|
||||
{
|
||||
@@ -3704,6 +3721,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
|
||||
fs_locations->server = server;
|
||||
fs_locations->nlocations = 0;
|
||||
status = rpc_call_sync(server->client, &msg, 0);
|
||||
nfs_fixup_referral_attributes(&fs_locations->fattr);
|
||||
dprintk("%s: returned status = %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
@@ -3767,6 +3785,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
|
||||
.commit_done = nfs4_commit_done,
|
||||
.lock = nfs4_proc_lock,
|
||||
.clear_acl_cache = nfs4_zap_acl_attr,
|
||||
.close_context = nfs4_close_context,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -62,8 +62,14 @@ static LIST_HEAD(nfs4_clientid_list);
|
||||
|
||||
static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
|
||||
{
|
||||
int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
|
||||
nfs_callback_tcpport, cred);
|
||||
unsigned short port;
|
||||
int status;
|
||||
|
||||
port = nfs_callback_tcpport;
|
||||
if (clp->cl_addr.ss_family == AF_INET6)
|
||||
port = nfs_callback_tcpport6;
|
||||
|
||||
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred);
|
||||
if (status == 0)
|
||||
status = nfs4_proc_setclientid_confirm(clp, cred);
|
||||
if (status == 0)
|
||||
|
213
fs/nfs/nfs4xdr.c
213
fs/nfs/nfs4xdr.c
@@ -522,20 +522,17 @@ static int nfs4_stat_to_errno(int);
|
||||
decode_lookup_maxsz + \
|
||||
decode_fs_locations_maxsz)
|
||||
|
||||
static struct {
|
||||
unsigned int mode;
|
||||
unsigned int nfs2type;
|
||||
} nfs_type2fmt[] = {
|
||||
{ 0, NFNON },
|
||||
{ S_IFREG, NFREG },
|
||||
{ S_IFDIR, NFDIR },
|
||||
{ S_IFBLK, NFBLK },
|
||||
{ S_IFCHR, NFCHR },
|
||||
{ S_IFLNK, NFLNK },
|
||||
{ S_IFSOCK, NFSOCK },
|
||||
{ S_IFIFO, NFFIFO },
|
||||
{ 0, NFNON },
|
||||
{ 0, NFNON },
|
||||
static const umode_t nfs_type2fmt[] = {
|
||||
[NF4BAD] = 0,
|
||||
[NF4REG] = S_IFREG,
|
||||
[NF4DIR] = S_IFDIR,
|
||||
[NF4BLK] = S_IFBLK,
|
||||
[NF4CHR] = S_IFCHR,
|
||||
[NF4LNK] = S_IFLNK,
|
||||
[NF4SOCK] = S_IFSOCK,
|
||||
[NF4FIFO] = S_IFIFO,
|
||||
[NF4ATTRDIR] = 0,
|
||||
[NF4NAMEDATTR] = 0,
|
||||
};
|
||||
|
||||
struct compound_hdr {
|
||||
@@ -2160,6 +2157,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
|
||||
static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*type = 0;
|
||||
if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
|
||||
@@ -2172,14 +2170,16 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
|
||||
return -EIO;
|
||||
}
|
||||
bitmap[0] &= ~FATTR4_WORD0_TYPE;
|
||||
ret = NFS_ATTR_FATTR_TYPE;
|
||||
}
|
||||
dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type].nfs2type);
|
||||
return 0;
|
||||
dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*change = 0;
|
||||
if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
|
||||
@@ -2188,15 +2188,17 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
|
||||
READ_BUF(8);
|
||||
READ64(*change);
|
||||
bitmap[0] &= ~FATTR4_WORD0_CHANGE;
|
||||
ret = NFS_ATTR_FATTR_CHANGE;
|
||||
}
|
||||
dprintk("%s: change attribute=%Lu\n", __func__,
|
||||
(unsigned long long)*change);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*size = 0;
|
||||
if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
|
||||
@@ -2205,9 +2207,10 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *
|
||||
READ_BUF(8);
|
||||
READ64(*size);
|
||||
bitmap[0] &= ~FATTR4_WORD0_SIZE;
|
||||
ret = NFS_ATTR_FATTR_SIZE;
|
||||
}
|
||||
dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
|
||||
@@ -2245,6 +2248,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
fsid->major = 0;
|
||||
fsid->minor = 0;
|
||||
@@ -2255,11 +2259,12 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs
|
||||
READ64(fsid->major);
|
||||
READ64(fsid->minor);
|
||||
bitmap[0] &= ~FATTR4_WORD0_FSID;
|
||||
ret = NFS_ATTR_FATTR_FSID;
|
||||
}
|
||||
dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
|
||||
(unsigned long long)fsid->major,
|
||||
(unsigned long long)fsid->minor);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
|
||||
@@ -2297,6 +2302,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
|
||||
static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*fileid = 0;
|
||||
if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
|
||||
@@ -2305,14 +2311,16 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
|
||||
READ_BUF(8);
|
||||
READ64(*fileid);
|
||||
bitmap[0] &= ~FATTR4_WORD0_FILEID;
|
||||
ret = NFS_ATTR_FATTR_FILEID;
|
||||
}
|
||||
dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*fileid = 0;
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
|
||||
@@ -2321,9 +2329,10 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
|
||||
READ_BUF(8);
|
||||
READ64(*fileid);
|
||||
bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
|
||||
ret = NFS_ATTR_FATTR_FILEID;
|
||||
}
|
||||
dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
|
||||
@@ -2479,6 +2488,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
|
||||
if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
|
||||
res->nlocations++;
|
||||
}
|
||||
if (res->nlocations != 0)
|
||||
status = NFS_ATTR_FATTR_V4_REFERRAL;
|
||||
out:
|
||||
dprintk("%s: fs_locations done, error = %d\n", __func__, status);
|
||||
return status;
|
||||
@@ -2580,26 +2591,30 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32
|
||||
return status;
|
||||
}
|
||||
|
||||
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
|
||||
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
|
||||
{
|
||||
uint32_t tmp;
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*mode = 0;
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
|
||||
return -EIO;
|
||||
if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
|
||||
READ_BUF(4);
|
||||
READ32(*mode);
|
||||
*mode &= ~S_IFMT;
|
||||
READ32(tmp);
|
||||
*mode = tmp & ~S_IFMT;
|
||||
bitmap[1] &= ~FATTR4_WORD1_MODE;
|
||||
ret = NFS_ATTR_FATTR_MODE;
|
||||
}
|
||||
dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*nlink = 1;
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
|
||||
@@ -2608,15 +2623,17 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
|
||||
READ_BUF(4);
|
||||
READ32(*nlink);
|
||||
bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
|
||||
ret = NFS_ATTR_FATTR_NLINK;
|
||||
}
|
||||
dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid)
|
||||
{
|
||||
uint32_t len;
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*uid = -2;
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
|
||||
@@ -2626,7 +2643,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
|
||||
READ32(len);
|
||||
READ_BUF(len);
|
||||
if (len < XDR_MAX_NETOBJ) {
|
||||
if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
|
||||
if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
|
||||
ret = NFS_ATTR_FATTR_OWNER;
|
||||
else
|
||||
dprintk("%s: nfs_map_name_to_uid failed!\n",
|
||||
__func__);
|
||||
} else
|
||||
@@ -2635,13 +2654,14 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
|
||||
bitmap[1] &= ~FATTR4_WORD1_OWNER;
|
||||
}
|
||||
dprintk("%s: uid=%d\n", __func__, (int)*uid);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid)
|
||||
{
|
||||
uint32_t len;
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*gid = -2;
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
|
||||
@@ -2651,7 +2671,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
|
||||
READ32(len);
|
||||
READ_BUF(len);
|
||||
if (len < XDR_MAX_NETOBJ) {
|
||||
if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
|
||||
if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
|
||||
ret = NFS_ATTR_FATTR_GROUP;
|
||||
else
|
||||
dprintk("%s: nfs_map_group_to_gid failed!\n",
|
||||
__func__);
|
||||
} else
|
||||
@@ -2660,13 +2682,14 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
|
||||
bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
|
||||
}
|
||||
dprintk("%s: gid=%d\n", __func__, (int)*gid);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
|
||||
{
|
||||
uint32_t major = 0, minor = 0;
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*rdev = MKDEV(0,0);
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
|
||||
@@ -2681,9 +2704,10 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde
|
||||
if (MAJOR(tmp) == major && MINOR(tmp) == minor)
|
||||
*rdev = tmp;
|
||||
bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
|
||||
ret = NFS_ATTR_FATTR_RDEV;
|
||||
}
|
||||
dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
|
||||
@@ -2740,6 +2764,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
|
||||
static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
|
||||
{
|
||||
__be32 *p;
|
||||
int ret = 0;
|
||||
|
||||
*used = 0;
|
||||
if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
|
||||
@@ -2748,10 +2773,11 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
|
||||
READ_BUF(8);
|
||||
READ64(*used);
|
||||
bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
|
||||
ret = NFS_ATTR_FATTR_SPACE_USED;
|
||||
}
|
||||
dprintk("%s: space used=%Lu\n", __func__,
|
||||
(unsigned long long)*used);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
|
||||
@@ -2778,6 +2804,8 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
|
||||
return -EIO;
|
||||
if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
|
||||
status = decode_attr_time(xdr, time);
|
||||
if (status == 0)
|
||||
status = NFS_ATTR_FATTR_ATIME;
|
||||
bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
|
||||
}
|
||||
dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
|
||||
@@ -2794,6 +2822,8 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
|
||||
return -EIO;
|
||||
if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
|
||||
status = decode_attr_time(xdr, time);
|
||||
if (status == 0)
|
||||
status = NFS_ATTR_FATTR_CTIME;
|
||||
bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
|
||||
}
|
||||
dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
|
||||
@@ -2810,6 +2840,8 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
|
||||
return -EIO;
|
||||
if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
|
||||
status = decode_attr_time(xdr, time);
|
||||
if (status == 0)
|
||||
status = NFS_ATTR_FATTR_MTIME;
|
||||
bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
|
||||
}
|
||||
dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
|
||||
@@ -2994,63 +3026,116 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
|
||||
uint32_t attrlen,
|
||||
bitmap[2] = {0},
|
||||
type;
|
||||
int status, fmode = 0;
|
||||
int status;
|
||||
umode_t fmode = 0;
|
||||
uint64_t fileid;
|
||||
|
||||
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
|
||||
status = decode_op_hdr(xdr, OP_GETATTR);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
|
||||
fattr->bitmap[0] = bitmap[0];
|
||||
fattr->bitmap[1] = bitmap[1];
|
||||
status = decode_attr_bitmap(xdr, bitmap);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
|
||||
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
|
||||
status = decode_attr_length(xdr, &attrlen, &savep);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
|
||||
|
||||
if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
|
||||
status = decode_attr_type(xdr, bitmap, &type);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
fattr->type = nfs_type2fmt[type].nfs2type;
|
||||
fmode = nfs_type2fmt[type].mode;
|
||||
fattr->mode = 0;
|
||||
if (status != 0) {
|
||||
fattr->mode |= nfs_type2fmt[type];
|
||||
fattr->valid |= status;
|
||||
}
|
||||
|
||||
if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
|
||||
status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_size(xdr, bitmap, &fattr->size);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
|
||||
struct nfs4_fs_locations,
|
||||
fattr))) != 0)
|
||||
fattr));
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_mode(xdr, bitmap, &fmode);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
fattr->mode |= fmode;
|
||||
if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
|
||||
if (status != 0) {
|
||||
fattr->mode |= fmode;
|
||||
fattr->valid |= status;
|
||||
}
|
||||
|
||||
status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
|
||||
fattr->valid |= status;
|
||||
|
||||
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
|
||||
if (status < 0)
|
||||
goto xdr_error;
|
||||
if (fattr->fileid == 0 && fileid != 0)
|
||||
if (status != 0 && !(fattr->valid & status)) {
|
||||
fattr->fileid = fileid;
|
||||
if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
|
||||
fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
|
||||
fattr->valid |= status;
|
||||
}
|
||||
|
||||
status = verify_attr_len(xdr, savep, attrlen);
|
||||
xdr_error:
|
||||
dprintk("%s: xdr returned %d\n", __func__, -status);
|
||||
return status;
|
||||
@@ -4078,9 +4163,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se
|
||||
status = decode_setattr(&xdr, res);
|
||||
if (status)
|
||||
goto out;
|
||||
status = decode_getfattr(&xdr, res->fattr, res->server);
|
||||
if (status == NFS4ERR_DELAY)
|
||||
status = 0;
|
||||
decode_getfattr(&xdr, res->fattr, res->server);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
@@ -176,17 +176,6 @@ void nfs_release_request(struct nfs_page *req)
|
||||
kref_put(&req->wb_kref, nfs_free_request);
|
||||
}
|
||||
|
||||
static int nfs_wait_bit_killable(void *word)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fatal_signal_pending(current))
|
||||
ret = -ERESTARTSYS;
|
||||
else
|
||||
schedule();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs_wait_on_request - Wait for a request to complete.
|
||||
* @req: request to wait upon.
|
||||
|
@@ -663,4 +663,5 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
|
||||
.commit_setup = nfs_proc_commit_setup,
|
||||
.lock = nfs_proc_lock,
|
||||
.lock_check_bounds = nfs_lock_check_bounds,
|
||||
.close_context = nfs_close_context,
|
||||
};
|
||||
|
@@ -1018,6 +1018,7 @@ static int nfs_parse_mount_options(char *raw,
|
||||
case Opt_rdma:
|
||||
mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
|
||||
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
|
||||
xprt_load_transport(p);
|
||||
break;
|
||||
case Opt_acl:
|
||||
mnt->flags &= ~NFS_MOUNT_NOACL;
|
||||
@@ -1205,12 +1206,14 @@ static int nfs_parse_mount_options(char *raw,
|
||||
/* vector side protocols to TCP */
|
||||
mnt->flags |= NFS_MOUNT_TCP;
|
||||
mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
|
||||
xprt_load_transport(string);
|
||||
break;
|
||||
default:
|
||||
errors++;
|
||||
dfprintk(MOUNT, "NFS: unrecognized "
|
||||
"transport protocol\n");
|
||||
}
|
||||
kfree(string);
|
||||
break;
|
||||
case Opt_mountproto:
|
||||
string = match_strdup(args);
|
||||
@@ -1218,7 +1221,6 @@ static int nfs_parse_mount_options(char *raw,
|
||||
goto out_nomem;
|
||||
token = match_token(string,
|
||||
nfs_xprt_protocol_tokens, args);
|
||||
kfree(string);
|
||||
|
||||
switch (token) {
|
||||
case Opt_xprt_udp:
|
||||
|
@@ -313,19 +313,34 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control *
|
||||
int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
unsigned long *bitlock = &NFS_I(inode)->flags;
|
||||
struct nfs_pageio_descriptor pgio;
|
||||
int err;
|
||||
|
||||
/* Stop dirtying of new pages while we sync */
|
||||
err = wait_on_bit_lock(bitlock, NFS_INO_FLUSHING,
|
||||
nfs_wait_bit_killable, TASK_KILLABLE);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
|
||||
|
||||
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
|
||||
err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
|
||||
nfs_pageio_complete(&pgio);
|
||||
|
||||
clear_bit_unlock(NFS_INO_FLUSHING, bitlock);
|
||||
smp_mb__after_clear_bit();
|
||||
wake_up_bit(bitlock, NFS_INO_FLUSHING);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (pgio.pg_error < 0)
|
||||
return pgio.pg_error;
|
||||
goto out_err;
|
||||
err = pgio.pg_error;
|
||||
if (err < 0)
|
||||
goto out_err;
|
||||
return 0;
|
||||
out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -404,7 +419,6 @@ nfs_mark_request_commit(struct nfs_page *req)
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
nfsi->ncommit++;
|
||||
set_bit(PG_CLEAN, &(req)->wb_flags);
|
||||
radix_tree_tag_set(&nfsi->nfs_page_tree,
|
||||
req->wb_index,
|
||||
@@ -524,6 +538,12 @@ static void nfs_cancel_commit_list(struct list_head *head)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
|
||||
static int
|
||||
nfs_need_commit(struct nfs_inode *nfsi)
|
||||
{
|
||||
return radix_tree_tagged(&nfsi->nfs_page_tree, NFS_PAGE_TAG_COMMIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_scan_commit - Scan an inode for commit requests
|
||||
* @inode: NFS inode to scan
|
||||
@@ -538,16 +558,18 @@ static int
|
||||
nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
|
||||
{
|
||||
struct nfs_inode *nfsi = NFS_I(inode);
|
||||
int res = 0;
|
||||
|
||||
if (nfsi->ncommit != 0) {
|
||||
res = nfs_scan_list(nfsi, dst, idx_start, npages,
|
||||
NFS_PAGE_TAG_COMMIT);
|
||||
nfsi->ncommit -= res;
|
||||
}
|
||||
return res;
|
||||
if (!nfs_need_commit(nfsi))
|
||||
return 0;
|
||||
|
||||
return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT);
|
||||
}
|
||||
#else
|
||||
static inline int nfs_need_commit(struct nfs_inode *nfsi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
|
||||
{
|
||||
return 0;
|
||||
@@ -820,7 +842,7 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
|
||||
data->args.stable = NFS_UNSTABLE;
|
||||
if (how & FLUSH_STABLE) {
|
||||
data->args.stable = NFS_DATA_SYNC;
|
||||
if (!NFS_I(inode)->ncommit)
|
||||
if (!nfs_need_commit(NFS_I(inode)))
|
||||
data->args.stable = NFS_FILE_SYNC;
|
||||
}
|
||||
|
||||
@@ -1425,18 +1447,13 @@ static int nfs_write_mapping(struct address_space *mapping, int how)
|
||||
{
|
||||
struct writeback_control wbc = {
|
||||
.bdi = mapping->backing_dev_info,
|
||||
.sync_mode = WB_SYNC_NONE,
|
||||
.sync_mode = WB_SYNC_ALL,
|
||||
.nr_to_write = LONG_MAX,
|
||||
.range_start = 0,
|
||||
.range_end = LLONG_MAX,
|
||||
.for_writepages = 1,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = __nfs_write_mapping(mapping, &wbc, how);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
wbc.sync_mode = WB_SYNC_ALL;
|
||||
return __nfs_write_mapping(mapping, &wbc, how);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user