When a_fl->type is F_UNLCK, FreeBSD gives our VOP_ADVLOCK an a_op of
F_UNLCK, instead of F_SETLK like we expect. This causes afs_lockctl to
return EINVAL, since F_UNLCK isn't a normal fcntl lock op, and so
userspace requests to unlock fcntl-style locks always fail. This can
be seen, for example, when trying to use sqlite3 to access a database
that lives in afs.
This F_UNLCK behavior in FreeBSD seems a bit peculiar, but has been
around effectively forever (since 4.4BSD-Lite). So just work around
it.
[adeason@dson.org: minor style adjustments and commit message/comment
rewording.]
Change-Id: I8bfaff9274e40761aa291930430a08b83b524d1b
Reviewed-on: https://gerrit.openafs.org/12579
Reviewed-by: Tim Creech <tcreech@tcreech.com>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
* int a_flags;
* } */ *ap;
{
- int error;
+ int error, a_op;
struct ucred cr = *osi_curcred();
+ a_op = ap->a_op;
+ if (a_op == F_UNLCK) {
+ /*
+ * When a_fl->type is F_UNLCK, FreeBSD passes in an a_op of F_UNLCK.
+ * This is (confusingly) different than how you actually release a lock
+ * with fcntl(), which is done with an a_op of F_SETLK and an l_type of
+ * F_UNLCK. Pretend we were given an a_op of F_SETLK in this case,
+ * since this is what afs_lockctl expects.
+ */
+ a_op = F_SETLK;
+ }
+
AFS_GLOCK();
error =
afs_lockctl(VTOAFS(ap->a_vp),
ap->a_fl,
- ap->a_op, &cr,
+ a_op, &cr,
(int)(intptr_t)ap->a_id); /* XXX: no longer unique! */
AFS_GUNLOCK();
return error;