.. | .. |
---|
40 | 40 | #include <linux/utsname.h> |
---|
41 | 41 | #include <linux/pagemap.h> |
---|
42 | 42 | #include <linux/sunrpc/svcauth_gss.h> |
---|
| 43 | +#include <linux/sunrpc/addr.h> |
---|
| 44 | +#include <linux/xattr.h> |
---|
| 45 | +#include <uapi/linux/xattr.h> |
---|
43 | 46 | |
---|
44 | 47 | #include "idmap.h" |
---|
45 | 48 | #include "acl.h" |
---|
.. | .. |
---|
49 | 52 | #include "cache.h" |
---|
50 | 53 | #include "netns.h" |
---|
51 | 54 | #include "pnfs.h" |
---|
| 55 | +#include "filecache.h" |
---|
52 | 56 | |
---|
53 | 57 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
---|
54 | 58 | #include <linux/security.h> |
---|
.. | .. |
---|
203 | 207 | return p; |
---|
204 | 208 | } |
---|
205 | 209 | |
---|
| 210 | +static unsigned int compoundargs_bytes_left(struct nfsd4_compoundargs *argp) |
---|
| 211 | +{ |
---|
| 212 | + unsigned int this = (char *)argp->end - (char *)argp->p; |
---|
| 213 | + |
---|
| 214 | + return this + argp->pagelen; |
---|
| 215 | +} |
---|
| 216 | + |
---|
206 | 217 | static int zero_clientid(clientid_t *clid) |
---|
207 | 218 | { |
---|
208 | 219 | return (clid->cl_boot == 0) && (clid->cl_id == 0); |
---|
.. | .. |
---|
211 | 222 | /** |
---|
212 | 223 | * svcxdr_tmpalloc - allocate memory to be freed after compound processing |
---|
213 | 224 | * @argp: NFSv4 compound argument structure |
---|
214 | | - * @p: pointer to be freed (with kfree()) |
---|
| 225 | + * @len: length of buffer to allocate |
---|
215 | 226 | * |
---|
216 | | - * Marks @p to be freed when processing the compound operation |
---|
217 | | - * described in @argp finishes. |
---|
| 227 | + * Allocates a buffer of size @len to be freed when processing the compound |
---|
| 228 | + * operation described in @argp finishes. |
---|
218 | 229 | */ |
---|
219 | 230 | static void * |
---|
220 | 231 | svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len) |
---|
.. | .. |
---|
248 | 259 | return p; |
---|
249 | 260 | } |
---|
250 | 261 | |
---|
| 262 | +static __be32 |
---|
| 263 | +svcxdr_construct_vector(struct nfsd4_compoundargs *argp, struct kvec *head, |
---|
| 264 | + struct page ***pagelist, u32 buflen) |
---|
| 265 | +{ |
---|
| 266 | + int avail; |
---|
| 267 | + int len; |
---|
| 268 | + int pages; |
---|
| 269 | + |
---|
| 270 | + /* Sorry .. no magic macros for this.. * |
---|
| 271 | + * READ_BUF(write->wr_buflen); |
---|
| 272 | + * SAVEMEM(write->wr_buf, write->wr_buflen); |
---|
| 273 | + */ |
---|
| 274 | + avail = (char *)argp->end - (char *)argp->p; |
---|
| 275 | + if (avail + argp->pagelen < buflen) { |
---|
| 276 | + dprintk("NFSD: xdr error (%s:%d)\n", |
---|
| 277 | + __FILE__, __LINE__); |
---|
| 278 | + return nfserr_bad_xdr; |
---|
| 279 | + } |
---|
| 280 | + head->iov_base = argp->p; |
---|
| 281 | + head->iov_len = avail; |
---|
| 282 | + *pagelist = argp->pagelist; |
---|
| 283 | + |
---|
| 284 | + len = XDR_QUADLEN(buflen) << 2; |
---|
| 285 | + if (len >= avail) { |
---|
| 286 | + len -= avail; |
---|
| 287 | + |
---|
| 288 | + pages = len >> PAGE_SHIFT; |
---|
| 289 | + argp->pagelist += pages; |
---|
| 290 | + argp->pagelen -= pages * PAGE_SIZE; |
---|
| 291 | + len -= pages * PAGE_SIZE; |
---|
| 292 | + |
---|
| 293 | + next_decode_page(argp); |
---|
| 294 | + } |
---|
| 295 | + argp->p += XDR_QUADLEN(len); |
---|
| 296 | + |
---|
| 297 | + return 0; |
---|
| 298 | +} |
---|
| 299 | + |
---|
251 | 300 | /** |
---|
252 | 301 | * savemem - duplicate a chunk of memory for later processing |
---|
253 | 302 | * @argp: NFSv4 compound argument structure to be freed with |
---|
.. | .. |
---|
269 | 318 | return ret; |
---|
270 | 319 | } |
---|
271 | 320 | |
---|
272 | | -/* |
---|
273 | | - * We require the high 32 bits of 'seconds' to be 0, and |
---|
274 | | - * we ignore all 32 bits of 'nseconds'. |
---|
275 | | - */ |
---|
276 | 321 | static __be32 |
---|
277 | | -nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec *tv) |
---|
| 322 | +nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv) |
---|
278 | 323 | { |
---|
279 | 324 | DECODE_HEAD; |
---|
280 | | - u64 sec; |
---|
281 | 325 | |
---|
282 | 326 | READ_BUF(12); |
---|
283 | | - p = xdr_decode_hyper(p, &sec); |
---|
284 | | - tv->tv_sec = sec; |
---|
| 327 | + p = xdr_decode_hyper(p, &tv->tv_sec); |
---|
285 | 328 | tv->tv_nsec = be32_to_cpup(p++); |
---|
286 | 329 | if (tv->tv_nsec >= (u32)1000000000) |
---|
287 | 330 | return nfserr_inval; |
---|
.. | .. |
---|
320 | 363 | struct iattr *iattr, struct nfs4_acl **acl, |
---|
321 | 364 | struct xdr_netobj *label, int *umask) |
---|
322 | 365 | { |
---|
323 | | - struct timespec ts; |
---|
324 | 366 | int expected_len, len = 0; |
---|
325 | 367 | u32 dummy32; |
---|
326 | 368 | char *buf; |
---|
.. | .. |
---|
354 | 396 | READ_BUF(4); len += 4; |
---|
355 | 397 | nace = be32_to_cpup(p++); |
---|
356 | 398 | |
---|
357 | | - if (nace > NFS4_ACL_MAX) |
---|
| 399 | + if (nace > compoundargs_bytes_left(argp)/20) |
---|
| 400 | + /* |
---|
| 401 | + * Even with 4-byte names there wouldn't be |
---|
| 402 | + * space for that many aces; something fishy is |
---|
| 403 | + * going on: |
---|
| 404 | + */ |
---|
358 | 405 | return nfserr_fbig; |
---|
359 | 406 | |
---|
360 | 407 | *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); |
---|
.. | .. |
---|
422 | 469 | switch (dummy32) { |
---|
423 | 470 | case NFS4_SET_TO_CLIENT_TIME: |
---|
424 | 471 | len += 12; |
---|
425 | | - status = nfsd4_decode_time(argp, &ts); |
---|
426 | | - iattr->ia_atime = timespec_to_timespec64(ts); |
---|
| 472 | + status = nfsd4_decode_time(argp, &iattr->ia_atime); |
---|
427 | 473 | if (status) |
---|
428 | 474 | return status; |
---|
429 | 475 | iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); |
---|
.. | .. |
---|
442 | 488 | switch (dummy32) { |
---|
443 | 489 | case NFS4_SET_TO_CLIENT_TIME: |
---|
444 | 490 | len += 12; |
---|
445 | | - status = nfsd4_decode_time(argp, &ts); |
---|
446 | | - iattr->ia_mtime = timespec_to_timespec64(ts); |
---|
| 491 | + status = nfsd4_decode_time(argp, &iattr->ia_mtime); |
---|
447 | 492 | if (status) |
---|
448 | 493 | return status; |
---|
449 | 494 | iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); |
---|
.. | .. |
---|
521 | 566 | static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) |
---|
522 | 567 | { |
---|
523 | 568 | DECODE_HEAD; |
---|
| 569 | + struct user_namespace *userns = nfsd_user_namespace(argp->rqstp); |
---|
524 | 570 | u32 dummy, uid, gid; |
---|
525 | 571 | char *machine_name; |
---|
526 | 572 | int i; |
---|
.. | .. |
---|
563 | 609 | dummy = be32_to_cpup(p++); |
---|
564 | 610 | READ_BUF(dummy * 4); |
---|
565 | 611 | if (cbs->flavor == (u32)(-1)) { |
---|
566 | | - kuid_t kuid = make_kuid(&init_user_ns, uid); |
---|
567 | | - kgid_t kgid = make_kgid(&init_user_ns, gid); |
---|
| 612 | + kuid_t kuid = make_kuid(userns, uid); |
---|
| 613 | + kgid_t kgid = make_kgid(userns, gid); |
---|
568 | 614 | if (uid_valid(kuid) && gid_valid(kgid)) { |
---|
569 | 615 | cbs->uid = kuid; |
---|
570 | 616 | cbs->gid = kgid; |
---|
.. | .. |
---|
1259 | 1305 | static __be32 |
---|
1260 | 1306 | nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) |
---|
1261 | 1307 | { |
---|
1262 | | - int avail; |
---|
1263 | | - int len; |
---|
1264 | 1308 | DECODE_HEAD; |
---|
1265 | 1309 | |
---|
1266 | 1310 | status = nfsd4_decode_stateid(argp, &write->wr_stateid); |
---|
.. | .. |
---|
1273 | 1317 | goto xdr_error; |
---|
1274 | 1318 | write->wr_buflen = be32_to_cpup(p++); |
---|
1275 | 1319 | |
---|
1276 | | - /* Sorry .. no magic macros for this.. * |
---|
1277 | | - * READ_BUF(write->wr_buflen); |
---|
1278 | | - * SAVEMEM(write->wr_buf, write->wr_buflen); |
---|
1279 | | - */ |
---|
1280 | | - avail = (char*)argp->end - (char*)argp->p; |
---|
1281 | | - if (avail + argp->pagelen < write->wr_buflen) { |
---|
1282 | | - dprintk("NFSD: xdr error (%s:%d)\n", |
---|
1283 | | - __FILE__, __LINE__); |
---|
1284 | | - goto xdr_error; |
---|
1285 | | - } |
---|
1286 | | - write->wr_head.iov_base = p; |
---|
1287 | | - write->wr_head.iov_len = avail; |
---|
1288 | | - write->wr_pagelist = argp->pagelist; |
---|
1289 | | - |
---|
1290 | | - len = XDR_QUADLEN(write->wr_buflen) << 2; |
---|
1291 | | - if (len >= avail) { |
---|
1292 | | - int pages; |
---|
1293 | | - |
---|
1294 | | - len -= avail; |
---|
1295 | | - |
---|
1296 | | - pages = len >> PAGE_SHIFT; |
---|
1297 | | - argp->pagelist += pages; |
---|
1298 | | - argp->pagelen -= pages * PAGE_SIZE; |
---|
1299 | | - len -= pages * PAGE_SIZE; |
---|
1300 | | - |
---|
1301 | | - next_decode_page(argp); |
---|
1302 | | - } |
---|
1303 | | - argp->p += XDR_QUADLEN(len); |
---|
| 1320 | + status = svcxdr_construct_vector(argp, &write->wr_head, |
---|
| 1321 | + &write->wr_pagelist, write->wr_buflen); |
---|
| 1322 | + if (status) |
---|
| 1323 | + return status; |
---|
1304 | 1324 | |
---|
1305 | 1325 | DECODE_TAIL; |
---|
1306 | 1326 | } |
---|
.. | .. |
---|
1397 | 1417 | goto xdr_error; |
---|
1398 | 1418 | } |
---|
1399 | 1419 | |
---|
1400 | | - /* Ignore Implementation ID */ |
---|
1401 | 1420 | READ_BUF(4); /* nfs_impl_id4 array length */ |
---|
1402 | 1421 | dummy = be32_to_cpup(p++); |
---|
1403 | 1422 | |
---|
.. | .. |
---|
1405 | 1424 | goto xdr_error; |
---|
1406 | 1425 | |
---|
1407 | 1426 | if (dummy == 1) { |
---|
1408 | | - /* nii_domain */ |
---|
1409 | | - READ_BUF(4); |
---|
1410 | | - dummy = be32_to_cpup(p++); |
---|
1411 | | - READ_BUF(dummy); |
---|
1412 | | - p += XDR_QUADLEN(dummy); |
---|
| 1427 | + status = nfsd4_decode_opaque(argp, &exid->nii_domain); |
---|
| 1428 | + if (status) |
---|
| 1429 | + goto xdr_error; |
---|
1413 | 1430 | |
---|
1414 | 1431 | /* nii_name */ |
---|
1415 | | - READ_BUF(4); |
---|
1416 | | - dummy = be32_to_cpup(p++); |
---|
1417 | | - READ_BUF(dummy); |
---|
1418 | | - p += XDR_QUADLEN(dummy); |
---|
| 1432 | + status = nfsd4_decode_opaque(argp, &exid->nii_name); |
---|
| 1433 | + if (status) |
---|
| 1434 | + goto xdr_error; |
---|
1419 | 1435 | |
---|
1420 | 1436 | /* nii_date */ |
---|
1421 | | - READ_BUF(12); |
---|
1422 | | - p += 3; |
---|
| 1437 | + status = nfsd4_decode_time(argp, &exid->nii_time); |
---|
| 1438 | + if (status) |
---|
| 1439 | + goto xdr_error; |
---|
1423 | 1440 | } |
---|
1424 | 1441 | DECODE_TAIL; |
---|
1425 | 1442 | } |
---|
.. | .. |
---|
1429 | 1446 | struct nfsd4_create_session *sess) |
---|
1430 | 1447 | { |
---|
1431 | 1448 | DECODE_HEAD; |
---|
1432 | | - u32 dummy; |
---|
1433 | 1449 | |
---|
1434 | 1450 | READ_BUF(16); |
---|
1435 | 1451 | COPYMEM(&sess->clientid, 8); |
---|
.. | .. |
---|
1438 | 1454 | |
---|
1439 | 1455 | /* Fore channel attrs */ |
---|
1440 | 1456 | READ_BUF(28); |
---|
1441 | | - dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ |
---|
| 1457 | + p++; /* headerpadsz is always 0 */ |
---|
1442 | 1458 | sess->fore_channel.maxreq_sz = be32_to_cpup(p++); |
---|
1443 | 1459 | sess->fore_channel.maxresp_sz = be32_to_cpup(p++); |
---|
1444 | 1460 | sess->fore_channel.maxresp_cached = be32_to_cpup(p++); |
---|
.. | .. |
---|
1455 | 1471 | |
---|
1456 | 1472 | /* Back channel attrs */ |
---|
1457 | 1473 | READ_BUF(28); |
---|
1458 | | - dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */ |
---|
| 1474 | + p++; /* headerpadsz is always 0 */ |
---|
1459 | 1475 | sess->back_channel.maxreq_sz = be32_to_cpup(p++); |
---|
1460 | 1476 | sess->back_channel.maxresp_sz = be32_to_cpup(p++); |
---|
1461 | 1477 | sess->back_channel.maxresp_cached = be32_to_cpup(p++); |
---|
.. | .. |
---|
1743 | 1759 | DECODE_TAIL; |
---|
1744 | 1760 | } |
---|
1745 | 1761 | |
---|
| 1762 | +static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp, |
---|
| 1763 | + struct nl4_server *ns) |
---|
| 1764 | +{ |
---|
| 1765 | + DECODE_HEAD; |
---|
| 1766 | + struct nfs42_netaddr *naddr; |
---|
| 1767 | + |
---|
| 1768 | + READ_BUF(4); |
---|
| 1769 | + ns->nl4_type = be32_to_cpup(p++); |
---|
| 1770 | + |
---|
| 1771 | + /* currently support for 1 inter-server source server */ |
---|
| 1772 | + switch (ns->nl4_type) { |
---|
| 1773 | + case NL4_NETADDR: |
---|
| 1774 | + naddr = &ns->u.nl4_addr; |
---|
| 1775 | + |
---|
| 1776 | + READ_BUF(4); |
---|
| 1777 | + naddr->netid_len = be32_to_cpup(p++); |
---|
| 1778 | + if (naddr->netid_len > RPCBIND_MAXNETIDLEN) |
---|
| 1779 | + goto xdr_error; |
---|
| 1780 | + |
---|
| 1781 | + READ_BUF(naddr->netid_len + 4); /* 4 for uaddr len */ |
---|
| 1782 | + COPYMEM(naddr->netid, naddr->netid_len); |
---|
| 1783 | + |
---|
| 1784 | + naddr->addr_len = be32_to_cpup(p++); |
---|
| 1785 | + if (naddr->addr_len > RPCBIND_MAXUADDRLEN) |
---|
| 1786 | + goto xdr_error; |
---|
| 1787 | + |
---|
| 1788 | + READ_BUF(naddr->addr_len); |
---|
| 1789 | + COPYMEM(naddr->addr, naddr->addr_len); |
---|
| 1790 | + break; |
---|
| 1791 | + default: |
---|
| 1792 | + goto xdr_error; |
---|
| 1793 | + } |
---|
| 1794 | + DECODE_TAIL; |
---|
| 1795 | +} |
---|
| 1796 | + |
---|
1746 | 1797 | static __be32 |
---|
1747 | 1798 | nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) |
---|
1748 | 1799 | { |
---|
1749 | 1800 | DECODE_HEAD; |
---|
1750 | | - unsigned int tmp; |
---|
| 1801 | + struct nl4_server *ns_dummy; |
---|
| 1802 | + int i, count; |
---|
1751 | 1803 | |
---|
1752 | 1804 | status = nfsd4_decode_stateid(argp, ©->cp_src_stateid); |
---|
1753 | 1805 | if (status) |
---|
.. | .. |
---|
1762 | 1814 | p = xdr_decode_hyper(p, ©->cp_count); |
---|
1763 | 1815 | p++; /* ca_consecutive: we always do consecutive copies */ |
---|
1764 | 1816 | copy->cp_synchronous = be32_to_cpup(p++); |
---|
1765 | | - tmp = be32_to_cpup(p); /* Source server list not supported */ |
---|
| 1817 | + |
---|
| 1818 | + count = be32_to_cpup(p++); |
---|
| 1819 | + |
---|
| 1820 | + copy->cp_intra = false; |
---|
| 1821 | + if (count == 0) { /* intra-server copy */ |
---|
| 1822 | + copy->cp_intra = true; |
---|
| 1823 | + goto intra; |
---|
| 1824 | + } |
---|
| 1825 | + |
---|
| 1826 | + /* decode all the supplied server addresses but use first */ |
---|
| 1827 | + status = nfsd4_decode_nl4_server(argp, ©->cp_src); |
---|
| 1828 | + if (status) |
---|
| 1829 | + return status; |
---|
| 1830 | + |
---|
| 1831 | + ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL); |
---|
| 1832 | + if (ns_dummy == NULL) |
---|
| 1833 | + return nfserrno(-ENOMEM); |
---|
| 1834 | + for (i = 0; i < count - 1; i++) { |
---|
| 1835 | + status = nfsd4_decode_nl4_server(argp, ns_dummy); |
---|
| 1836 | + if (status) { |
---|
| 1837 | + kfree(ns_dummy); |
---|
| 1838 | + return status; |
---|
| 1839 | + } |
---|
| 1840 | + } |
---|
| 1841 | + kfree(ns_dummy); |
---|
| 1842 | +intra: |
---|
1766 | 1843 | |
---|
1767 | 1844 | DECODE_TAIL; |
---|
| 1845 | +} |
---|
| 1846 | + |
---|
| 1847 | +static __be32 |
---|
| 1848 | +nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, |
---|
| 1849 | + struct nfsd4_offload_status *os) |
---|
| 1850 | +{ |
---|
| 1851 | + return nfsd4_decode_stateid(argp, &os->stateid); |
---|
| 1852 | +} |
---|
| 1853 | + |
---|
| 1854 | +static __be32 |
---|
| 1855 | +nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, |
---|
| 1856 | + struct nfsd4_copy_notify *cn) |
---|
| 1857 | +{ |
---|
| 1858 | + __be32 status; |
---|
| 1859 | + |
---|
| 1860 | + status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid); |
---|
| 1861 | + if (status) |
---|
| 1862 | + return status; |
---|
| 1863 | + return nfsd4_decode_nl4_server(argp, &cn->cpn_dst); |
---|
1768 | 1864 | } |
---|
1769 | 1865 | |
---|
1770 | 1866 | static __be32 |
---|
.. | .. |
---|
1781 | 1877 | seek->seek_whence = be32_to_cpup(p); |
---|
1782 | 1878 | |
---|
1783 | 1879 | DECODE_TAIL; |
---|
| 1880 | +} |
---|
| 1881 | + |
---|
| 1882 | +/* |
---|
| 1883 | + * XDR data that is more than PAGE_SIZE in size is normally part of a |
---|
| 1884 | + * read or write. However, the size of extended attributes is limited |
---|
| 1885 | + * by the maximum request size, and then further limited by the underlying |
---|
| 1886 | + * filesystem limits. This can exceed PAGE_SIZE (currently, XATTR_SIZE_MAX |
---|
| 1887 | + * is 64k). Since there is no kvec- or page-based interface to xattrs, |
---|
| 1888 | + * and we're not dealing with contiguous pages, we need to do some copying. |
---|
| 1889 | + */ |
---|
| 1890 | + |
---|
| 1891 | +/* |
---|
| 1892 | + * Decode data into buffer. Uses head and pages constructed by |
---|
| 1893 | + * svcxdr_construct_vector. |
---|
| 1894 | + */ |
---|
| 1895 | +static __be32 |
---|
| 1896 | +nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct kvec *head, |
---|
| 1897 | + struct page **pages, char **bufp, u32 buflen) |
---|
| 1898 | +{ |
---|
| 1899 | + char *tmp, *dp; |
---|
| 1900 | + u32 len; |
---|
| 1901 | + |
---|
| 1902 | + if (buflen <= head->iov_len) { |
---|
| 1903 | + /* |
---|
| 1904 | + * We're in luck, the head has enough space. Just return |
---|
| 1905 | + * the head, no need for copying. |
---|
| 1906 | + */ |
---|
| 1907 | + *bufp = head->iov_base; |
---|
| 1908 | + return 0; |
---|
| 1909 | + } |
---|
| 1910 | + |
---|
| 1911 | + tmp = svcxdr_tmpalloc(argp, buflen); |
---|
| 1912 | + if (tmp == NULL) |
---|
| 1913 | + return nfserr_jukebox; |
---|
| 1914 | + |
---|
| 1915 | + dp = tmp; |
---|
| 1916 | + memcpy(dp, head->iov_base, head->iov_len); |
---|
| 1917 | + buflen -= head->iov_len; |
---|
| 1918 | + dp += head->iov_len; |
---|
| 1919 | + |
---|
| 1920 | + while (buflen > 0) { |
---|
| 1921 | + len = min_t(u32, buflen, PAGE_SIZE); |
---|
| 1922 | + memcpy(dp, page_address(*pages), len); |
---|
| 1923 | + |
---|
| 1924 | + buflen -= len; |
---|
| 1925 | + dp += len; |
---|
| 1926 | + pages++; |
---|
| 1927 | + } |
---|
| 1928 | + |
---|
| 1929 | + *bufp = tmp; |
---|
| 1930 | + return 0; |
---|
| 1931 | +} |
---|
| 1932 | + |
---|
| 1933 | +/* |
---|
| 1934 | + * Get a user extended attribute name from the XDR buffer. |
---|
| 1935 | + * It will not have the "user." prefix, so prepend it. |
---|
| 1936 | + * Lastly, check for nul characters in the name. |
---|
| 1937 | + */ |
---|
| 1938 | +static __be32 |
---|
| 1939 | +nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep) |
---|
| 1940 | +{ |
---|
| 1941 | + DECODE_HEAD; |
---|
| 1942 | + char *name, *sp, *dp; |
---|
| 1943 | + u32 namelen, cnt; |
---|
| 1944 | + |
---|
| 1945 | + READ_BUF(4); |
---|
| 1946 | + namelen = be32_to_cpup(p++); |
---|
| 1947 | + |
---|
| 1948 | + if (namelen > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) |
---|
| 1949 | + return nfserr_nametoolong; |
---|
| 1950 | + |
---|
| 1951 | + if (namelen == 0) |
---|
| 1952 | + goto xdr_error; |
---|
| 1953 | + |
---|
| 1954 | + READ_BUF(namelen); |
---|
| 1955 | + |
---|
| 1956 | + name = svcxdr_tmpalloc(argp, namelen + XATTR_USER_PREFIX_LEN + 1); |
---|
| 1957 | + if (!name) |
---|
| 1958 | + return nfserr_jukebox; |
---|
| 1959 | + |
---|
| 1960 | + memcpy(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); |
---|
| 1961 | + |
---|
| 1962 | + /* |
---|
| 1963 | + * Copy the extended attribute name over while checking for 0 |
---|
| 1964 | + * characters. |
---|
| 1965 | + */ |
---|
| 1966 | + sp = (char *)p; |
---|
| 1967 | + dp = name + XATTR_USER_PREFIX_LEN; |
---|
| 1968 | + cnt = namelen; |
---|
| 1969 | + |
---|
| 1970 | + while (cnt-- > 0) { |
---|
| 1971 | + if (*sp == '\0') |
---|
| 1972 | + goto xdr_error; |
---|
| 1973 | + *dp++ = *sp++; |
---|
| 1974 | + } |
---|
| 1975 | + *dp = '\0'; |
---|
| 1976 | + |
---|
| 1977 | + *namep = name; |
---|
| 1978 | + |
---|
| 1979 | + DECODE_TAIL; |
---|
| 1980 | +} |
---|
| 1981 | + |
---|
| 1982 | +/* |
---|
| 1983 | + * A GETXATTR op request comes without a length specifier. We just set the |
---|
| 1984 | + * maximum length for the reply based on XATTR_SIZE_MAX and the maximum |
---|
| 1985 | + * channel reply size. nfsd_getxattr will probe the length of the xattr, |
---|
| 1986 | + * check it against getxa_len, and allocate + return the value. |
---|
| 1987 | + */ |
---|
| 1988 | +static __be32 |
---|
| 1989 | +nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp, |
---|
| 1990 | + struct nfsd4_getxattr *getxattr) |
---|
| 1991 | +{ |
---|
| 1992 | + __be32 status; |
---|
| 1993 | + u32 maxcount; |
---|
| 1994 | + |
---|
| 1995 | + status = nfsd4_decode_xattr_name(argp, &getxattr->getxa_name); |
---|
| 1996 | + if (status) |
---|
| 1997 | + return status; |
---|
| 1998 | + |
---|
| 1999 | + maxcount = svc_max_payload(argp->rqstp); |
---|
| 2000 | + maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount); |
---|
| 2001 | + |
---|
| 2002 | + getxattr->getxa_len = maxcount; |
---|
| 2003 | + |
---|
| 2004 | + return status; |
---|
| 2005 | +} |
---|
| 2006 | + |
---|
| 2007 | +static __be32 |
---|
| 2008 | +nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, |
---|
| 2009 | + struct nfsd4_setxattr *setxattr) |
---|
| 2010 | +{ |
---|
| 2011 | + DECODE_HEAD; |
---|
| 2012 | + u32 flags, maxcount, size; |
---|
| 2013 | + struct kvec head; |
---|
| 2014 | + struct page **pagelist; |
---|
| 2015 | + |
---|
| 2016 | + READ_BUF(4); |
---|
| 2017 | + flags = be32_to_cpup(p++); |
---|
| 2018 | + |
---|
| 2019 | + if (flags > SETXATTR4_REPLACE) |
---|
| 2020 | + return nfserr_inval; |
---|
| 2021 | + setxattr->setxa_flags = flags; |
---|
| 2022 | + |
---|
| 2023 | + status = nfsd4_decode_xattr_name(argp, &setxattr->setxa_name); |
---|
| 2024 | + if (status) |
---|
| 2025 | + return status; |
---|
| 2026 | + |
---|
| 2027 | + maxcount = svc_max_payload(argp->rqstp); |
---|
| 2028 | + maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount); |
---|
| 2029 | + |
---|
| 2030 | + READ_BUF(4); |
---|
| 2031 | + size = be32_to_cpup(p++); |
---|
| 2032 | + if (size > maxcount) |
---|
| 2033 | + return nfserr_xattr2big; |
---|
| 2034 | + |
---|
| 2035 | + setxattr->setxa_len = size; |
---|
| 2036 | + if (size > 0) { |
---|
| 2037 | + status = svcxdr_construct_vector(argp, &head, &pagelist, size); |
---|
| 2038 | + if (status) |
---|
| 2039 | + return status; |
---|
| 2040 | + |
---|
| 2041 | + status = nfsd4_vbuf_from_vector(argp, &head, pagelist, |
---|
| 2042 | + &setxattr->setxa_buf, size); |
---|
| 2043 | + } |
---|
| 2044 | + |
---|
| 2045 | + DECODE_TAIL; |
---|
| 2046 | +} |
---|
| 2047 | + |
---|
| 2048 | +static __be32 |
---|
| 2049 | +nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, |
---|
| 2050 | + struct nfsd4_listxattrs *listxattrs) |
---|
| 2051 | +{ |
---|
| 2052 | + DECODE_HEAD; |
---|
| 2053 | + u32 maxcount; |
---|
| 2054 | + |
---|
| 2055 | + READ_BUF(12); |
---|
| 2056 | + p = xdr_decode_hyper(p, &listxattrs->lsxa_cookie); |
---|
| 2057 | + |
---|
| 2058 | + /* |
---|
| 2059 | + * If the cookie is too large to have even one user.x attribute |
---|
| 2060 | + * plus trailing '\0' left in a maximum size buffer, it's invalid. |
---|
| 2061 | + */ |
---|
| 2062 | + if (listxattrs->lsxa_cookie >= |
---|
| 2063 | + (XATTR_LIST_MAX / (XATTR_USER_PREFIX_LEN + 2))) |
---|
| 2064 | + return nfserr_badcookie; |
---|
| 2065 | + |
---|
| 2066 | + maxcount = be32_to_cpup(p++); |
---|
| 2067 | + if (maxcount < 8) |
---|
| 2068 | + /* Always need at least 2 words (length and one character) */ |
---|
| 2069 | + return nfserr_inval; |
---|
| 2070 | + |
---|
| 2071 | + maxcount = min(maxcount, svc_max_payload(argp->rqstp)); |
---|
| 2072 | + listxattrs->lsxa_maxcount = maxcount; |
---|
| 2073 | + |
---|
| 2074 | + DECODE_TAIL; |
---|
| 2075 | +} |
---|
| 2076 | + |
---|
| 2077 | +static __be32 |
---|
| 2078 | +nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp, |
---|
| 2079 | + struct nfsd4_removexattr *removexattr) |
---|
| 2080 | +{ |
---|
| 2081 | + return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name); |
---|
1784 | 2082 | } |
---|
1785 | 2083 | |
---|
1786 | 2084 | static __be32 |
---|
.. | .. |
---|
1868 | 2166 | /* new operations for NFSv4.2 */ |
---|
1869 | 2167 | [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, |
---|
1870 | 2168 | [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy, |
---|
1871 | | - [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
| 2169 | + [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_copy_notify, |
---|
1872 | 2170 | [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, |
---|
1873 | 2171 | [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
1874 | 2172 | [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
1875 | 2173 | [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
1876 | | - [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
1877 | | - [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
1878 | | - [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
| 2174 | + [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status, |
---|
| 2175 | + [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status, |
---|
| 2176 | + [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read, |
---|
1879 | 2177 | [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, |
---|
1880 | 2178 | [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, |
---|
1881 | 2179 | [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone, |
---|
| 2180 | + /* RFC 8276 extended atributes operations */ |
---|
| 2181 | + [OP_GETXATTR] = (nfsd4_dec)nfsd4_decode_getxattr, |
---|
| 2182 | + [OP_SETXATTR] = (nfsd4_dec)nfsd4_decode_setxattr, |
---|
| 2183 | + [OP_LISTXATTRS] = (nfsd4_dec)nfsd4_decode_listxattrs, |
---|
| 2184 | + [OP_REMOVEXATTR] = (nfsd4_dec)nfsd4_decode_removexattr, |
---|
1882 | 2185 | }; |
---|
1883 | 2186 | |
---|
1884 | 2187 | static inline bool |
---|
.. | .. |
---|
1958 | 2261 | */ |
---|
1959 | 2262 | cachethis |= nfsd4_cache_this_op(op); |
---|
1960 | 2263 | |
---|
1961 | | - if (op->opnum == OP_READ) { |
---|
| 2264 | + if (op->opnum == OP_READ || op->opnum == OP_READ_PLUS) { |
---|
1962 | 2265 | readcount++; |
---|
1963 | 2266 | readbytes += nfsd4_max_reply(argp->rqstp, op); |
---|
1964 | 2267 | } else |
---|
.. | .. |
---|
2017 | 2320 | */ |
---|
2018 | 2321 | static __be32 *encode_time_delta(__be32 *p, struct inode *inode) |
---|
2019 | 2322 | { |
---|
2020 | | - struct timespec ts; |
---|
| 2323 | + struct timespec64 ts; |
---|
2021 | 2324 | u32 ns; |
---|
2022 | 2325 | |
---|
2023 | 2326 | ns = max_t(u32, NSEC_PER_SEC/HZ, inode->i_sb->s_time_gran); |
---|
2024 | | - ts = ns_to_timespec(ns); |
---|
| 2327 | + ts = ns_to_timespec64(ns); |
---|
2025 | 2328 | |
---|
2026 | 2329 | p = xdr_encode_hyper(p, ts.tv_sec); |
---|
2027 | 2330 | *p++ = cpu_to_be32(ts.tv_nsec); |
---|
.. | .. |
---|
2910 | 3213 | } |
---|
2911 | 3214 | #endif |
---|
2912 | 3215 | |
---|
| 3216 | + if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) { |
---|
| 3217 | + p = xdr_reserve_space(xdr, 4); |
---|
| 3218 | + if (!p) |
---|
| 3219 | + goto out_resource; |
---|
| 3220 | + err = xattr_supported_namespace(d_inode(dentry), |
---|
| 3221 | + XATTR_USER_PREFIX); |
---|
| 3222 | + *p++ = cpu_to_be32(err == 0); |
---|
| 3223 | + } |
---|
| 3224 | + |
---|
2913 | 3225 | attrlen = htonl(xdr->buf->len - attrlen_offset - 4); |
---|
2914 | 3226 | write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4); |
---|
2915 | 3227 | status = nfs_ok; |
---|
.. | .. |
---|
2984 | 3296 | __be32 nfserr; |
---|
2985 | 3297 | int ignore_crossmnt = 0; |
---|
2986 | 3298 | |
---|
2987 | | - dentry = lookup_one_len_unlocked(name, cd->rd_fhp->fh_dentry, namlen); |
---|
| 3299 | + dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry, namlen); |
---|
2988 | 3300 | if (IS_ERR(dentry)) |
---|
2989 | 3301 | return nfserrno(PTR_ERR(dentry)); |
---|
2990 | | - if (d_really_is_negative(dentry)) { |
---|
2991 | | - /* |
---|
2992 | | - * we're not holding the i_mutex here, so there's |
---|
2993 | | - * a window where this directory entry could have gone |
---|
2994 | | - * away. |
---|
2995 | | - */ |
---|
2996 | | - dput(dentry); |
---|
2997 | | - return nfserr_noent; |
---|
2998 | | - } |
---|
2999 | 3302 | |
---|
3000 | 3303 | exp_get(exp); |
---|
3001 | 3304 | /* |
---|
.. | .. |
---|
3102 | 3405 | case nfserr_noent: |
---|
3103 | 3406 | xdr_truncate_encode(xdr, start_offset); |
---|
3104 | 3407 | goto skip_entry; |
---|
| 3408 | + case nfserr_jukebox: |
---|
| 3409 | + /* |
---|
| 3410 | + * The pseudoroot should only display dentries that lead to |
---|
| 3411 | + * exports. If we get EJUKEBOX here, then we can't tell whether |
---|
| 3412 | + * this entry should be included. Just fail the whole READDIR |
---|
| 3413 | + * with NFS4ERR_DELAY in that case, and hope that the situation |
---|
| 3414 | + * will resolve itself by the client's next attempt. |
---|
| 3415 | + */ |
---|
| 3416 | + if (cd->rd_fhp->fh_export->ex_flags & NFSEXP_V4ROOT) |
---|
| 3417 | + goto fail; |
---|
| 3418 | + fallthrough; |
---|
3105 | 3419 | default: |
---|
3106 | 3420 | /* |
---|
3107 | 3421 | * If the client requested the RDATTR_ERROR attribute, |
---|
.. | .. |
---|
3224 | 3538 | if (!p) |
---|
3225 | 3539 | return nfserr_resource; |
---|
3226 | 3540 | encode_cinfo(p, &create->cr_cinfo); |
---|
3227 | | - nfserr = nfsd4_encode_bitmap(xdr, create->cr_bmval[0], |
---|
| 3541 | + return nfsd4_encode_bitmap(xdr, create->cr_bmval[0], |
---|
3228 | 3542 | create->cr_bmval[1], create->cr_bmval[2]); |
---|
3229 | | - return 0; |
---|
3230 | 3543 | } |
---|
3231 | 3544 | |
---|
3232 | 3545 | static __be32 |
---|
.. | .. |
---|
3392 | 3705 | p = xdr_reserve_space(xdr, 32); |
---|
3393 | 3706 | if (!p) |
---|
3394 | 3707 | return nfserr_resource; |
---|
3395 | | - *p++ = cpu_to_be32(0); |
---|
| 3708 | + *p++ = cpu_to_be32(open->op_recall); |
---|
3396 | 3709 | |
---|
3397 | 3710 | /* |
---|
3398 | 3711 | * TODO: space_limit's in delegations |
---|
.. | .. |
---|
3458 | 3771 | struct xdr_stream *xdr = &resp->xdr; |
---|
3459 | 3772 | struct xdr_buf *buf = xdr->buf; |
---|
3460 | 3773 | u32 eof; |
---|
3461 | | - long len; |
---|
3462 | 3774 | int space_left; |
---|
3463 | 3775 | __be32 nfserr; |
---|
3464 | 3776 | __be32 *p = xdr->p - 2; |
---|
.. | .. |
---|
3467 | 3779 | if (xdr->end - xdr->p < 1) |
---|
3468 | 3780 | return nfserr_resource; |
---|
3469 | 3781 | |
---|
3470 | | - len = maxcount; |
---|
3471 | 3782 | nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp, |
---|
3472 | | - file, read->rd_offset, &maxcount); |
---|
| 3783 | + file, read->rd_offset, &maxcount, &eof); |
---|
3473 | 3784 | read->rd_length = maxcount; |
---|
3474 | 3785 | if (nfserr) { |
---|
3475 | 3786 | /* |
---|
.. | .. |
---|
3480 | 3791 | buf->page_len = 0; |
---|
3481 | 3792 | return nfserr; |
---|
3482 | 3793 | } |
---|
3483 | | - |
---|
3484 | | - eof = nfsd_eof_on_read(len, maxcount, read->rd_offset, |
---|
3485 | | - d_inode(read->rd_fhp->fh_dentry)->i_size); |
---|
3486 | 3794 | |
---|
3487 | 3795 | *(p++) = htonl(eof); |
---|
3488 | 3796 | *(p++) = htonl(maxcount); |
---|
.. | .. |
---|
3520 | 3828 | { |
---|
3521 | 3829 | struct xdr_stream *xdr = &resp->xdr; |
---|
3522 | 3830 | u32 eof; |
---|
3523 | | - int v; |
---|
3524 | 3831 | int starting_len = xdr->buf->len - 8; |
---|
3525 | | - long len; |
---|
3526 | | - int thislen; |
---|
3527 | 3832 | __be32 nfserr; |
---|
3528 | 3833 | __be32 tmp; |
---|
3529 | | - __be32 *p; |
---|
3530 | | - u32 zzz = 0; |
---|
3531 | 3834 | int pad; |
---|
3532 | 3835 | |
---|
3533 | | - len = maxcount; |
---|
3534 | | - v = 0; |
---|
| 3836 | + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); |
---|
| 3837 | + if (read->rd_vlen < 0) |
---|
| 3838 | + return nfserr_resource; |
---|
3535 | 3839 | |
---|
3536 | | - thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p)); |
---|
3537 | | - p = xdr_reserve_space(xdr, (thislen+3)&~3); |
---|
3538 | | - WARN_ON_ONCE(!p); |
---|
3539 | | - resp->rqstp->rq_vec[v].iov_base = p; |
---|
3540 | | - resp->rqstp->rq_vec[v].iov_len = thislen; |
---|
3541 | | - v++; |
---|
3542 | | - len -= thislen; |
---|
3543 | | - |
---|
3544 | | - while (len) { |
---|
3545 | | - thislen = min_t(long, len, PAGE_SIZE); |
---|
3546 | | - p = xdr_reserve_space(xdr, (thislen+3)&~3); |
---|
3547 | | - WARN_ON_ONCE(!p); |
---|
3548 | | - resp->rqstp->rq_vec[v].iov_base = p; |
---|
3549 | | - resp->rqstp->rq_vec[v].iov_len = thislen; |
---|
3550 | | - v++; |
---|
3551 | | - len -= thislen; |
---|
3552 | | - } |
---|
3553 | | - read->rd_vlen = v; |
---|
3554 | | - |
---|
3555 | | - len = maxcount; |
---|
3556 | 3840 | nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, |
---|
3557 | | - resp->rqstp->rq_vec, read->rd_vlen, &maxcount); |
---|
| 3841 | + resp->rqstp->rq_vec, read->rd_vlen, &maxcount, |
---|
| 3842 | + &eof); |
---|
3558 | 3843 | read->rd_length = maxcount; |
---|
3559 | 3844 | if (nfserr) |
---|
3560 | 3845 | return nfserr; |
---|
3561 | | - xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3)); |
---|
3562 | | - |
---|
3563 | | - eof = nfsd_eof_on_read(len, maxcount, read->rd_offset, |
---|
3564 | | - d_inode(read->rd_fhp->fh_dentry)->i_size); |
---|
| 3846 | + if (svc_encode_read_payload(resp->rqstp, starting_len + 8, maxcount)) |
---|
| 3847 | + return nfserr_io; |
---|
| 3848 | + xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount)); |
---|
3565 | 3849 | |
---|
3566 | 3850 | tmp = htonl(eof); |
---|
3567 | 3851 | write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); |
---|
3568 | 3852 | tmp = htonl(maxcount); |
---|
3569 | 3853 | write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); |
---|
3570 | 3854 | |
---|
| 3855 | + tmp = xdr_zero; |
---|
3571 | 3856 | pad = (maxcount&3) ? 4 - (maxcount&3) : 0; |
---|
3572 | 3857 | write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount, |
---|
3573 | | - &zzz, pad); |
---|
| 3858 | + &tmp, pad); |
---|
3574 | 3859 | return 0; |
---|
3575 | 3860 | |
---|
3576 | 3861 | } |
---|
.. | .. |
---|
3581 | 3866 | { |
---|
3582 | 3867 | unsigned long maxcount; |
---|
3583 | 3868 | struct xdr_stream *xdr = &resp->xdr; |
---|
3584 | | - struct file *file = read->rd_filp; |
---|
| 3869 | + struct file *file; |
---|
3585 | 3870 | int starting_len = xdr->buf->len; |
---|
3586 | | - struct raparms *ra = NULL; |
---|
3587 | 3871 | __be32 *p; |
---|
| 3872 | + |
---|
| 3873 | + if (nfserr) |
---|
| 3874 | + return nfserr; |
---|
| 3875 | + file = read->rd_nf->nf_file; |
---|
3588 | 3876 | |
---|
3589 | 3877 | p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ |
---|
3590 | 3878 | if (!p) { |
---|
.. | .. |
---|
3594 | 3882 | if (resp->xdr.buf->page_len && |
---|
3595 | 3883 | test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) { |
---|
3596 | 3884 | WARN_ON_ONCE(1); |
---|
3597 | | - return nfserr_resource; |
---|
| 3885 | + return nfserr_serverfault; |
---|
3598 | 3886 | } |
---|
3599 | 3887 | xdr_commit_encode(xdr); |
---|
3600 | 3888 | |
---|
.. | .. |
---|
3603 | 3891 | (xdr->buf->buflen - xdr->buf->len)); |
---|
3604 | 3892 | maxcount = min_t(unsigned long, maxcount, read->rd_length); |
---|
3605 | 3893 | |
---|
3606 | | - if (read->rd_tmp_file) |
---|
3607 | | - ra = nfsd_init_raparms(file); |
---|
3608 | | - |
---|
3609 | 3894 | if (file->f_op->splice_read && |
---|
3610 | 3895 | test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) |
---|
3611 | 3896 | nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); |
---|
3612 | 3897 | else |
---|
3613 | 3898 | nfserr = nfsd4_encode_readv(resp, read, file, maxcount); |
---|
3614 | | - |
---|
3615 | | - if (ra) |
---|
3616 | | - nfsd_put_raparams(file, ra); |
---|
3617 | 3899 | |
---|
3618 | 3900 | if (nfserr) |
---|
3619 | 3901 | xdr_truncate_encode(xdr, starting_len); |
---|
.. | .. |
---|
3946 | 4228 | int major_id_sz; |
---|
3947 | 4229 | int server_scope_sz; |
---|
3948 | 4230 | uint64_t minor_id = 0; |
---|
| 4231 | + struct nfsd_net *nn = net_generic(SVC_NET(resp->rqstp), nfsd_net_id); |
---|
3949 | 4232 | |
---|
3950 | | - major_id = utsname()->nodename; |
---|
3951 | | - major_id_sz = strlen(major_id); |
---|
3952 | | - server_scope = utsname()->nodename; |
---|
3953 | | - server_scope_sz = strlen(server_scope); |
---|
| 4233 | + major_id = nn->nfsd_name; |
---|
| 4234 | + major_id_sz = strlen(nn->nfsd_name); |
---|
| 4235 | + server_scope = nn->nfsd_name; |
---|
| 4236 | + server_scope_sz = strlen(nn->nfsd_name); |
---|
3954 | 4237 | |
---|
3955 | 4238 | p = xdr_reserve_space(xdr, |
---|
3956 | 4239 | 8 /* eir_clientid */ + |
---|
.. | .. |
---|
4124 | 4407 | |
---|
4125 | 4408 | *p++ = cpu_to_be32(gdev->gd_layout_type); |
---|
4126 | 4409 | |
---|
4127 | | - /* If maxcount is 0 then just update notifications */ |
---|
4128 | | - if (gdev->gd_maxcount != 0) { |
---|
4129 | | - ops = nfsd4_layout_ops[gdev->gd_layout_type]; |
---|
4130 | | - nfserr = ops->encode_getdeviceinfo(xdr, gdev); |
---|
4131 | | - if (nfserr) { |
---|
4132 | | - /* |
---|
4133 | | - * We don't bother to burden the layout drivers with |
---|
4134 | | - * enforcing gd_maxcount, just tell the client to |
---|
4135 | | - * come back with a bigger buffer if it's not enough. |
---|
4136 | | - */ |
---|
4137 | | - if (xdr->buf->len + 4 > gdev->gd_maxcount) |
---|
4138 | | - goto toosmall; |
---|
4139 | | - return nfserr; |
---|
4140 | | - } |
---|
| 4410 | + ops = nfsd4_layout_ops[gdev->gd_layout_type]; |
---|
| 4411 | + nfserr = ops->encode_getdeviceinfo(xdr, gdev); |
---|
| 4412 | + if (nfserr) { |
---|
| 4413 | + /* |
---|
| 4414 | + * We don't bother to burden the layout drivers with |
---|
| 4415 | + * enforcing gd_maxcount, just tell the client to |
---|
| 4416 | + * come back with a bigger buffer if it's not enough. |
---|
| 4417 | + */ |
---|
| 4418 | + if (xdr->buf->len + 4 > gdev->gd_maxcount) |
---|
| 4419 | + goto toosmall; |
---|
| 4420 | + return nfserr; |
---|
4141 | 4421 | } |
---|
4142 | 4422 | |
---|
4143 | 4423 | if (gdev->gd_notify_types) { |
---|
.. | .. |
---|
4231 | 4511 | #endif /* CONFIG_NFSD_PNFS */ |
---|
4232 | 4512 | |
---|
4233 | 4513 | static __be32 |
---|
4234 | | -nfsd42_encode_write_res(struct nfsd4_compoundres *resp, struct nfsd42_write_res *write) |
---|
| 4514 | +nfsd42_encode_write_res(struct nfsd4_compoundres *resp, |
---|
| 4515 | + struct nfsd42_write_res *write, bool sync) |
---|
4235 | 4516 | { |
---|
4236 | 4517 | __be32 *p; |
---|
4237 | | - |
---|
4238 | | - p = xdr_reserve_space(&resp->xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE); |
---|
| 4518 | + p = xdr_reserve_space(&resp->xdr, 4); |
---|
4239 | 4519 | if (!p) |
---|
4240 | 4520 | return nfserr_resource; |
---|
4241 | 4521 | |
---|
4242 | | - *p++ = cpu_to_be32(0); |
---|
| 4522 | + if (sync) |
---|
| 4523 | + *p++ = cpu_to_be32(0); |
---|
| 4524 | + else { |
---|
| 4525 | + __be32 nfserr; |
---|
| 4526 | + *p++ = cpu_to_be32(1); |
---|
| 4527 | + nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid); |
---|
| 4528 | + if (nfserr) |
---|
| 4529 | + return nfserr; |
---|
| 4530 | + } |
---|
| 4531 | + p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE); |
---|
| 4532 | + if (!p) |
---|
| 4533 | + return nfserr_resource; |
---|
| 4534 | + |
---|
4243 | 4535 | p = xdr_encode_hyper(p, write->wr_bytes_written); |
---|
4244 | 4536 | *p++ = cpu_to_be32(write->wr_stable_how); |
---|
4245 | 4537 | p = xdr_encode_opaque_fixed(p, write->wr_verifier.data, |
---|
.. | .. |
---|
4248 | 4540 | } |
---|
4249 | 4541 | |
---|
4250 | 4542 | static __be32 |
---|
| 4543 | +nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns) |
---|
| 4544 | +{ |
---|
| 4545 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4546 | + struct nfs42_netaddr *addr; |
---|
| 4547 | + __be32 *p; |
---|
| 4548 | + |
---|
| 4549 | + p = xdr_reserve_space(xdr, 4); |
---|
| 4550 | + *p++ = cpu_to_be32(ns->nl4_type); |
---|
| 4551 | + |
---|
| 4552 | + switch (ns->nl4_type) { |
---|
| 4553 | + case NL4_NETADDR: |
---|
| 4554 | + addr = &ns->u.nl4_addr; |
---|
| 4555 | + |
---|
| 4556 | + /* netid_len, netid, uaddr_len, uaddr (port included |
---|
| 4557 | + * in RPCBIND_MAXUADDRLEN) |
---|
| 4558 | + */ |
---|
| 4559 | + p = xdr_reserve_space(xdr, |
---|
| 4560 | + 4 /* netid len */ + |
---|
| 4561 | + (XDR_QUADLEN(addr->netid_len) * 4) + |
---|
| 4562 | + 4 /* uaddr len */ + |
---|
| 4563 | + (XDR_QUADLEN(addr->addr_len) * 4)); |
---|
| 4564 | + if (!p) |
---|
| 4565 | + return nfserr_resource; |
---|
| 4566 | + |
---|
| 4567 | + *p++ = cpu_to_be32(addr->netid_len); |
---|
| 4568 | + p = xdr_encode_opaque_fixed(p, addr->netid, |
---|
| 4569 | + addr->netid_len); |
---|
| 4570 | + *p++ = cpu_to_be32(addr->addr_len); |
---|
| 4571 | + p = xdr_encode_opaque_fixed(p, addr->addr, |
---|
| 4572 | + addr->addr_len); |
---|
| 4573 | + break; |
---|
| 4574 | + default: |
---|
| 4575 | + WARN_ON_ONCE(ns->nl4_type != NL4_NETADDR); |
---|
| 4576 | + return nfserr_inval; |
---|
| 4577 | + } |
---|
| 4578 | + |
---|
| 4579 | + return 0; |
---|
| 4580 | +} |
---|
| 4581 | + |
---|
| 4582 | +static __be32 |
---|
4251 | 4583 | nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
4252 | 4584 | struct nfsd4_copy *copy) |
---|
4253 | 4585 | { |
---|
4254 | 4586 | __be32 *p; |
---|
4255 | 4587 | |
---|
4256 | | - nfserr = nfsd42_encode_write_res(resp, ©->cp_res); |
---|
| 4588 | + nfserr = nfsd42_encode_write_res(resp, ©->cp_res, |
---|
| 4589 | + copy->cp_synchronous); |
---|
4257 | 4590 | if (nfserr) |
---|
4258 | 4591 | return nfserr; |
---|
4259 | 4592 | |
---|
.. | .. |
---|
4261 | 4594 | *p++ = xdr_one; /* cr_consecutive */ |
---|
4262 | 4595 | *p++ = cpu_to_be32(copy->cp_synchronous); |
---|
4263 | 4596 | return 0; |
---|
| 4597 | +} |
---|
| 4598 | + |
---|
| 4599 | +static __be32 |
---|
| 4600 | +nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 4601 | + struct nfsd4_offload_status *os) |
---|
| 4602 | +{ |
---|
| 4603 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4604 | + __be32 *p; |
---|
| 4605 | + |
---|
| 4606 | + p = xdr_reserve_space(xdr, 8 + 4); |
---|
| 4607 | + if (!p) |
---|
| 4608 | + return nfserr_resource; |
---|
| 4609 | + p = xdr_encode_hyper(p, os->count); |
---|
| 4610 | + *p++ = cpu_to_be32(0); |
---|
| 4611 | + return nfserr; |
---|
| 4612 | +} |
---|
| 4613 | + |
---|
| 4614 | +static __be32 |
---|
| 4615 | +nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, |
---|
| 4616 | + struct nfsd4_read *read, |
---|
| 4617 | + unsigned long *maxcount, u32 *eof, |
---|
| 4618 | + loff_t *pos) |
---|
| 4619 | +{ |
---|
| 4620 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4621 | + struct file *file = read->rd_nf->nf_file; |
---|
| 4622 | + int starting_len = xdr->buf->len; |
---|
| 4623 | + loff_t hole_pos; |
---|
| 4624 | + __be32 nfserr; |
---|
| 4625 | + __be32 *p, tmp; |
---|
| 4626 | + __be64 tmp64; |
---|
| 4627 | + |
---|
| 4628 | + hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE); |
---|
| 4629 | + if (hole_pos > read->rd_offset) |
---|
| 4630 | + *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset); |
---|
| 4631 | + *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len)); |
---|
| 4632 | + |
---|
| 4633 | + /* Content type, offset, byte count */ |
---|
| 4634 | + p = xdr_reserve_space(xdr, 4 + 8 + 4); |
---|
| 4635 | + if (!p) |
---|
| 4636 | + return nfserr_resource; |
---|
| 4637 | + |
---|
| 4638 | + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount); |
---|
| 4639 | + if (read->rd_vlen < 0) |
---|
| 4640 | + return nfserr_resource; |
---|
| 4641 | + |
---|
| 4642 | + nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, |
---|
| 4643 | + resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof); |
---|
| 4644 | + if (nfserr) |
---|
| 4645 | + return nfserr; |
---|
| 4646 | + xdr_truncate_encode(xdr, starting_len + 16 + xdr_align_size(*maxcount)); |
---|
| 4647 | + |
---|
| 4648 | + tmp = htonl(NFS4_CONTENT_DATA); |
---|
| 4649 | + write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); |
---|
| 4650 | + tmp64 = cpu_to_be64(read->rd_offset); |
---|
| 4651 | + write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8); |
---|
| 4652 | + tmp = htonl(*maxcount); |
---|
| 4653 | + write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4); |
---|
| 4654 | + |
---|
| 4655 | + tmp = xdr_zero; |
---|
| 4656 | + write_bytes_to_xdr_buf(xdr->buf, starting_len + 16 + *maxcount, &tmp, |
---|
| 4657 | + xdr_pad_size(*maxcount)); |
---|
| 4658 | + return nfs_ok; |
---|
| 4659 | +} |
---|
| 4660 | + |
---|
| 4661 | +static __be32 |
---|
| 4662 | +nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, |
---|
| 4663 | + struct nfsd4_read *read, |
---|
| 4664 | + unsigned long *maxcount, u32 *eof) |
---|
| 4665 | +{ |
---|
| 4666 | + struct file *file = read->rd_nf->nf_file; |
---|
| 4667 | + loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); |
---|
| 4668 | + loff_t f_size = i_size_read(file_inode(file)); |
---|
| 4669 | + unsigned long count; |
---|
| 4670 | + __be32 *p; |
---|
| 4671 | + |
---|
| 4672 | + if (data_pos == -ENXIO) |
---|
| 4673 | + data_pos = f_size; |
---|
| 4674 | + else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE)) |
---|
| 4675 | + return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size); |
---|
| 4676 | + count = data_pos - read->rd_offset; |
---|
| 4677 | + |
---|
| 4678 | + /* Content type, offset, byte count */ |
---|
| 4679 | + p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); |
---|
| 4680 | + if (!p) |
---|
| 4681 | + return nfserr_resource; |
---|
| 4682 | + |
---|
| 4683 | + *p++ = htonl(NFS4_CONTENT_HOLE); |
---|
| 4684 | + p = xdr_encode_hyper(p, read->rd_offset); |
---|
| 4685 | + p = xdr_encode_hyper(p, count); |
---|
| 4686 | + |
---|
| 4687 | + *eof = (read->rd_offset + count) >= f_size; |
---|
| 4688 | + *maxcount = min_t(unsigned long, count, *maxcount); |
---|
| 4689 | + return nfs_ok; |
---|
| 4690 | +} |
---|
| 4691 | + |
---|
| 4692 | +static __be32 |
---|
| 4693 | +nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 4694 | + struct nfsd4_read *read) |
---|
| 4695 | +{ |
---|
| 4696 | + unsigned long maxcount, count; |
---|
| 4697 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4698 | + struct file *file; |
---|
| 4699 | + int starting_len = xdr->buf->len; |
---|
| 4700 | + int last_segment = xdr->buf->len; |
---|
| 4701 | + int segments = 0; |
---|
| 4702 | + __be32 *p, tmp; |
---|
| 4703 | + bool is_data; |
---|
| 4704 | + loff_t pos; |
---|
| 4705 | + u32 eof; |
---|
| 4706 | + |
---|
| 4707 | + if (nfserr) |
---|
| 4708 | + return nfserr; |
---|
| 4709 | + file = read->rd_nf->nf_file; |
---|
| 4710 | + |
---|
| 4711 | + /* eof flag, segment count */ |
---|
| 4712 | + p = xdr_reserve_space(xdr, 4 + 4); |
---|
| 4713 | + if (!p) |
---|
| 4714 | + return nfserr_resource; |
---|
| 4715 | + xdr_commit_encode(xdr); |
---|
| 4716 | + |
---|
| 4717 | + maxcount = svc_max_payload(resp->rqstp); |
---|
| 4718 | + maxcount = min_t(unsigned long, maxcount, |
---|
| 4719 | + (xdr->buf->buflen - xdr->buf->len)); |
---|
| 4720 | + maxcount = min_t(unsigned long, maxcount, read->rd_length); |
---|
| 4721 | + count = maxcount; |
---|
| 4722 | + |
---|
| 4723 | + eof = read->rd_offset >= i_size_read(file_inode(file)); |
---|
| 4724 | + if (eof) |
---|
| 4725 | + goto out; |
---|
| 4726 | + |
---|
| 4727 | + pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE); |
---|
| 4728 | + is_data = pos > read->rd_offset; |
---|
| 4729 | + |
---|
| 4730 | + while (count > 0 && !eof) { |
---|
| 4731 | + maxcount = count; |
---|
| 4732 | + if (is_data) |
---|
| 4733 | + nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof, |
---|
| 4734 | + segments == 0 ? &pos : NULL); |
---|
| 4735 | + else |
---|
| 4736 | + nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof); |
---|
| 4737 | + if (nfserr) |
---|
| 4738 | + goto out; |
---|
| 4739 | + count -= maxcount; |
---|
| 4740 | + read->rd_offset += maxcount; |
---|
| 4741 | + is_data = !is_data; |
---|
| 4742 | + last_segment = xdr->buf->len; |
---|
| 4743 | + segments++; |
---|
| 4744 | + } |
---|
| 4745 | + |
---|
| 4746 | +out: |
---|
| 4747 | + if (nfserr && segments == 0) |
---|
| 4748 | + xdr_truncate_encode(xdr, starting_len); |
---|
| 4749 | + else { |
---|
| 4750 | + if (nfserr) { |
---|
| 4751 | + xdr_truncate_encode(xdr, last_segment); |
---|
| 4752 | + nfserr = nfs_ok; |
---|
| 4753 | + eof = 0; |
---|
| 4754 | + } |
---|
| 4755 | + tmp = htonl(eof); |
---|
| 4756 | + write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); |
---|
| 4757 | + tmp = htonl(segments); |
---|
| 4758 | + write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); |
---|
| 4759 | + } |
---|
| 4760 | + |
---|
| 4761 | + return nfserr; |
---|
| 4762 | +} |
---|
| 4763 | + |
---|
| 4764 | +static __be32 |
---|
| 4765 | +nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 4766 | + struct nfsd4_copy_notify *cn) |
---|
| 4767 | +{ |
---|
| 4768 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4769 | + __be32 *p; |
---|
| 4770 | + |
---|
| 4771 | + if (nfserr) |
---|
| 4772 | + return nfserr; |
---|
| 4773 | + |
---|
| 4774 | + /* 8 sec, 4 nsec */ |
---|
| 4775 | + p = xdr_reserve_space(xdr, 12); |
---|
| 4776 | + if (!p) |
---|
| 4777 | + return nfserr_resource; |
---|
| 4778 | + |
---|
| 4779 | + /* cnr_lease_time */ |
---|
| 4780 | + p = xdr_encode_hyper(p, cn->cpn_sec); |
---|
| 4781 | + *p++ = cpu_to_be32(cn->cpn_nsec); |
---|
| 4782 | + |
---|
| 4783 | + /* cnr_stateid */ |
---|
| 4784 | + nfserr = nfsd4_encode_stateid(xdr, &cn->cpn_cnr_stateid); |
---|
| 4785 | + if (nfserr) |
---|
| 4786 | + return nfserr; |
---|
| 4787 | + |
---|
| 4788 | + /* cnr_src.nl_nsvr */ |
---|
| 4789 | + p = xdr_reserve_space(xdr, 4); |
---|
| 4790 | + if (!p) |
---|
| 4791 | + return nfserr_resource; |
---|
| 4792 | + |
---|
| 4793 | + *p++ = cpu_to_be32(1); |
---|
| 4794 | + |
---|
| 4795 | + return nfsd42_encode_nl4_server(resp, &cn->cpn_src); |
---|
4264 | 4796 | } |
---|
4265 | 4797 | |
---|
4266 | 4798 | static __be32 |
---|
.. | .. |
---|
4280 | 4812 | nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) |
---|
4281 | 4813 | { |
---|
4282 | 4814 | return nfserr; |
---|
| 4815 | +} |
---|
| 4816 | + |
---|
| 4817 | +/* |
---|
| 4818 | + * Encode kmalloc-ed buffer in to XDR stream. |
---|
| 4819 | + */ |
---|
| 4820 | +static __be32 |
---|
| 4821 | +nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen) |
---|
| 4822 | +{ |
---|
| 4823 | + u32 cplen; |
---|
| 4824 | + __be32 *p; |
---|
| 4825 | + |
---|
| 4826 | + cplen = min_t(unsigned long, buflen, |
---|
| 4827 | + ((void *)xdr->end - (void *)xdr->p)); |
---|
| 4828 | + p = xdr_reserve_space(xdr, cplen); |
---|
| 4829 | + if (!p) |
---|
| 4830 | + return nfserr_resource; |
---|
| 4831 | + |
---|
| 4832 | + memcpy(p, buf, cplen); |
---|
| 4833 | + buf += cplen; |
---|
| 4834 | + buflen -= cplen; |
---|
| 4835 | + |
---|
| 4836 | + while (buflen) { |
---|
| 4837 | + cplen = min_t(u32, buflen, PAGE_SIZE); |
---|
| 4838 | + p = xdr_reserve_space(xdr, cplen); |
---|
| 4839 | + if (!p) |
---|
| 4840 | + return nfserr_resource; |
---|
| 4841 | + |
---|
| 4842 | + memcpy(p, buf, cplen); |
---|
| 4843 | + |
---|
| 4844 | + if (cplen < PAGE_SIZE) { |
---|
| 4845 | + /* |
---|
| 4846 | + * We're done, with a length that wasn't page |
---|
| 4847 | + * aligned, so possibly not word aligned. Pad |
---|
| 4848 | + * any trailing bytes with 0. |
---|
| 4849 | + */ |
---|
| 4850 | + xdr_encode_opaque_fixed(p, NULL, cplen); |
---|
| 4851 | + break; |
---|
| 4852 | + } |
---|
| 4853 | + |
---|
| 4854 | + buflen -= PAGE_SIZE; |
---|
| 4855 | + buf += PAGE_SIZE; |
---|
| 4856 | + } |
---|
| 4857 | + |
---|
| 4858 | + return 0; |
---|
| 4859 | +} |
---|
| 4860 | + |
---|
| 4861 | +static __be32 |
---|
| 4862 | +nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 4863 | + struct nfsd4_getxattr *getxattr) |
---|
| 4864 | +{ |
---|
| 4865 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4866 | + __be32 *p, err; |
---|
| 4867 | + |
---|
| 4868 | + p = xdr_reserve_space(xdr, 4); |
---|
| 4869 | + if (!p) |
---|
| 4870 | + return nfserr_resource; |
---|
| 4871 | + |
---|
| 4872 | + *p = cpu_to_be32(getxattr->getxa_len); |
---|
| 4873 | + |
---|
| 4874 | + if (getxattr->getxa_len == 0) |
---|
| 4875 | + return 0; |
---|
| 4876 | + |
---|
| 4877 | + err = nfsd4_vbuf_to_stream(xdr, getxattr->getxa_buf, |
---|
| 4878 | + getxattr->getxa_len); |
---|
| 4879 | + |
---|
| 4880 | + kvfree(getxattr->getxa_buf); |
---|
| 4881 | + |
---|
| 4882 | + return err; |
---|
| 4883 | +} |
---|
| 4884 | + |
---|
| 4885 | +static __be32 |
---|
| 4886 | +nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 4887 | + struct nfsd4_setxattr *setxattr) |
---|
| 4888 | +{ |
---|
| 4889 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4890 | + __be32 *p; |
---|
| 4891 | + |
---|
| 4892 | + p = xdr_reserve_space(xdr, 20); |
---|
| 4893 | + if (!p) |
---|
| 4894 | + return nfserr_resource; |
---|
| 4895 | + |
---|
| 4896 | + encode_cinfo(p, &setxattr->setxa_cinfo); |
---|
| 4897 | + |
---|
| 4898 | + return 0; |
---|
| 4899 | +} |
---|
| 4900 | + |
---|
| 4901 | +/* |
---|
| 4902 | + * See if there are cookie values that can be rejected outright. |
---|
| 4903 | + */ |
---|
| 4904 | +static __be32 |
---|
| 4905 | +nfsd4_listxattr_validate_cookie(struct nfsd4_listxattrs *listxattrs, |
---|
| 4906 | + u32 *offsetp) |
---|
| 4907 | +{ |
---|
| 4908 | + u64 cookie = listxattrs->lsxa_cookie; |
---|
| 4909 | + |
---|
| 4910 | + /* |
---|
| 4911 | + * If the cookie is larger than the maximum number we can fit |
---|
| 4912 | + * in either the buffer we just got back from vfs_listxattr, or, |
---|
| 4913 | + * XDR-encoded, in the return buffer, it's invalid. |
---|
| 4914 | + */ |
---|
| 4915 | + if (cookie > (listxattrs->lsxa_len) / (XATTR_USER_PREFIX_LEN + 2)) |
---|
| 4916 | + return nfserr_badcookie; |
---|
| 4917 | + |
---|
| 4918 | + if (cookie > (listxattrs->lsxa_maxcount / |
---|
| 4919 | + (XDR_QUADLEN(XATTR_USER_PREFIX_LEN + 2) + 4))) |
---|
| 4920 | + return nfserr_badcookie; |
---|
| 4921 | + |
---|
| 4922 | + *offsetp = (u32)cookie; |
---|
| 4923 | + return 0; |
---|
| 4924 | +} |
---|
| 4925 | + |
---|
| 4926 | +static __be32 |
---|
| 4927 | +nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 4928 | + struct nfsd4_listxattrs *listxattrs) |
---|
| 4929 | +{ |
---|
| 4930 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 4931 | + u32 cookie_offset, count_offset, eof; |
---|
| 4932 | + u32 left, xdrleft, slen, count; |
---|
| 4933 | + u32 xdrlen, offset; |
---|
| 4934 | + u64 cookie; |
---|
| 4935 | + char *sp; |
---|
| 4936 | + __be32 status, tmp; |
---|
| 4937 | + __be32 *p; |
---|
| 4938 | + u32 nuser; |
---|
| 4939 | + |
---|
| 4940 | + eof = 1; |
---|
| 4941 | + |
---|
| 4942 | + status = nfsd4_listxattr_validate_cookie(listxattrs, &offset); |
---|
| 4943 | + if (status) |
---|
| 4944 | + goto out; |
---|
| 4945 | + |
---|
| 4946 | + /* |
---|
| 4947 | + * Reserve space for the cookie and the name array count. Record |
---|
| 4948 | + * the offsets to save them later. |
---|
| 4949 | + */ |
---|
| 4950 | + cookie_offset = xdr->buf->len; |
---|
| 4951 | + count_offset = cookie_offset + 8; |
---|
| 4952 | + p = xdr_reserve_space(xdr, 12); |
---|
| 4953 | + if (!p) { |
---|
| 4954 | + status = nfserr_resource; |
---|
| 4955 | + goto out; |
---|
| 4956 | + } |
---|
| 4957 | + |
---|
| 4958 | + count = 0; |
---|
| 4959 | + left = listxattrs->lsxa_len; |
---|
| 4960 | + sp = listxattrs->lsxa_buf; |
---|
| 4961 | + nuser = 0; |
---|
| 4962 | + |
---|
| 4963 | + xdrleft = listxattrs->lsxa_maxcount; |
---|
| 4964 | + |
---|
| 4965 | + while (left > 0 && xdrleft > 0) { |
---|
| 4966 | + slen = strlen(sp); |
---|
| 4967 | + |
---|
| 4968 | + /* |
---|
| 4969 | + * Check if this is a "user." attribute, skip it if not. |
---|
| 4970 | + */ |
---|
| 4971 | + if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) |
---|
| 4972 | + goto contloop; |
---|
| 4973 | + |
---|
| 4974 | + slen -= XATTR_USER_PREFIX_LEN; |
---|
| 4975 | + xdrlen = 4 + ((slen + 3) & ~3); |
---|
| 4976 | + if (xdrlen > xdrleft) { |
---|
| 4977 | + if (count == 0) { |
---|
| 4978 | + /* |
---|
| 4979 | + * Can't even fit the first attribute name. |
---|
| 4980 | + */ |
---|
| 4981 | + status = nfserr_toosmall; |
---|
| 4982 | + goto out; |
---|
| 4983 | + } |
---|
| 4984 | + eof = 0; |
---|
| 4985 | + goto wreof; |
---|
| 4986 | + } |
---|
| 4987 | + |
---|
| 4988 | + left -= XATTR_USER_PREFIX_LEN; |
---|
| 4989 | + sp += XATTR_USER_PREFIX_LEN; |
---|
| 4990 | + if (nuser++ < offset) |
---|
| 4991 | + goto contloop; |
---|
| 4992 | + |
---|
| 4993 | + |
---|
| 4994 | + p = xdr_reserve_space(xdr, xdrlen); |
---|
| 4995 | + if (!p) { |
---|
| 4996 | + status = nfserr_resource; |
---|
| 4997 | + goto out; |
---|
| 4998 | + } |
---|
| 4999 | + |
---|
| 5000 | + xdr_encode_opaque(p, sp, slen); |
---|
| 5001 | + |
---|
| 5002 | + xdrleft -= xdrlen; |
---|
| 5003 | + count++; |
---|
| 5004 | +contloop: |
---|
| 5005 | + sp += slen + 1; |
---|
| 5006 | + left -= slen + 1; |
---|
| 5007 | + } |
---|
| 5008 | + |
---|
| 5009 | + /* |
---|
| 5010 | + * If there were user attributes to copy, but we didn't copy |
---|
| 5011 | + * any, the offset was too large (e.g. the cookie was invalid). |
---|
| 5012 | + */ |
---|
| 5013 | + if (nuser > 0 && count == 0) { |
---|
| 5014 | + status = nfserr_badcookie; |
---|
| 5015 | + goto out; |
---|
| 5016 | + } |
---|
| 5017 | + |
---|
| 5018 | +wreof: |
---|
| 5019 | + p = xdr_reserve_space(xdr, 4); |
---|
| 5020 | + if (!p) { |
---|
| 5021 | + status = nfserr_resource; |
---|
| 5022 | + goto out; |
---|
| 5023 | + } |
---|
| 5024 | + *p = cpu_to_be32(eof); |
---|
| 5025 | + |
---|
| 5026 | + cookie = offset + count; |
---|
| 5027 | + |
---|
| 5028 | + write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8); |
---|
| 5029 | + tmp = cpu_to_be32(count); |
---|
| 5030 | + write_bytes_to_xdr_buf(xdr->buf, count_offset, &tmp, 4); |
---|
| 5031 | +out: |
---|
| 5032 | + if (listxattrs->lsxa_len) |
---|
| 5033 | + kvfree(listxattrs->lsxa_buf); |
---|
| 5034 | + return status; |
---|
| 5035 | +} |
---|
| 5036 | + |
---|
| 5037 | +static __be32 |
---|
| 5038 | +nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr, |
---|
| 5039 | + struct nfsd4_removexattr *removexattr) |
---|
| 5040 | +{ |
---|
| 5041 | + struct xdr_stream *xdr = &resp->xdr; |
---|
| 5042 | + __be32 *p; |
---|
| 5043 | + |
---|
| 5044 | + p = xdr_reserve_space(xdr, 20); |
---|
| 5045 | + if (!p) |
---|
| 5046 | + return nfserr_resource; |
---|
| 5047 | + |
---|
| 5048 | + p = encode_cinfo(p, &removexattr->rmxa_cinfo); |
---|
| 5049 | + return 0; |
---|
4283 | 5050 | } |
---|
4284 | 5051 | |
---|
4285 | 5052 | typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); |
---|
.. | .. |
---|
4360 | 5127 | /* NFSv4.2 operations */ |
---|
4361 | 5128 | [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4362 | 5129 | [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy, |
---|
4363 | | - [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_noop, |
---|
| 5130 | + [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_copy_notify, |
---|
4364 | 5131 | [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4365 | 5132 | [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4366 | 5133 | [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4367 | 5134 | [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4368 | 5135 | [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4369 | | - [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4370 | | - [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, |
---|
| 5136 | + [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status, |
---|
| 5137 | + [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus, |
---|
4371 | 5138 | [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, |
---|
4372 | 5139 | [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, |
---|
4373 | 5140 | [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop, |
---|
| 5141 | + |
---|
| 5142 | + /* RFC 8276 extended atributes operations */ |
---|
| 5143 | + [OP_GETXATTR] = (nfsd4_enc)nfsd4_encode_getxattr, |
---|
| 5144 | + [OP_SETXATTR] = (nfsd4_enc)nfsd4_encode_setxattr, |
---|
| 5145 | + [OP_LISTXATTRS] = (nfsd4_enc)nfsd4_encode_listxattrs, |
---|
| 5146 | + [OP_REMOVEXATTR] = (nfsd4_enc)nfsd4_encode_removexattr, |
---|
4374 | 5147 | }; |
---|
4375 | 5148 | |
---|
4376 | 5149 | /* |
---|
.. | .. |
---|
4487 | 5260 | __be32 *p; |
---|
4488 | 5261 | struct nfs4_replay *rp = op->replay; |
---|
4489 | 5262 | |
---|
4490 | | - BUG_ON(!rp); |
---|
4491 | | - |
---|
4492 | 5263 | p = xdr_reserve_space(xdr, 8 + rp->rp_buflen); |
---|
4493 | 5264 | if (!p) { |
---|
4494 | 5265 | WARN_ON_ONCE(1); |
---|
.. | .. |
---|
4524 | 5295 | } |
---|
4525 | 5296 | |
---|
4526 | 5297 | int |
---|
| 5298 | +nfs4svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) |
---|
| 5299 | +{ |
---|
| 5300 | + return 1; |
---|
| 5301 | +} |
---|
| 5302 | + |
---|
| 5303 | +int |
---|
4527 | 5304 | nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) |
---|
4528 | 5305 | { |
---|
4529 | 5306 | struct nfsd4_compoundargs *args = rqstp->rq_argp; |
---|
.. | .. |
---|
4550 | 5327 | int |
---|
4551 | 5328 | nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) |
---|
4552 | 5329 | { |
---|
4553 | | - /* |
---|
4554 | | - * All that remains is to write the tag and operation count... |
---|
4555 | | - */ |
---|
4556 | 5330 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
---|
4557 | 5331 | struct xdr_buf *buf = resp->xdr.buf; |
---|
4558 | 5332 | |
---|
4559 | 5333 | WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + |
---|
4560 | 5334 | buf->tail[0].iov_len); |
---|
4561 | 5335 | |
---|
| 5336 | + *p = resp->cstate.status; |
---|
| 5337 | + |
---|
4562 | 5338 | rqstp->rq_next_page = resp->xdr.page_ptr + 1; |
---|
4563 | 5339 | |
---|
4564 | 5340 | p = resp->tagp; |
---|