summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Kelly <mike@weatherwax.co.uk>2025-07-20 14:19:11 +0200
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2025-07-20 14:19:11 +0200
commit529b93b8f6cc94830325cfde1b237f0ca04af38e (patch)
tree2d1319b3725a1481737bf4f553173d3d8236d302
parent2c39bb58dfbcc018d2f2104d60733e6cf6be4adc (diff)
nfs: fix the handling of replies to MKNOD and SYMLINK
The Linux NFS server does not accept a setting of file size to 0 for sockets and FIFOs so there is code to strip that for those cases. I also spotted that the file modification times were not being applied to a created file so there is now just one rpc to set all file attributes using xdr_encode_create_state(). This sets the times to be server time which is appropriate for a new file (even though it was created in the previous RPC call). The previous code was supplying the 'gid' based on that returned by the 'stat' but I don't think that can be relied on since the V3 protocol states that CREATE3 using EXCLUSIVE cannot guarantee any file attributes until after the SETATTR3.
-rw-r--r--nfs/nfs.c32
-rw-r--r--nfs/ops.c52
2 files changed, 47 insertions, 37 deletions
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 313c1e4a..40e62669 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <netinet/in.h>
+#include <stdbool.h>
#include <stdio.h>
#include <sys/sysmacros.h>
@@ -179,6 +180,30 @@ xdr_encode_string (int *p, const char *string)
return xdr_encode_data (p, string, strlen (string));
}
+/* Some NFSv3 rpcs can fail if the file size field
+ is set within the set attributes unnecessarily. */
+static inline bool
+nfs_sattr3_size_needed(mode_t mode, size_t sz)
+{
+ if (sz == 0)
+ {
+ switch (hurd_mode_to_nfs_type (mode))
+ {
+ case NFSOCK:
+ case NF3FIFO:
+ /* NFCHR and NFBLK probaly also fall into this
+ category but as unable to check then leave
+ those alone. */
+ return false;
+
+ default:
+ break;
+ }
+ }
+
+ return true;
+}
+
/* Encode a MODE into an otherwise empty sattr. */
int *
xdr_encode_sattr_mode (int *p, mode_t mode)
@@ -372,14 +397,17 @@ xdr_encode_sattr_stat (int *p,
}
else
{
+ bool needs_size = nfs_sattr3_size_needed (st->st_mode, st->st_size);
+
*(p++) = htonl (1); /* set mode */
*(p++) = htonl (hurd_mode_to_nfs_mode (st->st_mode));
*(p++) = htonl (1); /* set uid */
*(p++) = htonl (st->st_uid);
*(p++) = htonl (1); /* set gid */
*(p++) = htonl (st->st_gid);
- *(p++) = htonl (1); /* set size */
- p = xdr_encode_64bit (p, st->st_size);
+ *(p++) = htonl (needs_size); /* set size */
+ if (needs_size)
+ p = xdr_encode_64bit (p, st->st_size);
*(p++) = htonl (SET_TO_CLIENT_TIME); /* set atime */
*(p++) = htonl (st->st_atim.tv_sec);
*(p++) = htonl (st->st_atim.tv_nsec);
diff --git a/nfs/ops.c b/nfs/ops.c
index 646e206c..2976641f 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -1056,8 +1056,6 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
}
pthread_mutex_unlock (&np->lock);
- pthread_mutex_lock (&dir->lock);
-
purge_lookup_cache (dir, name, strlen (name));
err = conduct_rpc (&rpcbuf, &p);
if (!err)
@@ -1068,6 +1066,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
if (protocol_version == 2 && !err)
{
free (rpcbuf);
+ pthread_mutex_lock (&dir->lock);
/* NFSPROC_SYMLINK stupidly does not pass back an
fhandle, so we have to fetch one now. */
@@ -1101,23 +1100,14 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
}
else if (protocol_version == 3)
{
- if (!err)
- {
- pthread_mutex_unlock (&dir->lock);
- pthread_mutex_lock (&np->lock);
- p = recache_handle (p, np);
- p = process_returned_stat (np, p, 1);
- pthread_mutex_unlock (&np->lock);
- pthread_mutex_lock (&dir->lock);
- }
- p = process_wcc_stat (dir, p, !err);
- pthread_mutex_unlock (&dir->lock);
+ /* process_create_reply needs the start of the buffer */
+ p--;
+
+ pthread_mutex_lock (&np->lock);
+ err = process_create_reply (cred, dir, name, &np, p);
+ pthread_mutex_unlock (&np->lock);
}
- else
- pthread_mutex_unlock (&dir->lock);
}
- else
- pthread_mutex_unlock (&dir->lock);
free (rpcbuf);
break;
@@ -1213,19 +1203,9 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
{
- err = nfs_error_trans (ntohl (*p));
- p++;
-
- if (!err)
- {
- pthread_mutex_lock (&np->lock);
- p = recache_handle (p, np);
- p = process_returned_stat (np, p, 1);
- pthread_mutex_unlock (&np->lock);
- }
- pthread_mutex_lock (&dir->lock);
- p = process_wcc_stat (dir, p, !err);
- pthread_mutex_unlock (&dir->lock);
+ pthread_mutex_lock (&np->lock);
+ err = process_create_reply (cred, dir, name, &np, p);
+ pthread_mutex_unlock (&np->lock);
}
free (rpcbuf);
}
@@ -1381,13 +1361,15 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np,
else
err = process_create_reply (cred, np, name, newnp, p);
- if (*newnp && !netfs_validate_stat (*newnp, (struct iouser *) -1))
+ if (protocol_version == 3 && !err)
{
- if ((*newnp)->nn_stat.st_uid != owner)
- err = netfs_attempt_chown ((struct iouser *) -1, *newnp, owner, (*newnp)->nn_stat.st_gid);
+ int *_cs_sattr_encoder (int * sp)
+ {
+ return xdr_encode_create_state (sp, mode, owner);
+ }
- if (!err && (*newnp)->nn_stat.st_mode != mode)
- err = netfs_attempt_chmod (cred, *newnp, mode);
+ err = nfs_setattr_rpc(cred, *newnp, -1, _cs_sattr_encoder);
+ /* Unlink *newnp if err ? */
}
}