diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e98b1f755e95..3022454f7698 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -565,7 +565,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA) nfsi->uncacheable_file_data = fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA; - else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA) + else if (S_ISREG(inode->i_mode) && + (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)) nfs_set_cache_invalid(inode, NFS_INO_INVALID_UNCACHEABLE_FILE_DATA); nfs_setsecurity(inode, fattr); @@ -2471,7 +2472,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) if (fattr->valid & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA) nfsi->uncacheable_file_data = fattr->aux_flags & NFS_AUX_UNCACHEABLE_FILE_DATA; - else if (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA) + else if (S_ISREG(inode->i_mode) && + (fattr_supported & NFS_ATTR_FATTR_UNCACHEABLE_FILE_DATA)) nfsi->cache_validity |= save_cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 59f6a38bfb5c..62fc7034e0ac 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -308,6 +308,15 @@ static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src, unsigned long cache_validity; memcpy(dst, src, NFS4_BITMASK_SZ*sizeof(*dst)); + /* + * The uncacheable_file_data attribute applies only to regular files + * (NF4REG); a server must reject a query of it on any other object + * type with NFS4ERR_INVAL. Never request it unless the target is + * known to be a regular file (callers with an unknown object type, + * e.g. LOOKUP, pass a NULL inode). + */ + if (!inode || !S_ISREG(inode->i_mode)) + dst[2] &= ~FATTR4_WORD2_UNCACHEABLE_FILE_DATA; if (!inode || !nfs_have_read_or_write_delegation(inode)) return; @@ -1243,7 +1252,7 @@ nfs4_update_changeattr_locked(struct inode *inode, NFS_INO_INVALID_SIZE | NFS_INO_INVALID_OTHER | NFS_INO_INVALID_BLOCKS | NFS_INO_INVALID_NLINK | NFS_INO_INVALID_MODE | NFS_INO_INVALID_BTIME | - NFS_INO_INVALID_XATTR | NFS_INO_INVALID_UNCACHEABLE_FILE_DATA; + NFS_INO_INVALID_XATTR; nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); } nfsi->attrtimeo_timestamp = jiffies; @@ -4598,6 +4607,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, .rpc_resp = &res, }; unsigned short task_flags = 0; + __u32 bitmask[NFS4_BITMASK_SZ]; if (nfs_server_capable(dir, NFS_CAP_MOVEABLE)) task_flags = RPC_TASK_MOVEABLE; @@ -4606,7 +4616,13 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, if (nfs_lookup_is_soft_revalidate(dentry)) task_flags |= RPC_TASK_TIMEOUT; - args.bitmask = nfs4_bitmask(server, fattr->label); + /* + * The looked-up object's type is unknown here, so gate out the + * regular-file-only uncacheable_file_data attribute (NULL inode). + */ + nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), + NULL, 0); + args.bitmask = bitmask; nfs_fattr_init(fattr); @@ -4720,13 +4736,20 @@ static int _nfs4_proc_lookupp(struct inode *inode, .rpc_resp = &res, }; unsigned short task_flags = 0; + __u32 bitmask[NFS4_BITMASK_SZ]; if (server->flags & NFS_MOUNT_SOFTREVAL) task_flags |= RPC_TASK_TIMEOUT; if (server->caps & NFS_CAP_MOVEABLE) task_flags |= RPC_TASK_MOVEABLE; - args.bitmask = nfs4_bitmask(server, fattr->label); + /* + * The looked-up object's type is unknown here, so gate out the + * regular-file-only uncacheable_file_data attribute (NULL inode). + */ + nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), + NULL, 0); + args.bitmask = bitmask; nfs_fattr_init(fattr); nfs4_init_sequence(server->nfs_client, &args.seq_args, &res.seq_res, 0, 0); @@ -5141,6 +5164,7 @@ struct nfs4_createdata { struct nfs4_create_res res; struct nfs_fh fh; struct nfs_fattr fattr; + u32 bitmask[NFS4_BITMASK_SZ]; }; static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, @@ -5164,7 +5188,14 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, data->arg.name = name; data->arg.attrs = sattr; data->arg.ftype = ftype; - data->arg.bitmask = nfs4_bitmask(server, data->fattr.label); + /* + * CREATE only makes non-regular objects, so gate out the + * regular-file-only uncacheable_file_data attribute (NULL inode). + */ + nfs4_bitmap_copy_adjust(data->bitmask, + nfs4_bitmask(server, data->fattr.label), + NULL, 0); + data->arg.bitmask = data->bitmask; data->arg.umask = current_umask(); data->res.server = server; data->res.fh = &data->fh; @@ -5816,7 +5847,12 @@ void nfs4_bitmask_set(__u32 bitmask[], const __u32 src[], bitmask[1] |= FATTR4_WORD1_SPACE_USED; if (cache_validity & NFS_INO_INVALID_BTIME) bitmask[1] |= FATTR4_WORD1_TIME_CREATE; - if (cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA) + /* + * uncacheable_file_data (attr 87) applies only to regular files; a + * directory can reach here via DELEGRETURN of a directory delegation. + */ + if ((cache_validity & NFS_INO_INVALID_UNCACHEABLE_FILE_DATA) && + S_ISREG(inode->i_mode)) bitmask[2] |= FATTR4_WORD2_UNCACHEABLE_FILE_DATA; if (cache_validity & NFS_INO_INVALID_SIZE)