Skip to content

Commit

Permalink
p9fs: Use UNLINKAT instead of REMOVE to implement removals
Browse files Browse the repository at this point in the history
REMOVE doesn't work properly in the face of hard links.  Use UNLINKAT
instead, which is implemented by qemu and bhyve and lets the client
specify the name being removed.

PR:		282432
Reviewed by:	dfr
Differential Revision:	https://reviews.freebsd.org/D47438
  • Loading branch information
markjdb authored and fichtner committed Feb 3, 2025
1 parent 81f1c70 commit ff21b77
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 7 deletions.
21 changes: 21 additions & 0 deletions sys/fs/p9fs/p9_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,27 @@ p9_client_remove(struct p9_fid *fid)
return (error);
}

int
p9_client_unlink(struct p9_fid *dfid, const char *name, int32_t flags)
{
int error;
struct p9_client *clnt;
struct p9_req_t *req;

error = 0;
clnt = dfid->clnt;

req = p9_client_request(clnt, P9PROTO_TUNLINKAT, &error, "dsd",
dfid->fid, name, flags);
if (error != 0) {
P9_DEBUG(PROTO, "RUNLINKAT fid %d\n", dfid->fid);
return (error);
}

p9_free_req(clnt, req);
return (error);
}

/* Inform the file server that the current file represented by fid is no longer
* needed by the client. Any allocated fid on the server needs a clunk to be
* destroyed.
Expand Down
1 change: 1 addition & 0 deletions sys/fs/p9fs/p9_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ int p9_client_write(struct p9_fid *fid, uint64_t offset, uint32_t count, char *d
int p9_client_file_create(struct p9_fid *fid, char *name, uint32_t perm, int mode,
char *extension);
int p9_client_remove(struct p9_fid *fid);
int p9_client_unlink(struct p9_fid *dfid, const char *name, int32_t flags);
int p9_dirent_read(struct p9_client *clnt, char *buf, int start, int len,
struct p9_dirent *dirent);
int p9_client_statfs(struct p9_fid *fid, struct p9_statfs *stat);
Expand Down
2 changes: 2 additions & 0 deletions sys/fs/p9fs/p9_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ struct p9_iattr_dotl {

#define P9PROTO_TGETATTR_BLK 512

#define P9PROTO_UNLINKAT_REMOVEDIR 0x200

/* PDU buffer used for SG lists. */
struct p9_buffer {
uint32_t size;
Expand Down
21 changes: 14 additions & 7 deletions sys/fs/p9fs/p9fs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1497,7 +1497,8 @@ p9fs_write(struct vop_write_args *ap)
* After that, does a node metadata cleanup on client side.
*/
static int
remove_common(struct p9fs_node *np, struct ucred *cred)
remove_common(struct p9fs_node *dnp, struct p9fs_node *np, const char *name,
struct ucred *cred)
{
int error;
struct p9fs_session *vses;
Expand All @@ -1508,21 +1509,23 @@ remove_common(struct p9fs_node *np, struct ucred *cred)
vses = np->p9fs_ses;
vp = P9FS_NTOV(np);

vfid = p9fs_get_fid(vses->clnt, np, cred, VFID, -1, &error);
vfid = p9fs_get_fid(vses->clnt, dnp, cred, VFID, -1, &error);
if (error != 0)
return (error);

error = p9_client_remove(vfid);
error = p9_client_unlink(vfid, name,
np->v_node->v_type == VDIR ? P9PROTO_UNLINKAT_REMOVEDIR : 0);
if (error != 0)
return (error);

/* Remove all non-open fids associated with the vp */
p9fs_fid_remove_all(np, TRUE);
if (np->inode.i_links_count == 1)
p9fs_fid_remove_all(np, TRUE);

/* Invalidate all entries of vnode from name cache and hash list. */
cache_purge(vp);

vfs_hash_remove(vp);

np->flags |= P9FS_NODE_DELETED;

return (error);
Expand All @@ -1537,8 +1540,10 @@ p9fs_remove(struct vop_remove_args *ap)
struct vnode *dvp;
struct p9fs_node *dnp;
struct p9fs_inode *dinode;
struct componentname *cnp;
int error;

cnp = ap->a_cnp;
vp = ap->a_vp;
np = P9FS_VTON(vp);
dvp = ap->a_dvp;
Expand All @@ -1550,7 +1555,7 @@ p9fs_remove(struct vop_remove_args *ap)
if (vp->v_type == VDIR)
return (EISDIR);

error = remove_common(np, ap->a_cnp->cn_cred);
error = remove_common(dnp, np, cnp->cn_nameptr, cnp->cn_cred);
if (error == 0)
P9FS_DECR_LINKS(dinode);

Expand All @@ -1566,8 +1571,10 @@ p9fs_rmdir(struct vop_rmdir_args *ap)
struct vnode *dvp;
struct p9fs_node *dnp;
struct p9fs_inode *dinode;
struct componentname *cnp;
int error;

cnp = ap->a_cnp;
vp = ap->a_vp;
np = P9FS_VTON(vp);
dvp = ap->a_dvp;
Expand All @@ -1576,7 +1583,7 @@ p9fs_rmdir(struct vop_rmdir_args *ap)

P9_DEBUG(VOPS, "%s: vp %p node %p \n", __func__, vp, np);

error = remove_common(np, ap->a_cnp->cn_cred);
error = remove_common(dnp, np, cnp->cn_nameptr, cnp->cn_cred);
if (error == 0)
P9FS_DECR_LINKS(dinode);

Expand Down

0 comments on commit ff21b77

Please sign in to comment.