NetBSD Problem Report #49687
From www@NetBSD.org Mon Feb 23 08:20:38 2015
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 96961A6552
for <gnats-bugs@gnats.NetBSD.org>; Mon, 23 Feb 2015 08:20:38 +0000 (UTC)
Message-Id: <20150223082036.3AA32A65B7@mollari.NetBSD.org>
Date: Mon, 23 Feb 2015 08:20:36 +0000 (UTC)
From: hsuenaga@iij.ad.jp
Reply-To: hsuenaga@iij.ad.jp
To: gnats-bugs@NetBSD.org
Subject: Unexpected truncation of file occurs in open(2) when O_EXLOCK|O_TRUNC specified.
X-Send-Pr-Version: www-1.0
>Number: 49687
>Category: kern
>Synopsis: Unexpected truncation of file occurs in open(2) when O_EXLOCK|O_TRUNC specified.
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Feb 23 08:25:00 +0000 2015
>Originator: Hiroki Suenaga
>Release: NetBSD-current(7.99.5)
>Organization:
Internet Initiative Japan Inc.
>Environment:
NetBSD netbsd2.vmware 7.99.5 NetBSD 7.99.5 (GENERIC) #0: Mon Feb 23 07:25:43 UTC 2015 hsuenaga@netbsd2.vmware:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
If open(2) is called with both of O_EXLOCK(or O_SHLOCK) and O_TRUNC flags specified and it failed to obtain a lock, the file should not be truncated though O_EXLOCK and O_SHLOCK are non-standard extension, and there is no definite specifications.
But, on current NetBSD system, the file is always truncated even if lock operation is failed. This behavior should be fixed.
>How-To-Repeat:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int
main(int argc, char *argv[])
{
int fd0, fd1;
char buf[] = { 't', 'e', 's', 't', '\n'};
char buf2[] = {'\0', '\0', '\0', '\0', '\0'};
char *fname = "./file.txt";
int flag = O_RDWR|O_TRUNC|O_EXLOCK|O_CREAT|O_NONBLOCK;
if ((fd0 = open(fname, flag, 0644)) < 0) {
perror("1st descriptor");
exit(EXIT_FAILURE);
}
if (write(fd0, buf, sizeof(buf)) < 0) {
perror("write");
exit(EXIT_FAILURE);
}
if ((fd1 = open(fname, flag, 0644)) >= 0) {
printf("O_EXLOCK is not working");
exit(EXIT_FAILURE);
}
if (lseek(fd0, 0, SEEK_SET) < 0) {
perror("lseek");
exit(EXIT_FAILURE);
}
if (read(fd0, buf2, sizeof(buf2)) < 0) {
perror("read");
exit(EXIT_FAILURE);
}
if (memcmp(buf, buf2, sizeof(buf)) != 0) {
printf("File is corrupted.\n");
exit(EXIT_FAILURE);
}
printf("OK.\n");
exit(EXIT_SUCCESS);
}
The open(2) of fd1 will be fail because a lock is already held by fd0. In this case, the file "file.txt" should not be truncated and it should keep the data 'test¥n.' But file.txt is truncated after open(2) of fd1.
>Fix:
OpenBSD has fixed the problem. Here is a patch that modified for NetBSD.
Index: vfs_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.493
diff -u -w -p -r1.493 vfs_syscalls.c
--- vfs_syscalls.c 15 Feb 2015 10:48:21 -0000 1.493
+++ vfs_syscalls.c 23 Feb 2015 08:16:59 -0000
@@ -1553,8 +1553,10 @@ do_open(lwp_t *l, struct vnode *dvp, str
struct cwdinfo *cwdi = p->p_cwdi;
file_t *fp;
struct vnode *vp;
+ struct vattr vattr;
int flags, cmode;
int indx, error;
+ int localtrunc = 0;
struct nameidata nd;
if (open_flags & O_SEARCH) {
@@ -1564,6 +1566,10 @@ do_open(lwp_t *l, struct vnode *dvp, str
flags = FFLAGS(open_flags);
if ((flags & (FREAD | FWRITE)) == 0)
return EINVAL;
+ if ((flags & O_TRUNC) && (flags & (O_EXLOCK|O_SHLOCK))) {
+ localtrunc = 1;
+ flags &= ~O_TRUNC;
+ }
if ((error = fd_allocfile(&fp, &indx)) != 0) {
return error;
@@ -1596,6 +1602,25 @@ do_open(lwp_t *l, struct vnode *dvp, str
if ((error = open_setfp(l, fp, vp, indx, flags)))
return error;
+ if (localtrunc) {
+ if ((fp->f_flag & FWRITE) == 0)
+ error = EACCES;
+ else if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ error = EROFS;
+ else if (vp->v_type == VDIR)
+ error = EISDIR;
+ else if ((error = vn_writechk(vp)) == 0) {
+ vattr_null(&vattr);
+ vattr.va_size = 0;
+ error = VOP_SETATTR(vp, &vattr, fp->f_cred);
+ }
+ if (error) {
+ VOP_UNLOCK(vp);
+ closef(fp);
+ return error;
+ }
+ }
+
VOP_UNLOCK(vp);
*fd = indx;
fd_affix(p, fp, indx);
(Contact us)
$NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.