Skip to content

Commit

Permalink
nfsd: generate pre-modify path permission events
Browse files Browse the repository at this point in the history
When modifying local filesystem via nfsd, call fh_want_write() wrappers
to notify listeners on modification intent.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
  • Loading branch information
amir73il committed Nov 20, 2022
1 parent c4ce5db commit 74b4d66
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 29 deletions.
2 changes: 1 addition & 1 deletion fs/nfsd/nfs2acl.c
Expand Up @@ -107,7 +107,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)

inode = d_inode(fh->fh_dentry);

error = fh_want_write(fh);
error = fh_want_write(fh, ATTR_OTHER);
if (error)
goto out_errno;

Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/nfs3acl.c
Expand Up @@ -97,7 +97,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)

inode = d_inode(fh->fh_dentry);

error = fh_want_write(fh);
error = fh_want_write(fh, ATTR_OTHER);
if (error)
goto out_errno;

Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/nfs3proc.c
Expand Up @@ -256,7 +256,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
parent = fhp->fh_dentry;
inode = d_inode(parent);

host_err = fh_want_write(fhp);
host_err = fh_want_write(fhp, 0);
if (host_err)
return nfserrno(host_err);

Expand Down
4 changes: 2 additions & 2 deletions fs/nfsd/nfs4proc.c
Expand Up @@ -254,7 +254,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
parent = fhp->fh_dentry;
inode = d_inode(parent);

host_err = fh_want_write(fhp);
host_err = fh_want_write(fhp, 0);
if (host_err)
return nfserrno(host_err);

Expand Down Expand Up @@ -1113,7 +1113,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return status;
}
}
err = fh_want_write(&cstate->current_fh);
err = fh_want_write(&cstate->current_fh, setattr->sa_iattr.ia_valid);
if (err)
return nfserrno(err);
status = nfs_ok;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/nfsfh.h
Expand Up @@ -81,7 +81,7 @@ typedef struct svc_fh {
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */

bool fh_want_write; /* remount protection taken */
int fh_write_idx; /* remount protection taken */
bool fh_no_wcc; /* no wcc data needed */
bool fh_no_atomic_attr;
/*
Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/nfsproc.c
Expand Up @@ -286,7 +286,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
resp->status = nfserr_exist;
if (isdotent(argp->name, argp->len))
goto done;
hosterr = fh_want_write(dirfhp);
hosterr = fh_want_fname(dirfhp, argp->name, argp->len, MAY_CREATE);
if (hosterr) {
resp->status = nfserrno(hosterr);
goto done;
Expand Down
83 changes: 75 additions & 8 deletions fs/nfsd/vfs.c
Expand Up @@ -384,6 +384,73 @@ static int __nfsd_setattr(struct dentry *dentry, struct iattr *iap)
return notify_change(&init_user_ns, dentry, iap, NULL);
}

int fh_want_write(struct svc_fh *fh, unsigned int attr)
{
struct path path;
int ret, idx;

if (fh->fh_write_idx >= 0)
return 0;

path.mnt = fh->fh_export->ex_path.mnt;
path.dentry = fh->fh_dentry;
ret = mnt_want_write_path_attr(&path, attr, &idx);
if (!ret)
fh->fh_write_idx = idx;
return ret;
}

int fh_want_fname(struct svc_fh *fh, char *fname, int flen, int mask)
{
struct path path;
struct lookup_result res = {
.last = { .name = fname, .len = flen }
};
int ret, idx;

/*
* XXX: this does not look like it should happen on link/unlink
*/
if (WARN_ON(fh->fh_write_idx >= 0))
return 0;

path.mnt = fh->fh_export->ex_path.mnt;
path.dentry = fh->fh_dentry;
ret = mnt_want_write_parent(&path, mask, &res, &idx);
if (!ret)
fh->fh_write_idx = idx;
return ret;
}

