ablog

不器用で落着きのない技術者のメモ

ファイルが O_DIRECT フラグを指定してオープンされているか確認する方法

Kernel 2.6.22 以降だと /proc/$pid/fdinfo/$fd で確認できるんですね。

[yazekats@yazekats-linux ~]$ touch test.dat
[yazekats@yazekats-linux ~]$ perl -e 'sysopen($FH, "./test.dat", O_WRONLY | O_TRUNC | O_CREAT | O_ASYNC | O_DIRECT, 0666);sleep' &
[4] 20855
[yazekats@yazekats-linux ~]$ lsof -p 20855
COMMAND   PID     USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
perl    20855 yazekats  cwd    DIR  252,3     4096 20447233 /home/yazekats
perl    20855 yazekats  rtd    DIR  252,1     4096        2 /
perl    20855 yazekats  txt    REG  252,1    13200  2903275 /usr/bin/perl
perl    20855 yazekats  mem    REG  252,1   156872  1967400 /lib64/ld-2.12.so
perl    20855 yazekats  mem    REG  252,1  1922152  1967401 /lib64/libc-2.12.so
perl    20855 yazekats  mem    REG  252,1    22536  1967407 /lib64/libdl-2.12.so
perl    20855 yazekats  mem    REG  252,1   145720  1967402 /lib64/libpthread-2.12.so
perl    20855 yazekats  mem    REG  252,1   598680  1967413 /lib64/libm-2.12.so
perl    20855 yazekats  mem    REG  252,1  1488544  3163718 /usr/lib64/perl5/CORE/libperl.so
perl    20855 yazekats  mem    REG  252,1   113952  1967409 /lib64/libresolv-2.12.so
perl    20855 yazekats  mem    REG  252,1    43392  1967427 /lib64/libcrypt-2.12.so
perl    20855 yazekats  mem    REG  252,1   386040  1967426 /lib64/libfreebl3.so
perl    20855 yazekats  mem    REG  252,1    17520  1967412 /lib64/libutil-2.12.so
perl    20855 yazekats  mem    REG  252,1   116368  1967440 /lib64/libnsl-2.12.so
perl    20855 yazekats  mem    REG  252,1 99158576  2884365 /usr/lib/locale/locale-archive
perl    20855 yazekats    0u   CHR  136,0      0t0        3 /dev/pts/0
perl    20855 yazekats    1u   CHR  136,0      0t0        3 /dev/pts/0
perl    20855 yazekats    2u   CHR  136,0      0t0        3 /dev/pts/0
perl    20855 yazekats    3r   REG  252,3        0 20451124 /home/yazekats/test.dat
perl    20855 yazekats   12r  FIFO    0,8      0t0   214872 pipe
perl    20855 yazekats   13w  FIFO    0,8      0t0   214872 pipe
[yazekats@yazekats-linux ~]$ cat /proc/20855/fdinfo/3
pos:    0
flags:  02100000


追記(2016/11/20):
/proc/$pid/fdinfo/$fd の flags の読み方

Fichiers
P.12

P.13

include/uapi/asm-generic/fcntl.h

#ifndef _ASM_GENERIC_FCNTL_H
#define _ASM_GENERIC_FCNTL_H

#include <linux/types.h>

/*
 * FMODE_EXEC is 0x20
 * FMODE_NONOTIFY is 0x1000000
 * These cannot be used by userspace O_* until internal and external open
 * flags are split.
 * -Eric Paris
 */

/*
 * When introducing new O_* bits, please check its uniqueness in fcntl_init().
 */

#define O_ACCMODE	00000003
#define O_RDONLY	00000000
#define O_WRONLY	00000001
#define O_RDWR		00000002
#ifndef O_CREAT
#define O_CREAT		00000100	/* not fcntl */
#endif
#ifndef O_EXCL
#define O_EXCL		00000200	/* not fcntl */
#endif
#ifndef O_NOCTTY
#define O_NOCTTY	00000400	/* not fcntl */
#endif
#ifndef O_TRUNC
#define O_TRUNC		00001000	/* not fcntl */
#endif
#ifndef O_APPEND
#define O_APPEND	00002000
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK	00004000
#endif
#ifndef O_DSYNC
#define O_DSYNC		00010000	/* used to be O_SYNC, see below */
#endif
#ifndef FASYNC
#define FASYNC		00020000	/* fcntl, for BSD compatibility */
#endif
#ifndef O_DIRECT
#define O_DIRECT	00040000	/* direct disk access hint */
#endif
#ifndef O_LARGEFILE
#define O_LARGEFILE	00100000
#endif
#ifndef O_DIRECTORY
#define O_DIRECTORY	00200000	/* must be a directory */
#endif
#ifndef O_NOFOLLOW
#define O_NOFOLLOW	00400000	/* don't follow links */
#endif
#ifndef O_NOATIME
#define O_NOATIME	01000000
#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC	02000000	/* set close_on_exec */
#endif

