1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ファイルロック flockの実装 その2

Posted at

詳解Linuxカーネルの12章VFSに関連するコードを読んだ。

カーネルバージョン

v4.1.13

flockとは

manに書いてある。

  • ファイル(inode)に対してロックをかける、引数はファイルディスクリプタ。
  • 排他、共有のロック設定、解除ができる。
  • 勧告ロックである。追記:強制ロックも出来るかも?

プロセスはどうやって判別するのか

file_lock構造体のfl_fileにfile構造体へのポインタが入っているので、それが同一か否かで判定する。
file構造体はopenごとに生成されるので、forkした場合は子プロセスで同じロックを参照することができる。

struct file_lock {
	struct file_lock *fl_next;	/* singly linked list for this inode  */
	struct list_head fl_list;	/* link into file_lock_context */
	struct hlist_node fl_link;	/* node in global lists */
	struct list_head fl_block;	/* circular list of blocked processes */
	fl_owner_t fl_owner;
	unsigned int fl_flags;
	unsigned char fl_type;
	unsigned int fl_pid;
	int fl_link_cpu;		/* what cpu's list is this on? */
	struct pid *fl_nspid;
	wait_queue_head_t fl_wait;
	struct file *fl_file;
	loff_t fl_start;
	loff_t fl_end;

	struct fasync_struct *	fl_fasync; /* for lease break notifications */
	/* for lease breaks: */
	unsigned long fl_break_time;
	unsigned long fl_downgrade_time;

	const struct file_lock_operations *fl_ops;	/* Callbacks for filesystems */
	const struct lock_manager_operations *fl_lmops;	/* Callbacks for lockmanagers */
	union {
		struct nfs_lock_info	nfs_fl;
		struct nfs4_lock_info	nfs4_fl;
		struct {
			struct list_head link;	/* link in AFS vnode's pending_locks list */
			int state;		/* state of grant or error if -ve */
		} afs;
	} fl_u;
};

仕組み

同じfl_file(つまり、同一プロセスの同一fdのファイル)ですでにロックが存在する場合、いままでのロックを消す(正確には、disposeに繋いでout:セクションでまとめて削除している)、ということをしている。
完全に同じロックがかかっていた場合、何もせずにそのまま関数を抜ける。

	list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
		if (request->fl_file != fl->fl_file)
			continue;
		if (request->fl_type == fl->fl_type)
			goto out;
		found = true;
		locks_delete_lock_ctx(fl, &dispose);
		break;
	}

ロックの操作がアンロックだった場合はそのまま関数を抜ける。前のロックは上のブロックで消されている。

	if (request->fl_type == F_UNLCK) {
		if ((request->fl_flags & FL_EXISTS) && !found)
			error = -ENOENT;
		goto out;
	}

次に、ロックの衝突を探す。flock_locks_conflict()は、自分以外からのロックのうち排他ロック(F_WRLOCK)がある場合、もしくは自分がF_WRLOCKで他のロックがあった場合は衝突になる。
MAND_LOCKもチェックしているが・・flockで強制ロックも出来るのかな?ここはまだよくわからない。

find_conflict:
	list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
		if (!flock_locks_conflict(request, fl))
			continue;
		error = -EAGAIN;
		if (!(request->fl_flags & FL_SLEEP))
			goto out;
		error = FILE_LOCK_DEFERRED;
		locks_insert_block(fl, request);
		goto out;
	}

衝突がなければ、ロックを取得する。
関数内ではflc_lockのスピンロックをとっているため処理の競合はない。noblockの指定をしない場合の待ち処理はさらに上位の関数で書かれているようだ。

	locks_copy_lock(new_fl, request);
	locks_insert_lock_ctx(new_fl, &ctx->flc_flock);
	new_fl = NULL;
	error = 0;

参考

Linux におけるファイルの排他制御

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?