int fh_want_rename(struct svc_fh *ffh, char *fname, int flen,
struct svc_fh *tfh, char *tname, int tlen)
{
struct path oldpath, newpath;
struct lookup_result oldres = {
.last = { .name = fname, .len = flen }
};
struct lookup_result newres = {
.last = { .name = tname, .len = tlen }
};
int ret, idx;

/*
* XXX: this does not look like it should happen on rename
*/
if (WARN_ON(ffh->fh_write_idx >= 0))
return 0;

oldpath.mnt = ffh->fh_export->ex_path.mnt;
oldpath.dentry = ffh->fh_dentry;
newpath.mnt = tfh->fh_export->ex_path.mnt;
newpath.dentry = tfh->fh_dentry;
ret = mnt_want_write_parents(&oldpath, &oldres, &newpath, &newres,
&idx);
if (!ret)
ffh->fh_write_idx = idx;
return ret;
}

/**
* nfsd_setattr - Set various file attributes.
* @rqstp: controlling RPC transaction
Expand Down Expand Up @@ -441,7 +508,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (err)
return err;
if (get_write_count) {
host_err = fh_want_write(fhp);
host_err = fh_want_write(fhp, iap->ia_valid);
if (host_err)
goto out;
}
Expand Down Expand Up @@ -1386,7 +1453,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,

dentry = fhp->fh_dentry;

host_err = fh_want_write(fhp);
host_err = fh_want_fname(fhp, fname, flen, MAY_CREATE);
if (host_err)
return nfserrno(host_err);

Expand Down Expand Up @@ -1486,7 +1553,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (err)
goto out;

host_err = fh_want_write(fhp);
host_err = fh_want_fname(fhp, fname, flen, MAY_CREATE);
if (host_err) {
err = nfserrno(host_err);
goto out;
Expand Down Expand Up @@ -1547,7 +1614,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
if (isdotent(name, len))
goto out;

host_err = fh_want_write(tfhp);
host_err = fh_want_fname(ffhp, name, len, MAY_CREATE);
if (host_err) {
err = nfserrno(host_err);
goto out;
Expand Down Expand Up @@ -1647,7 +1714,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
goto out;

retry:
host_err = fh_want_write(ffhp);
host_err = fh_want_rename(ffhp, fname, flen, tfhp, tname, tlen);
if (host_err) {
err = nfserrno(host_err);
goto out;
Expand Down Expand Up @@ -1762,7 +1829,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (err)
goto out;

host_err = fh_want_write(fhp);
host_err = fh_want_fname(fhp, fname, flen, MAY_DELETE);
if (host_err)
goto out_nfserr;

Expand Down Expand Up @@ -2204,7 +2271,7 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
if (err)
return err;

ret = fh_want_write(fhp);
ret = fh_want_write(fhp, ATTR_OTHER);
if (ret)
return nfserrno(ret);

Expand Down Expand Up @@ -2232,7 +2299,7 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
if (err)
return err;

ret = fh_want_write(fhp);
ret = fh_want_write(fhp, ATTR_OTHER);
if (ret)
return nfserrno(ret);
inode_lock(fhp->fh_dentry->d_inode);
Expand Down
22 changes: 8 additions & 14 deletions fs/nfsd/vfs.h
Expand Up @@ -146,23 +146,17 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
struct dentry *, int);

static inline int fh_want_write(struct svc_fh *fh)
{
int ret;

if (fh->fh_want_write)
return 0;
ret = mnt_want_write(fh->fh_export->ex_path.mnt);
if (!ret)
fh->fh_want_write = true;
return ret;
}
int fh_want_write(struct svc_fh *fh, unsigned int attr);
int fh_want_fname(struct svc_fh *fh, char *fname, int flen, int mask);
int fh_want_rename(struct svc_fh *ffh, char *fname, int flen,
struct svc_fh *tfh, char *tname, int tlen);

static inline void fh_drop_write(struct svc_fh *fh)
{
if (fh->fh_want_write) {
fh->fh_want_write = false;
mnt_drop_write(fh->fh_export->ex_path.mnt);
if (fh->fh_write_idx >= 0) {
mnt_drop_write_idx(fh->fh_export->ex_path.mnt,
fh->fh_write_idx);
fh->fh_write_idx = -1;
}
}

Expand Down

0 comments on commit 74b4d66

Please sign in to comment.