/*
 * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using
 * the O_SYNC flag.  We continue to use the existing numerical value
 * for O_DSYNC semantics now, but using the correct symbolic name for it.
 * This new value is used to request true Posix O_SYNC semantics.  It is
 * defined in this strange way to make sure applications compiled against
 * new headers get at least O_DSYNC semantics on older kernels.
 *
 * This has the nice side-effect that we can simply test for O_DSYNC
 * wherever we do not care if O_DSYNC or O_SYNC is used.
 *
 * Note: __O_SYNC must never be used directly.
 */
#ifndef O_SYNC
#define __O_SYNC	04000000
#define O_SYNC		(__O_SYNC|O_DSYNC)
#endif

#ifndef O_PATH
#define O_PATH		010000000
#endif

#ifndef O_NDELAY
#define O_NDELAY	O_NONBLOCK
#endif

#define F_DUPFD		0	/* dup */
#define F_GETFD		1	/* get close_on_exec */
#define F_SETFD		2	/* set/clear close_on_exec */
#define F_GETFL		3	/* get file->f_flags */
#define F_SETFL		4	/* set file->f_flags */
#ifndef F_GETLK
#define F_GETLK		5
#define F_SETLK		6
#define F_SETLKW	7
#endif
#ifndef F_SETOWN
#define F_SETOWN	8	/* for sockets. */
#define F_GETOWN	9	/* for sockets. */
#endif
#ifndef F_SETSIG
#define F_SETSIG	10	/* for sockets. */
#define F_GETSIG	11	/* for sockets. */
#endif

#ifndef CONFIG_64BIT
#ifndef F_GETLK64
#define F_GETLK64	12	/*  using 'struct flock64' */
#define F_SETLK64	13
#define F_SETLKW64	14
#endif
#endif

#ifndef F_SETOWN_EX
#define F_SETOWN_EX	15
#define F_GETOWN_EX	16
#endif

#ifndef F_GETOWNER_UIDS
#define F_GETOWNER_UIDS	17
#endif

#define F_OWNER_TID	0
#define F_OWNER_PID	1
#define F_OWNER_PGRP	2

struct f_owner_ex {
	int	type;
	__kernel_pid_t	pid;
};

/* for F_[GET|SET]FL */
#define FD_CLOEXEC	1	/* actually anything with low bit set goes */

/* for posix fcntl() and lockf() */
#ifndef F_RDLCK
#define F_RDLCK		0
#define F_WRLCK		1
#define F_UNLCK		2
#endif

/* for old implementation of bsd flock () */
#ifndef F_EXLCK
#define F_EXLCK		4	/* or 3 */
#define F_SHLCK		8	/* or 4 */
#endif

/* operations for bsd flock(), also used by the kernel implementation */
#define LOCK_SH		1	/* shared lock */
#define LOCK_EX		2	/* exclusive lock */
#define LOCK_NB		4	/* or'd with one of the above to prevent
				   blocking */
#define LOCK_UN		8	/* remove lock */

#define LOCK_MAND	32	/* This is a mandatory flock ... */
#define LOCK_READ	64	/* which allows concurrent read operations */
#define LOCK_WRITE	128	/* which allows concurrent write operations */
#define LOCK_RW		192	/* which allows concurrent read & write ops */

#define F_LINUX_SPECIFIC_BASE	1024

#ifndef HAVE_ARCH_STRUCT_FLOCK
#ifndef __ARCH_FLOCK_PAD
#define __ARCH_FLOCK_PAD
#endif

struct flock {
	short	l_type;
	short	l_whence;
	__kernel_off_t	l_start;
	__kernel_off_t	l_len;
	__kernel_pid_t	l_pid;
	__ARCH_FLOCK_PAD
};
#endif

#ifndef CONFIG_64BIT

#ifndef HAVE_ARCH_STRUCT_FLOCK64
#ifndef __ARCH_FLOCK64_PAD
#define __ARCH_FLOCK64_PAD
#endif

struct flock64 {
	short  l_type;
	short  l_whence;
	__kernel_loff_t l_start;
	__kernel_loff_t l_len;
	__kernel_pid_t  l_pid;
	__ARCH_FLOCK64_PAD
};
#endif
#endif /* !CONFIG_64BIT */

#endif /* _ASM_GENERIC_FCNTL_H */

普通に lsof で良かったもよう。

$ perl -e 'while(1){printf(qq/%s\n/,q/1/);sleep 10}' > foo.txt
$ lsof +fg -p 32767
COMMAND   PID   USER   FD   TYPE FILE-FLAG DEVICE SIZE/OFF    NODE NAME
(中略)
perl    32767 oracle    1w   REG      W,LG  202,3        0 3522585 /home/oracle/foo.txt
(中略)
$ lsof +fg ~/foo.txt                                                                                                                            
COMMAND   PID   USER   FD   TYPE FILE-FLAG DEVICE SIZE/OFF    NODE NAME
perl    32767 oracle    1w   REG      W,LG  202,3        0 3522585 /home/oracle/foo.txt

$ strace -e open lsof +fg -p 32767  2>&1|grep fdinfo
open("/proc/1147/fdinfo/3", O_RDONLY)   = 4
open("/proc/32767/fdinfo/0", O_RDONLY)  = 7
open("/proc/32767/fdinfo/1", O_RDONLY)  = 7
open("/proc/32767/fdinfo/2", O_RDONLY)  = 7