static __be32 nfsd_map_status(__be32 status)
{ switch (status) { case nfs_ok: break; case nfserr_nofilehandle: case nfserr_badhandle:
status = nfserr_stale; break; case nfserr_wrongsec: case nfserr_xdev: case nfserr_file_open:
status = nfserr_acces; break; case nfserr_symlink_not_dir:
status = nfserr_notdir; break; case nfserr_symlink: case nfserr_wrong_type:
status = nfserr_inval; break;
} return status;
}
/* * NFSv2 does not differentiate between "set-[ac]time-to-now" * which only requires access, and "set-[ac]time-to-X" which * requires ownership. * So if it looks like it might be "set both to the same time which * is close to now", and if setattr_prepare fails, then we * convert to "set to now" instead of "set to explicit time" * * We only call setattr_prepare as the last test as technically * it is not an interface that we should be using.
*/ #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) #define MAX_TOUCH_TIME_ERROR (30*60) if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) { /* * Looks probable. * * Now just make sure time is in the right ballpark. * Solaris, at least, doesn't seem to care what the time * request is. We require it be within 30 minutes of now.
*/
time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
if (delta < 0)
delta = -delta; if (delta < MAX_TOUCH_TIME_ERROR &&
setattr_prepare(&nop_mnt_idmap, fhp->fh_dentry, iap) != 0) { /* * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. * This will cause notify_change to set these times * to "now"
*/
iap->ia_valid &= ~BOTH_TIME_SET;
}
}
/* * Look up a path name component * Note: the dentry in the resp->fh may be negative if the file * doesn't exist yet. * N.B. After this call resp->fh needs an fh_put
*/ static __be32
nfsd_proc_lookup(struct svc_rqst *rqstp)
{ struct nfsd_diropargs *argp = rqstp->rq_argp; struct nfsd_diropres *resp = rqstp->rq_resp;
/* Obtain buffer pointer for payload. 19 is 1 word for * status, 17 words for fattr, and 1 word for the byte count.
*/
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
/* * CREATE processing is complicated. The keyword here is `overloaded.' * The parent directory is kept locked between the check for existence * and the actual create() call in compliance with VFS protocols. * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
*/ static __be32
nfsd_proc_create(struct svc_rqst *rqstp)
{ struct nfsd_createargs *argp = rqstp->rq_argp; struct nfsd_diropres *resp = rqstp->rq_resp;
svc_fh *dirfhp = &argp->fh;
svc_fh *newfhp = &resp->fh; struct iattr *attr = &argp->attrs; struct nfsd_attrs attrs = {
.na_iattr = attr,
}; struct inode *inode; struct dentry *dchild; int type, mode; int hosterr;
dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
/* First verify the parent file handle */
resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); if (resp->status != nfs_ok) goto done; /* must fh_put dirfhp even on error */
/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
resp->status = nfserr_exist; if (isdotent(argp->name, argp->len)) goto done;
hosterr = fh_want_write(dirfhp); if (hosterr) {
resp->status = nfserrno(hosterr); goto done;
}
inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
dchild = lookup_one(&nop_mnt_idmap, &QSTR_LEN(argp->name, argp->len),
dirfhp->fh_dentry); if (IS_ERR(dchild)) {
resp->status = nfserrno(PTR_ERR(dchild)); goto out_unlock;
}
fh_init(newfhp, NFS_FHSIZE);
resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); if (!resp->status && d_really_is_negative(dchild))
resp->status = nfserr_noent;
dput(dchild); if (resp->status) { if (resp->status != nfserr_noent) goto out_unlock; /* * If the new file handle wasn't verified, we can't tell * whether the file exists or not. Time to bail ...
*/
resp->status = nfserr_acces; if (!newfhp->fh_dentry) {
printk(KERN_WARNING "nfsd_proc_create: file handle not verified\n"); goto out_unlock;
}
}
inode = d_inode(newfhp->fh_dentry);
/* Unfudge the mode bits */ if (attr->ia_valid & ATTR_MODE) {
type = attr->ia_mode & S_IFMT;
mode = attr->ia_mode & ~S_IFMT; if (!type) { /* no type, so if target exists, assume same as that,
* else assume a file */ if (inode) {
type = inode->i_mode & S_IFMT; switch(type) { case S_IFCHR: case S_IFBLK: /* reserve rdev for later checking */
rdev = inode->i_rdev;
attr->ia_valid |= ATTR_SIZE;
fallthrough; case S_IFIFO: /* this is probably a permission check.. * at least IRIX implements perm checking on * echo thing > device-special-file-or-pipe * by doing a CREATE with type==0
*/
resp->status = nfsd_permission(
&rqstp->rq_cred,
newfhp->fh_export,
newfhp->fh_dentry,
NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); if (resp->status && resp->status != nfserr_rofs) goto out_unlock;
}
} else
type = S_IFREG;
}
} elseif (inode) {
type = inode->i_mode & S_IFMT;
mode = inode->i_mode & ~S_IFMT;
} else {
type = S_IFREG;
mode = 0; /* ??? */
}
/* Special treatment for non-regular files according to the * gospel of sun micro
*/ if (type != S_IFREG) { if (type != S_IFBLK && type != S_IFCHR) {
rdev = 0;
} elseif (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { /* If you think you've seen the worst, grok this. */
type = S_IFIFO;
} else { /* Okay, char or block special */ if (!rdev)
rdev = wanted;
}
/* we've used the SIZE information, so discard it */
attr->ia_valid &= ~ATTR_SIZE;
/* Make sure the type and device matches */
resp->status = nfserr_exist; if (inode && inode_wrong_type(inode, type)) goto out_unlock;
}
resp->status = nfs_ok; if (!inode) { /* File doesn't exist. Create it and set attrs */
resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type,
rdev, newfhp);
} elseif (type == S_IFREG) {
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
argp->name, attr->ia_valid, (long) attr->ia_size); /* File already exists. We ignore all attributes except * size, so that creat() behaves exactly like * open(..., O_CREAT|O_TRUNC|O_WRONLY).
*/
attr->ia_valid &= ATTR_SIZE; if (attr->ia_valid)
resp->status = nfsd_setattr(rqstp, newfhp, &attrs,
NULL);
}
/* Unlink. -SIFDIR means file must not be a directory */
resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
argp->name, argp->len);
fh_put(&argp->fh);
resp->status = nfsd_map_status(resp->status); return rpc_success;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.