Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1823acf authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
  NFS: Fix the fix to Bugzilla #11061, when IPv6 isn't defined...
  SUNRPC: xprt_connect() don't abort the task if the transport isn't bound
  SUNRPC: Fix an Oops due to socket not set up yet...
  Bug 11061, NFS mounts dropped
  NFS: Handle -ESTALE error in access()
  NLM: Fix GRANT callback address comparison when IPv6 is enabled
  NLM: Shrink the IPv4-only version of nlm_cmp_addr()
  NFSv3: Fix posix ACL code
  NFS: Fix misparsing of nfsv4 fs_locations attribute (take 2)
  SUNRPC: Tighten up the task locking rules in __rpc_execute()
parents ff9cb43c 9f4c899c
Loading
Loading
Loading
Loading
+50 −1
Original line number Diff line number Diff line
@@ -139,6 +139,55 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
	return 0;
}

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap,
						 struct in6_addr *addr_mapped)
{
	const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;

	switch (sap->sa_family) {
	case AF_INET6:
		return &((const struct sockaddr_in6 *)sap)->sin6_addr;
	case AF_INET:
		ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped);
		return addr_mapped;
	}

	return NULL;
}

/*
 * If lockd is using a PF_INET6 listener, all incoming requests appear
 * to come from AF_INET6 remotes.  The address of AF_INET remotes are
 * mapped to AF_INET6 automatically by the network layer.  In case the
 * user passed an AF_INET server address at mount time, ensure both
 * addresses are AF_INET6 before comparing them.
 */
static int nlmclnt_cmp_addr(const struct nlm_host *host,
			    const struct sockaddr *sap)
{
	const struct in6_addr *addr1;
	const struct in6_addr *addr2;
	struct in6_addr addr1_mapped;
	struct in6_addr addr2_mapped;

	addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped);
	if (likely(addr1 != NULL)) {
		addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped);
		if (likely(addr2 != NULL))
			return ipv6_addr_equal(addr1, addr2);
	}

	return 0;
}
#else	/* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static int nlmclnt_cmp_addr(const struct nlm_host *host,
			    const struct sockaddr *sap)
{
	return nlm_cmp_addr(nlm_addr(host), sap);
}
#endif	/* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */

/*
 * The server lockd has called us back to tell us the lock was granted
 */
@@ -166,7 +215,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
		 */
		if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
			continue;
		if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
		if (!nlmclnt_cmp_addr(block->b_host, addr))
			continue;
		if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
			continue;
+72 −1
Original line number Diff line number Diff line
@@ -255,6 +255,32 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
	}
	return 0;
}

/*
 * Test if two ip6 socket addresses refer to the same socket by
 * comparing relevant fields. The padding bytes specifically, are not
 * compared. sin6_flowinfo is not compared because it only affects QoS
 * and sin6_scope_id is only compared if the address is "link local"
 * because "link local" addresses need only be unique to a specific
 * link. Conversely, ordinary unicast addresses might have different
 * sin6_scope_id.
 *
 * The caller should ensure both socket addresses are AF_INET6.
 */
static int nfs_sockaddr_cmp_ip6(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;

	if (!ipv6_addr_equal(&saddr1->sin6_addr,
			     &saddr1->sin6_addr))
		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)
@@ -270,8 +296,51 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
	return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1,
			(const struct sockaddr_in *)sa2);
}

static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1,
				const struct sockaddr * sa2)
{
	return 0;
}
#endif

/*
 * Test if two ip4 socket addresses refer to the same socket, by
 * comparing relevant fields. The padding bytes specifically, are
 * not compared.
 *
 * The caller should ensure both socket addresses are AF_INET.
 */
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;

	if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr)
		return 0;
	return saddr1->sin_port == saddr2->sin_port;
}

/*
 * Test if two socket addresses represent the same actual socket,
 * by comparing (only) relevant fields.
 */
static int nfs_sockaddr_cmp(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_cmp_ip4(sa1, sa2);
	case AF_INET6:
		return nfs_sockaddr_cmp_ip6(sa1, sa2);
	}
	return 0;
}

/*
 * Find a client by IP address and protocol version
 * - returns NULL if no such client
@@ -344,8 +413,10 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
{
	struct nfs_client *clp;
	const struct sockaddr *sap = data->addr;

	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
	        const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
		/* Don't match clients that failed to initialise properly */
		if (clp->cl_cons_state < 0)
			continue;
