| 188 | }; |
| 189 | #endif |
| 190 | int |
| 191 | sys_quotactl(struct thread *td, struct quotactl_args *uap) |
| 192 | { |
| 193 | struct mount *mp; |
| 194 | struct nameidata nd; |
| 195 | int error; |
| 196 | |
| 197 | AUDIT_ARG_CMD(uap->cmd); |
| 198 | AUDIT_ARG_UID(uap->uid); |
| 199 | if (!prison_allow(td->td_ucred, PR_ALLOW_QUOTAS)) |
| 200 | return (EPERM); |
| 201 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE, |
| 202 | uap->path, td); |
| 203 | if ((error = namei(&nd)) != 0) |
| 204 | return (error); |
| 205 | NDFREE(&nd, NDF_ONLY_PNBUF); |
| 206 | mp = nd.ni_vp->v_mount; |
| 207 | vfs_ref(mp); |
| 208 | vput(nd.ni_vp); |
| 209 | error = vfs_busy(mp, 0); |
| 210 | if (error != 0) { |
| 211 | vfs_rel(mp); |
| 212 | return (error); |
| 213 | } |
| 214 | error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg); |
| 215 | |
| 216 | /* |
| 217 | * Since quota on operation typically needs to open quota |
| 218 | * file, the Q_QUOTAON handler needs to unbusy the mount point |
| 219 | * before calling into namei. Otherwise, unmount might be |
| 220 | * started between two vfs_busy() invocations (first is our, |
| 221 | * second is from mount point cross-walk code in lookup()), |
| 222 | * causing deadlock. |
| 223 | * |
| 224 | * Require that Q_QUOTAON handles the vfs_busy() reference on |
| 225 | * its own, always returning with ubusied mount point. |
| 226 | */ |
| 227 | if ((uap->cmd >> SUBCMDSHIFT) != Q_QUOTAON && |
| 228 | (uap->cmd >> SUBCMDSHIFT) != Q_QUOTAOFF) |
| 229 | vfs_unbusy(mp); |
| 230 | vfs_rel(mp); |
| 231 | return (error); |
| 232 | } |
| 233 | |
| 234 | /* |
| 235 | * Used by statfs conversion routines to scale the block size up if |
nothing calls this directly
no test coverage detected