@@ -358,7 +429,7 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
			continue;

		/* Match the full socket address */
		if (memcmp(&clp->cl_addr, data->addr, sizeof(clp->cl_addr)) != 0)
		if (!nfs_sockaddr_cmp(sap, clap))
			continue;

		atomic_inc(&clp->cl_count);
+7 −1
Original line number Diff line number Diff line
@@ -1892,8 +1892,14 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
	cache.cred = cred;
	cache.jiffies = jiffies;
	status = NFS_PROTO(inode)->access(inode, &cache);
	if (status != 0)
	if (status != 0) {
		if (status == -ESTALE) {
			nfs_zap_caches(inode);
			if (!S_ISDIR(inode->i_mode))
				set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
		}
		return status;
	}
	nfs_access_add_cache(inode, &cache);
out:
	if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
+21 −6
Original line number Diff line number Diff line
@@ -292,7 +292,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
{
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_fattr fattr;
	struct page *pages[NFSACL_MAXPAGES] = { };
	struct page *pages[NFSACL_MAXPAGES];
	struct nfs3_setaclargs args = {
		.inode = inode,
		.mask = NFS_ACL,
@@ -303,7 +303,7 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
		.rpc_argp	= &args,
		.rpc_resp	= &fattr,
	};
	int status, count;
	int status;

	status = -EOPNOTSUPP;
	if (!nfs_server_capable(inode, NFS_CAP_ACLS))
@@ -319,6 +319,20 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
	if (S_ISDIR(inode->i_mode)) {
		args.mask |= NFS_DFACL;
		args.acl_default = dfacl;
		args.len = nfsacl_size(acl, dfacl);
	} else
		args.len = nfsacl_size(acl, NULL);

	if (args.len > NFS_ACL_INLINE_BUFSIZE) {
		unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);

		status = -ENOMEM;
		do {
			args.pages[args.npages] = alloc_page(GFP_KERNEL);
			if (args.pages[args.npages] == NULL)
				goto out_freepages;
			args.npages++;
		} while (args.npages < npages);
	}

	dprintk("NFS call setacl\n");
@@ -329,10 +343,6 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
	nfs_zap_acl_cache(inode);
	dprintk("NFS reply setacl: %d\n", status);

	/* pages may have been allocated at the xdr layer. */
	for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
		__free_page(args.pages[count]);

	switch (status) {
		case 0:
			status = nfs_refresh_inode(inode, &fattr);
@@ -346,6 +356,11 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
		case -ENOTSUPP:
			status = -EOPNOTSUPP;
	}
out_freepages:
	while (args.npages != 0) {
		args.npages--;
		__free_page(args.pages[args.npages]);
	}
out:
	return status;
}
+13 −21
Original line number Diff line number Diff line
@@ -82,8 +82,10 @@
#define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)

#define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
#define ACL3_setaclargs_sz	(NFS3_fh_sz+1+2*(2+5*3))
#define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+2*(2+5*3))
#define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
#define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
#define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)

/*
@@ -703,28 +705,18 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
                   struct nfs3_setaclargs *args)
{
	struct xdr_buf *buf = &req->rq_snd_buf;
	unsigned int base, len_in_head, len = nfsacl_size(
		(args->mask & NFS_ACL)   ? args->acl_access  : NULL,
		(args->mask & NFS_DFACL) ? args->acl_default : NULL);
	int count, err;
	unsigned int base;
	int err;

	p = xdr_encode_fhandle(p, NFS_FH(args->inode));
	*p++ = htonl(args->mask);
	base = (char *)p - (char *)buf->head->iov_base;
	/* put as much of the acls into head as possible. */
	len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
	len -= len_in_head;
	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
	base = req->rq_slen;

	for (count = 0; (count << PAGE_SHIFT) < len; count++) {
		args->pages[count] = alloc_page(GFP_KERNEL);
		if (!args->pages[count]) {
			while (count)
				__free_page(args->pages[--count]);
			return -ENOMEM;
		}
	}
	xdr_encode_pages(buf, args->pages, 0, len);
	if (args->npages != 0)
		xdr_encode_pages(buf, args->pages, 0, args->len);
	else
		req->rq_slen += args->len;

	err = nfsacl_encode(buf, base, args->inode,
			    (args->mask & NFS_ACL) ?
Loading