suzuna 0.0.1-freebsd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.md +35 -0
- data/README.md +140 -0
- data/Rakefile +106 -0
- data/examples/gate.rb +47 -0
- data/gemstub.rb +23 -0
- data/lib/suzuna.rb +423 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fd5ab88833f46fc0c494ddfa17de68c30a41675a
|
4
|
+
data.tar.gz: c0f42f43c647683708e60c98511ff5ba3188b803
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 134e68effecf0a1f35173b638abaae7307bf969fa81ab5107f1cea8528509eb6fff3cea8f1c6090b7ed1d5ee7b9249d9f4cbfa5b47a3bdbb60645e20d457d1d9
|
7
|
+
data.tar.gz: 8e28be08ec031f7079985be4cd6d2cb1a976906efa2d5848f2d45fba61a5632c07f3c635783740a6fb5d6ffda8d0afb4e59aef061d166923bd829d4db18cde86
|
data/LICENSE.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# suzuna License (2-clause BSD License)
|
2
|
+
|
3
|
+
----
|
4
|
+
|
5
|
+
Copyright (c) 2014, dearblue
|
6
|
+
All rights reserved.
|
7
|
+
|
8
|
+
Redistribution and use in source and binary forms, with or without
|
9
|
+
modification, are permitted provided that the following conditions are met:
|
10
|
+
|
11
|
+
1. Redistributions of source code must retain the above copyright notice,
|
12
|
+
this list of conditions and the following disclaimer.
|
13
|
+
|
14
|
+
2. Redistributions in binary form must reproduce the above copyright
|
15
|
+
notice, this list of conditions and the following disclaimer in the
|
16
|
+
documentation and/or other materials provided with the distribution.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
21
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
22
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
23
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
24
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
25
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
26
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28
|
+
POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
----
|
31
|
+
|
32
|
+
In Japanese.
|
33
|
+
|
34
|
+
日本語訳については次のページが参考になるでしょう:
|
35
|
+
http://www.freebsd.org/ja/copyright/freebsd-license.html
|
data/README.md
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
# suzuna (スズナ)
|
2
|
+
|
3
|
+
The suzuna is a ruby library that provides an infrastructure for virtualized block devices.
|
4
|
+
|
5
|
+
"suzuna" is means "Turnip" in japanese.
|
6
|
+
|
7
|
+
----
|
8
|
+
|
9
|
+
(in Japanese)
|
10
|
+
|
11
|
+
suzuna は ruby 拡張ライブラリで、仮想ブロックデバイス基盤を提供します。
|
12
|
+
|
13
|
+
名称は春の七種の一つである『スズナ』から取りました。
|
14
|
+
|
15
|
+
----
|
16
|
+
|
17
|
+
* product name: suzuna (スズナ / 菘 / カブ / Turnip)
|
18
|
+
* author: dearblue <<dearblue@users.sourceforge.jp>>
|
19
|
+
* license: 2-clause BSD License (二条項 BSD ライセンス)
|
20
|
+
* software quarity: PROTOTYPE
|
21
|
+
* users: rubyist
|
22
|
+
* release number: 0.0.1
|
23
|
+
* memory usage: 1 MB +
|
24
|
+
* installed size: under 1 MB
|
25
|
+
* project page: <http://sourceforge.jp/projects/rutsubo/>
|
26
|
+
* support ruby: ruby-2.0+ <http://www.ruby-lang.org/>
|
27
|
+
* support platforms:
|
28
|
+
* FreeBSD (GEOM Gate / ggate) (ggatel only)
|
29
|
+
* dependency libraries:
|
30
|
+
* ruby - gogyou-0.2+ <https://rubygems.org/gems/gogyou>
|
31
|
+
|
32
|
+
|
33
|
+
## LIBRARY
|
34
|
+
|
35
|
+
``require "suzuna"``
|
36
|
+
|
37
|
+
|
38
|
+
## SYNOPSIS
|
39
|
+
|
40
|
+
``module Suzuna``
|
41
|
+
|
42
|
+
``module Suzuna::Template``
|
43
|
+
|
44
|
+
``Suzuna.join(unit_object)``
|
45
|
+
|
46
|
+
|
47
|
+
## DESCRIPTION
|
48
|
+
|
49
|
+
suzuna は ruby で GEOM Gate を用いて GEOM クラスを書くためのライブラリです。
|
50
|
+
|
51
|
+
``module Suzuna`` は、suzuna の名前空間として使われるモジュールです。
|
52
|
+
|
53
|
+
``module Suzuna::Template`` は、I/O 要求処理を担当するクラスに ``include`` することを想定したモジュールです (必ず必要なモジュールではありません)。このモジュールには、I/O 要求処理に必要となるインスタンスメソッドが予め定義してあります。ただし ``raise NotImplementedError`` を発生させるだけのメソッドがあるので、このようなメソッドは利用者側で実装する必要があります。このあたりは [EXAMPLE](#label-EXAMPLE) が参考になると思います。
|
54
|
+
|
55
|
+
``Suzuna.join(unit_object)`` は、I/O 要求処理オブジェクトを与えて実際に GEOM Gate オブジェクトを作成するためのメソッドです。***このメソッドはスレッドを停止させます。現在の実装では、このメソッドから返ってくる場面は例外が発生した時のみとなります。***
|
56
|
+
|
57
|
+
|
58
|
+
## EXAMPLE
|
59
|
+
|
60
|
+
以下は FreeBSD 上でローカルな GEOM Gate (ggate) を用いた、ruby による仮想ブロックデバイスプログラミングです。
|
61
|
+
|
62
|
+
``` ruby:ruby
|
63
|
+
#!ruby
|
64
|
+
|
65
|
+
require "stringio"
|
66
|
+
require "fattr"
|
67
|
+
require "suzuna"
|
68
|
+
|
69
|
+
class MyUnit
|
70
|
+
include Suzuna::Template
|
71
|
+
|
72
|
+
fattr(:mediasize) { @pool.size }
|
73
|
+
fattr sectorsize: 512,
|
74
|
+
timeout: 30,
|
75
|
+
flags: 0 # or Suzuna::G_GATE_FLAG_READONLY
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
@pool = File.open("testsuzuna.img", File::BINARY | File::RDWR | File::CREAT)
|
79
|
+
@pool.truncate(80.MiB) unless @pool.size >= 80.MiB
|
80
|
+
end
|
81
|
+
|
82
|
+
def cleanup
|
83
|
+
@pool.flush rescue nil
|
84
|
+
@pool.close rescue nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def read(offset, size, buf)
|
88
|
+
puts "#{File.basename caller(0, 1)[0]}: offset=#{offset}, size=#{size}"
|
89
|
+
@pool.pos = offset
|
90
|
+
@pool.read(size, buf)
|
91
|
+
buf.resize(size)
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def write(offset, buf)
|
96
|
+
puts "#{File.basename caller(0, 1)[0]}: offset=#{offset}, size=#{buf.bytesize}"
|
97
|
+
@pool.pos = offset
|
98
|
+
@pool.write(buf)
|
99
|
+
nil
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete(offset, size)
|
103
|
+
puts "#{File.basename caller(0, 1)[0]}: offset=#{offset}, size=#{size}"
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
Suzuna.join(MyUnit.new)
|
109
|
+
```
|
110
|
+
|
111
|
+
これを管理者権限で実行すると `/dev/ggate0` が作成されて、`/dev/ada0` や `/dev/da0` などと同様の扱いをすることが出来ます。
|
112
|
+
|
113
|
+
停止させる場合は、`Ctrl+C` をするか、他の(擬似)端末から `$ sudo ggate -du0` と入力します。
|
114
|
+
|
115
|
+
環境によっては ``/usr/local/lib/ruby/gems/2.1/gems/suzuna-0.0.1-freebsd/lib/suzuna.rb:in `initialize': No such file or directory @ rb_sysopen - /dev/ggctl (Errno::ENOENT)`` などと例外が出るかもしれません。この場合はカーネルに `geom_gate.ko` を読み込ませてから試して下さい。
|
116
|
+
|
117
|
+
``` shell:shell
|
118
|
+
$ sudo kldload geom_gate
|
119
|
+
```
|
120
|
+
|
121
|
+
|
122
|
+
## DEMERIT
|
123
|
+
|
124
|
+
* geom gate + ruby のため、実行性能はカーネルに置かれた geom オブジェクトよりもかなり劣ります。
|
125
|
+
|
126
|
+
個人・研究用途としては十分かもしれませんが、大規模な用途には向かないでしょう。
|
127
|
+
|
128
|
+
* geom gate ネットワークデーモンとしての機能は持っていません。
|
129
|
+
|
130
|
+
``ggated`` を組み合わせて利用できるかもしれません (試していません)。
|
131
|
+
|
132
|
+
* 現在の実装は、マルチスレッド化されていません。
|
133
|
+
|
134
|
+
I/O 要求の処理は単体のスレッドのみで行われます。
|
135
|
+
|
136
|
+
## SEE ALSO
|
137
|
+
|
138
|
+
* [geom(4)](http://www.freebsd.org/cgi/man.cgi?sektion=4&query=geom),
|
139
|
+
[geom(8)](http://www.freebsd.org/cgi/man.cgi?sektion=8&query=geom),
|
140
|
+
[ggatel(8)](http://www.freebsd.org/cgi/man.cgi?sektion=8&query=ggatel)
|
data/Rakefile
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
require "rake/clean"
|
3
|
+
|
4
|
+
DOC = FileList["{README,LICENSE,CHANGELOG,Changelog}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"] +
|
5
|
+
FileList["ext/**/{README,LICENSE,CHANGELOG,Changelog}{,.ja}{,.txt,.rd,.rdoc,.md,.markdown}"]
|
6
|
+
#EXT = FileList["ext/**/*.{h,hh,c,cc,cpp,cxx}"] +
|
7
|
+
# FileList["ext/externals/**/*"]
|
8
|
+
EXT = FileList["ext/**/*"]
|
9
|
+
BIN = FileList["bin/*"]
|
10
|
+
LIB = FileList["lib/**/*.rb"]
|
11
|
+
SPEC = FileList["spec/**/*"]
|
12
|
+
EXAMPLE = FileList["examples/**/*"]
|
13
|
+
RAKEFILE = [File.basename(__FILE__), "gemstub.rb"]
|
14
|
+
EXTRA = []
|
15
|
+
|
16
|
+
load "gemstub.rb"
|
17
|
+
|
18
|
+
EXTCONF = FileList["ext/extconf.rb"]
|
19
|
+
EXTCONF.reject! { |n| !File.file?(n) }
|
20
|
+
GEMSTUB.extensions += EXTCONF
|
21
|
+
GEMSTUB.executables += FileList["bin/*"].map { |n| File.basename n }
|
22
|
+
|
23
|
+
GEMFILE = "#{GEMSTUB.name}-#{GEMSTUB.version}.gem"
|
24
|
+
GEMSPEC = "#{GEMSTUB.name}.gemspec"
|
25
|
+
|
26
|
+
GEMSTUB.files += DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + RAKEFILE + EXTRA
|
27
|
+
GEMSTUB.rdoc_options ||= %w(--charset UTF-8)
|
28
|
+
GEMSTUB.extra_rdoc_files += DOC + LIB + EXT.reject { |n| n.include?("/externals/") || !%w(.h .hh .c .cc .cpp .cxx).include?(File.extname(n)) }
|
29
|
+
|
30
|
+
CLEAN << GEMSPEC
|
31
|
+
CLOBBER << GEMFILE
|
32
|
+
|
33
|
+
task :default => :all
|
34
|
+
|
35
|
+
task :all => GEMFILE
|
36
|
+
|
37
|
+
task :rdoc => DOC + EXT + LIB do
|
38
|
+
sh *(%w(rdoc) + GEMSTUB.rdoc_options + DOC + EXT + LIB)
|
39
|
+
end
|
40
|
+
|
41
|
+
file GEMFILE => DOC + EXT + EXTCONF + BIN + LIB + SPEC + EXAMPLE + RAKEFILE + [GEMSPEC] do
|
42
|
+
sh "gem build #{GEMSPEC}"
|
43
|
+
end
|
44
|
+
|
45
|
+
file GEMSPEC => RAKEFILE do
|
46
|
+
File.write(GEMSPEC, GEMSTUB.to_ruby, mode: "wb")
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
RUBYSET ||= nil
|
51
|
+
|
52
|
+
if RUBYSET && !RUBYSET.empty? && !EXTCONF.empty?
|
53
|
+
RUBY_VERSIONS = RUBYSET.map do |ruby|
|
54
|
+
ver = `#{ruby} --disable gem -rrbconfig -e "puts RbConfig::CONFIG['ruby_version']"`.chomp
|
55
|
+
raise "failed ruby checking - ``#{ruby}''" unless $?.success?
|
56
|
+
[ver, ruby]
|
57
|
+
end
|
58
|
+
SOFILES_SET = RUBY_VERSIONS.map { |(ver, ruby)| ["lib/#{ver}/#{GEMSTUB.name}.so", ruby] }
|
59
|
+
SOFILES = SOFILES_SET.map { |(lib, ruby)| lib }
|
60
|
+
platforms = RUBYSET.map { |ruby| `#{ruby} -rubygems -e "puts Gem::Platform.local.to_s"`.chomp }
|
61
|
+
platforms.uniq!
|
62
|
+
platforms.compact!
|
63
|
+
unless platforms.size == 1
|
64
|
+
raise "wrong platforms (#{RUBYSET.inspect} => #{platforms.inspect})"
|
65
|
+
end
|
66
|
+
|
67
|
+
GEMSTUB_NATIVE = GEMSTUB.dup
|
68
|
+
GEMSTUB_NATIVE.files += SOFILES
|
69
|
+
GEMSTUB_NATIVE.platform = platforms[0]
|
70
|
+
GEMFILE_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.version}-#{GEMSTUB_NATIVE.platform}.gem"
|
71
|
+
GEMSPEC_NATIVE = "#{GEMSTUB_NATIVE.name}-#{GEMSTUB_NATIVE.platform}.gemspec"
|
72
|
+
|
73
|
+
task :all => [GEMFILE, :native]
|
74
|
+
|
75
|
+
task :native => GEMFILE_NATIVE
|
76
|
+
|
77
|
+
file GEMFILE_NATIVE => DOC + EXT + [EXTCONF] + BIN + LIB + SPEC + EXAMPLE + SOFILES + RAKEFILE + [GEMSPEC_NATIVE] do
|
78
|
+
sh "gem build #{GEMSPEC_NATIVE}"
|
79
|
+
end
|
80
|
+
|
81
|
+
file GEMSPEC_NATIVE => __FILE__ do
|
82
|
+
File.write(GEMSPEC_NATIVE, GEMSTUB_NATIVE.to_ruby, mode: "wb")
|
83
|
+
end
|
84
|
+
|
85
|
+
SOFILES_SET.each do |(soname, ruby)|
|
86
|
+
sodir = File.dirname(soname)
|
87
|
+
makefile = File.join(sodir, "Makefile")
|
88
|
+
|
89
|
+
CLEAN << GEMSPEC_NATIVE << sodir
|
90
|
+
CLOBBER << GEMFILE_NATIVE
|
91
|
+
|
92
|
+
directory sodir
|
93
|
+
|
94
|
+
file soname => [makefile] + EXT do
|
95
|
+
cd sodir do
|
96
|
+
sh "make"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
file makefile => [sodir] + [EXTCONF] do
|
101
|
+
cd sodir do
|
102
|
+
sh "#{ruby} ../../#{EXTCONF} \"--ruby=#{ruby}\""
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/examples/gate.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
require "fattr"
|
5
|
+
require "suzuna"
|
6
|
+
|
7
|
+
class MyUnit
|
8
|
+
include Suzuna::Template
|
9
|
+
|
10
|
+
fattr(:mediasize) { @pool.size }
|
11
|
+
fattr sectorsize: 512,
|
12
|
+
timeout: 30,
|
13
|
+
flags: 0 # or Suzuna::G_GATE_FLAG_READONLY
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
#@pool = StringIO.new(String.alloc(80.MiB))
|
17
|
+
@pool = File.open("testsuzuna.img", File::BINARY | File::RDWR | File::CREAT)
|
18
|
+
@pool.truncate(80.MiB) unless @pool.size >= 80.MiB
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleanup
|
22
|
+
@pool.flush rescue nil
|
23
|
+
@pool.close rescue nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def read(offset, size, buf)
|
27
|
+
puts "#{File.basename caller(0, 1)[0]}: offset=#{offset}, size=#{size}"
|
28
|
+
@pool.pos = offset
|
29
|
+
@pool.read(size, buf)
|
30
|
+
buf.resize(size)
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def write(offset, buf)
|
35
|
+
puts "#{File.basename caller(0, 1)[0]}: offset=#{offset}, size=#{buf.bytesize}"
|
36
|
+
@pool.pos = offset
|
37
|
+
@pool.write(buf)
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(offset, size)
|
42
|
+
puts "#{File.basename caller(0, 1)[0]}: offset=#{offset}, size=#{size}"
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Suzuna.join(MyUnit.new)
|
data/gemstub.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
require_relative "lib/suzuna"
|
3
|
+
|
4
|
+
GEMSTUB = Gem::Specification.new do |s|
|
5
|
+
s.name = "suzuna"
|
6
|
+
s.version = Suzuna::VERSION
|
7
|
+
s.platform = "freebsd"
|
8
|
+
s.summary = "Soft volume infrastructure for ruby"
|
9
|
+
s.description = <<EOS
|
10
|
+
``suzuna'' is software volume infrastructure for ruby.
|
11
|
+
|
12
|
+
Support platform is FreeBSD GEOM only.
|
13
|
+
EOS
|
14
|
+
s.license = "2-clause BSD License"
|
15
|
+
s.author = "dearblue"
|
16
|
+
s.email = "dearblue@users.sourceforge.jp"
|
17
|
+
s.homepage = "http://sourceforge.jp/projects/rutsubo/"
|
18
|
+
|
19
|
+
s.required_ruby_version = ">= 2.0"
|
20
|
+
s.add_development_dependency "rspec", "~> 2.14"
|
21
|
+
s.add_development_dependency "rake", "~> 10.0"
|
22
|
+
s.add_runtime_dependency "gogyou", "~> 0.2"
|
23
|
+
end
|
data/lib/suzuna.rb
ADDED
@@ -0,0 +1,423 @@
|
|
1
|
+
require "gogyou"
|
2
|
+
|
3
|
+
module Suzuna
|
4
|
+
Suzuna = self
|
5
|
+
VERSION = Gem::Version.new "0.0.1"
|
6
|
+
|
7
|
+
G_GATE_CTL_NAME = "/dev/ggctl"
|
8
|
+
G_GATE_TIMEOUT = 0
|
9
|
+
G_GATE_UNIT_AUTO = -1
|
10
|
+
G_GATE_PROVIDER_NAME = "ggate"
|
11
|
+
|
12
|
+
G_GATE_FLAG_READWRITE = 0x0000
|
13
|
+
G_GATE_FLAG_READONLY = 0x0001
|
14
|
+
G_GATE_FLAG_WRITEONLY = 0x0002
|
15
|
+
G_GATE_FLAG_DESTROY = 0x1000
|
16
|
+
G_GATE_USERFLAGS = G_GATE_FLAG_READONLY | G_GATE_FLAG_WRITEONLY
|
17
|
+
|
18
|
+
G_GATE_VERSION = 3
|
19
|
+
|
20
|
+
BIO_READ = 0x01
|
21
|
+
BIO_WRITE = 0x02
|
22
|
+
BIO_DELETE = 0x04
|
23
|
+
|
24
|
+
#
|
25
|
+
# suzuna 固有の例外が include しているモジュールです。
|
26
|
+
#
|
27
|
+
# rescue で一括して受け取るために用意されています。
|
28
|
+
#
|
29
|
+
module Exceptions
|
30
|
+
end
|
31
|
+
|
32
|
+
class DestroyedGate < Errno::ENXIO
|
33
|
+
include Exceptions
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# I/O 要求処理の基本機能のみを実装したモジュールです。
|
38
|
+
#
|
39
|
+
# クラスやモジュールに include することを想定しています。
|
40
|
+
#
|
41
|
+
# 必要なインスタンスメソッドは include したクラスで再定義して下さい。
|
42
|
+
#
|
43
|
+
module Template
|
44
|
+
#
|
45
|
+
# このメソッドはデバイスの大きさを取得するために呼ばれます。
|
46
|
+
#
|
47
|
+
# /dev 以下に geom gate オブジェクトとして作成される前に呼ばれます。
|
48
|
+
#
|
49
|
+
# 戻り値として 0以上で sectorsize の整数倍となる整数を返して下さい。
|
50
|
+
#
|
51
|
+
def mediasize
|
52
|
+
raise NotImplementedError, "IMPLEMENT ME! #mediasize -> integer"
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# このメソッドはデバイスの読み書き特性を取得するために呼ばれます。
|
57
|
+
#
|
58
|
+
# /dev 以下に geom gate オブジェクトとして作成される前に呼ばれます。
|
59
|
+
#
|
60
|
+
# 戻り値として G_GATE_FLAG_READWRITE、G_GATE_FLAG_READONLY、G_GATE_FLAG_WRITEONLY のいずれかを返して下さい。
|
61
|
+
#
|
62
|
+
def flags
|
63
|
+
G_GATE_FLAG_READONLY
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# このメソッドはデバイスのセクタサイズ (読み書きの最小単位) を取得するために呼ばれます。
|
68
|
+
#
|
69
|
+
# /dev 以下に geom gate オブジェクトとして作成される前に呼ばれます。
|
70
|
+
#
|
71
|
+
# 戻り値として正の整数値を返して下さい。
|
72
|
+
#
|
73
|
+
def sectorsize
|
74
|
+
512
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# このメソッドはデバイスのテキスト情報を取得するために呼ばれます。
|
79
|
+
#
|
80
|
+
# /dev 以下に geom gate オブジェクトとして作成される前に呼ばれます。
|
81
|
+
#
|
82
|
+
# 戻り値として nil か 2048 バイト未満の文字列を返して下さい。
|
83
|
+
#
|
84
|
+
def info
|
85
|
+
"#{Suzuna}-#{VERSION} (powered by #{RUBY_ENGINE})"
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# このメソッドはデバイスの要求処理の最大待機時間を取得するために呼ばれます。
|
90
|
+
#
|
91
|
+
# /dev 以下に geom gate オブジェクトとして作成される前に呼ばれます。
|
92
|
+
#
|
93
|
+
# 戻り値として正の整数値を返して下さい。0 は無制限とみなされます。
|
94
|
+
#
|
95
|
+
def timeout
|
96
|
+
60
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# このメソッドはデバイスのユニット番号を取得するために呼ばれます。
|
101
|
+
#
|
102
|
+
# /dev 以下に geom gate オブジェクトとして作成される前に呼ばれます。
|
103
|
+
#
|
104
|
+
# 戻り値として正の整数値か、G_GATE_UNIT_AUTO を返して下さい。
|
105
|
+
#
|
106
|
+
def unit
|
107
|
+
G_GATE_UNIT_AUTO
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# このメソッドは geom gate オブジェクトが破棄されたあとに呼ばれます。
|
112
|
+
#
|
113
|
+
# 仮想デバイスの終了処理などを目的として用意されています。
|
114
|
+
#
|
115
|
+
# 戻り値は無視されます。
|
116
|
+
#
|
117
|
+
def cleanup
|
118
|
+
nil
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# このメソッドは geom gate オブジェクトに対して読み込み要求があった時に呼ばれます。
|
123
|
+
#
|
124
|
+
# 文字列オブジェクトである buf に読み込んだデータを転写して下さい。
|
125
|
+
#
|
126
|
+
# 戻り値として、処理の成否である Errno::EXXX クラスかそのインスタンス、errno の整数値を返して下さい。
|
127
|
+
# 正常な場合には、nil を返すことで Errno::NOERROR と認識されます。
|
128
|
+
#
|
129
|
+
def read(offset, size, buf)
|
130
|
+
raise NotImplementedError, "IMPLEMENT ME! #read(offset, size, buf) -> errno"
|
131
|
+
end
|
132
|
+
|
133
|
+
#
|
134
|
+
# このメソッドは geom gate オブジェクトに対して書き込み要求があった時に呼ばれます。
|
135
|
+
#
|
136
|
+
# 文字列オブジェクトである buf を書き込む処理を行って下さい。
|
137
|
+
#
|
138
|
+
# 戻り値として、処理の成否である Errno::EXXX クラスかそのインスタンス、errno の整数値を返して下さい。
|
139
|
+
# 正常な場合には、nil を返すことで Errno::NOERROR と認識されます。
|
140
|
+
#
|
141
|
+
def write(offset, buf)
|
142
|
+
raise NotImplementedError, "IMPLEMENT ME! #write(offset, buf) -> errno"
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
# このメソッドは geom gate オブジェクトに対してセクタの削除(解放)要求があった時に呼ばれます。
|
147
|
+
#
|
148
|
+
# 戻り値として、処理の成否である Errno::EXXX クラスかそのインスタンス、errno の整数値を返して下さい。
|
149
|
+
# 正常な場合には、nil を返すことで Errno::NOERROR と認識されます。
|
150
|
+
#
|
151
|
+
def delete(offset, size)
|
152
|
+
raise NotImplementedError, "IMPLEMENT ME! #delete(offset, size) -> errno"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.join(unitobj)
|
157
|
+
unit = IOCTL::Create.post(unitobj.mediasize, unitobj.flags,
|
158
|
+
sectorsize: unitobj.sectorsize, info: unitobj.info,
|
159
|
+
timeout: unitobj.timeout, unit: unitobj.unit)
|
160
|
+
|
161
|
+
begin
|
162
|
+
mainloop(unitobj, unit)
|
163
|
+
ensure
|
164
|
+
IOCTL::Destroy.post(unit, true) rescue nil unless $!.kind_of?(DestroyedGate)
|
165
|
+
unitobj.cleanup
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.mainloop(unitobj, unit)
|
170
|
+
ioc = IOCTL::IOReq.new
|
171
|
+
ioc.start.version = G_GATE_VERSION
|
172
|
+
ioc.start.unit = unit
|
173
|
+
bufsize = unitobj.sectorsize
|
174
|
+
buf = String.alloc(bufsize)
|
175
|
+
ioc.start.data = buf.to_ptr
|
176
|
+
|
177
|
+
while true
|
178
|
+
while true
|
179
|
+
ioc.start.data = buf.to_ptr
|
180
|
+
ioc.start.length = buf.bytesize
|
181
|
+
ioc.start.error = 0
|
182
|
+
begin
|
183
|
+
ioc.start.post
|
184
|
+
rescue Errno::ENXIO
|
185
|
+
raise DestroyedGate, "/dev/ggate#{unit}"
|
186
|
+
end
|
187
|
+
|
188
|
+
case ioc.start.error
|
189
|
+
when Errno::NOERROR::Errno
|
190
|
+
# nothing to do here
|
191
|
+
when Errno::ECANCELED::Errno, Errno::ENXIO::Errno
|
192
|
+
raise DestroyedGate, "/dev/ggate#{unit}"
|
193
|
+
when Errno::ENOMEM::Errno
|
194
|
+
buf.resize(bufsize = ioc.start.length)
|
195
|
+
unless buf.bytesize == bufsize
|
196
|
+
raise Errno::ENOMEM, <<-EOM.chomp
|
197
|
+
#{G_GATE_CTL_NAME} (require size = #{bufsize}, but allocated size = #{buf.bytesize})
|
198
|
+
EOM
|
199
|
+
end
|
200
|
+
break
|
201
|
+
else
|
202
|
+
raise SystemCallError.new("#{G_GATE_CTL_NAME} (ioctl)", ioc.start.error)
|
203
|
+
end
|
204
|
+
|
205
|
+
catch(:break) do
|
206
|
+
begin
|
207
|
+
case ioc.start.cmd
|
208
|
+
when BIO_READ
|
209
|
+
if ioc.start.length > bufsize
|
210
|
+
buf.resize(bufsize = ioc.start.length)
|
211
|
+
unless buf.bytesize == bufsize
|
212
|
+
ioc.done.error = Errno::ENOMEM::Errno
|
213
|
+
throw :break
|
214
|
+
end
|
215
|
+
end
|
216
|
+
ioc.done.error = err2code(unitobj.read(ioc.start.offset, ioc.start.length, buf))
|
217
|
+
ioc.done.data = buf.to_ptr
|
218
|
+
when BIO_DELETE
|
219
|
+
ioc.done.error = err2code(unitobj.delete(ioc.start.offset, ioc.start.length))
|
220
|
+
when BIO_WRITE
|
221
|
+
buf.resize(ioc.start.length)
|
222
|
+
ioc.done.error = err2code(unitobj.write(ioc.start.offset, buf))
|
223
|
+
buf.resize(bufsize)
|
224
|
+
ioc.done.data = buf.to_ptr
|
225
|
+
else
|
226
|
+
ioc.done.error = Errno::EOPNOTSUPP::Errno
|
227
|
+
end
|
228
|
+
rescue BasicObject
|
229
|
+
ioc.done.error = Errno::EFAULT::Errno
|
230
|
+
raise
|
231
|
+
ensure
|
232
|
+
#p err: SystemCallError.new(ioc.done.error)
|
233
|
+
ioc.done.post
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
raise Exception, "!!BUG!! - SHALL NOT REACHED HERE!"
|
240
|
+
end
|
241
|
+
|
242
|
+
def self.err2code(err)
|
243
|
+
case err
|
244
|
+
when nil
|
245
|
+
Errno::NOERROR::Errno
|
246
|
+
when Class
|
247
|
+
err::Errno
|
248
|
+
when Integer
|
249
|
+
err.to_i
|
250
|
+
else
|
251
|
+
err.errno
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
module IOCTL
|
256
|
+
module IOC
|
257
|
+
IOCPARM_SHIFT = 13
|
258
|
+
IOCPARM_MASK = ~(~0 << IOCPARM_SHIFT)
|
259
|
+
IOC_IN = 0x80000000
|
260
|
+
IOC_OUT = 0x40000000
|
261
|
+
IOC_INOUT = IOC_IN | IOC_OUT
|
262
|
+
|
263
|
+
def _IOC(inout, group, num, len)
|
264
|
+
inout.to_i | ((len.to_i & IOCPARM_MASK) << 16) | (group.to_i << 8) | num.to_i
|
265
|
+
end
|
266
|
+
|
267
|
+
def _IOWR(g, n, t)
|
268
|
+
_IOC(IOC_INOUT, g.to_i, n.to_i, t.bytesize)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
NAME_MAX = 255
|
273
|
+
|
274
|
+
G_GATE_INFOSIZE = 2048
|
275
|
+
|
276
|
+
GG_MODIFY_MEDIASIZE = 0x01
|
277
|
+
GG_MODIFY_INFO = 0x02
|
278
|
+
GG_MODIFY_READPROV = 0x04
|
279
|
+
GG_MODIFY_READOFFSET = 0x08
|
280
|
+
|
281
|
+
@@devfd = File.open(G_GATE_CTL_NAME, File::RDWR)
|
282
|
+
|
283
|
+
# :nodoc:
|
284
|
+
def self.ioctl(req, data)
|
285
|
+
@@devfd.ioctl(req, data)
|
286
|
+
end
|
287
|
+
|
288
|
+
module CommonModule
|
289
|
+
def post
|
290
|
+
IOCTL.ioctl(self.class::REQ, to_buffer)
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
extend Gogyou
|
295
|
+
|
296
|
+
typedef :uint64_t, :off_t
|
297
|
+
|
298
|
+
Create = struct {
|
299
|
+
uint :version
|
300
|
+
off_t :mediasize
|
301
|
+
uint :sectorsize
|
302
|
+
uint :flags
|
303
|
+
uint :maxcount
|
304
|
+
uint :timeout
|
305
|
+
char :name, NAME_MAX
|
306
|
+
char :info, G_GATE_INFOSIZE
|
307
|
+
char :readprov, NAME_MAX
|
308
|
+
off_t :readoffset
|
309
|
+
int :unit
|
310
|
+
}
|
311
|
+
|
312
|
+
class Create
|
313
|
+
include CommonModule
|
314
|
+
extend IOC
|
315
|
+
|
316
|
+
REQ = _IOWR("m".ord, 0, self)
|
317
|
+
|
318
|
+
def self.post(mediasize, flags, sectorsize: 512, info: nil, timeout: G_GATE_TIMEOUT, unit: G_GATE_UNIT_AUTO)
|
319
|
+
ioc = IOCTL::Create.new
|
320
|
+
ioc.version = G_GATE_VERSION
|
321
|
+
ioc.unit = unit ? unit : G_GATE_UNIT_AUTO
|
322
|
+
ioc.mediasize = mediasize
|
323
|
+
ioc.sectorsize = sectorsize
|
324
|
+
ioc.timeout = timeout
|
325
|
+
ioc.flags = flags
|
326
|
+
ioc.maxcount = 0
|
327
|
+
ioc.info = info if info
|
328
|
+
ioc.post
|
329
|
+
|
330
|
+
if unit == G_GATE_UNIT_AUTO
|
331
|
+
puts "%s%u\n" % [G_GATE_PROVIDER_NAME, ioc.unit]
|
332
|
+
end
|
333
|
+
|
334
|
+
ioc.unit
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
Modify = struct {
|
339
|
+
uint :version
|
340
|
+
int :unit
|
341
|
+
uint32_t :modify
|
342
|
+
off_t :mediasize
|
343
|
+
char :info, G_GATE_INFOSIZE
|
344
|
+
char :readprov, NAME_MAX
|
345
|
+
off_t :readoffset
|
346
|
+
}
|
347
|
+
|
348
|
+
class Modify
|
349
|
+
include CommonModule
|
350
|
+
extend IOC
|
351
|
+
|
352
|
+
REQ = _IOWR("m".ord, 1, self)
|
353
|
+
end
|
354
|
+
|
355
|
+
Destroy = struct {
|
356
|
+
uint :version
|
357
|
+
int :unit
|
358
|
+
int :force
|
359
|
+
char :name, NAME_MAX
|
360
|
+
}
|
361
|
+
|
362
|
+
class Destroy
|
363
|
+
include CommonModule
|
364
|
+
extend IOC
|
365
|
+
|
366
|
+
REQ = _IOWR("m".ord, 2, self)
|
367
|
+
|
368
|
+
def self.post(unit, force = false)
|
369
|
+
cmd = IOCTL::Destroy.new
|
370
|
+
cmd.version = G_GATE_VERSION
|
371
|
+
cmd.unit = unit
|
372
|
+
cmd.force = force ? 1 : 0
|
373
|
+
cmd.post
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
Cancel = struct {
|
378
|
+
uint :version
|
379
|
+
int :unit
|
380
|
+
uintptr_t :seq
|
381
|
+
char :name, NAME_MAX
|
382
|
+
}
|
383
|
+
|
384
|
+
class Cancel
|
385
|
+
include CommonModule
|
386
|
+
extend IOC
|
387
|
+
|
388
|
+
REQ = _IOWR("m".ord, 3, self)
|
389
|
+
end
|
390
|
+
|
391
|
+
CtlIO = struct {
|
392
|
+
uint :version
|
393
|
+
int :unit
|
394
|
+
uintptr_t :seq
|
395
|
+
uint :cmd
|
396
|
+
off_t :offset
|
397
|
+
off_t :length
|
398
|
+
uintptr_t :data # void *gctl_data
|
399
|
+
int :error
|
400
|
+
}
|
401
|
+
|
402
|
+
class Start < CtlIO
|
403
|
+
include CommonModule
|
404
|
+
extend IOC
|
405
|
+
|
406
|
+
REQ = _IOWR("m".ord, 4, self)
|
407
|
+
end
|
408
|
+
|
409
|
+
class Done < CtlIO
|
410
|
+
include CommonModule
|
411
|
+
extend IOC
|
412
|
+
|
413
|
+
REQ = _IOWR("m".ord, 5, self)
|
414
|
+
end
|
415
|
+
|
416
|
+
IOReq = struct {
|
417
|
+
union {
|
418
|
+
Start :start
|
419
|
+
Done :done
|
420
|
+
}
|
421
|
+
}
|
422
|
+
end
|
423
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: suzuna
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: freebsd
|
6
|
+
authors:
|
7
|
+
- dearblue
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: gogyou
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.2'
|
55
|
+
description: |
|
56
|
+
``suzuna'' is software volume infrastructure for ruby.
|
57
|
+
|
58
|
+
Support platform is FreeBSD GEOM only.
|
59
|
+
email: dearblue@users.sourceforge.jp
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files:
|
63
|
+
- LICENSE.md
|
64
|
+
- README.md
|
65
|
+
- lib/suzuna.rb
|
66
|
+
files:
|
67
|
+
- LICENSE.md
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- examples/gate.rb
|
71
|
+
- gemstub.rb
|
72
|
+
- lib/suzuna.rb
|
73
|
+
homepage: http://sourceforge.jp/projects/rutsubo/
|
74
|
+
licenses:
|
75
|
+
- 2-clause BSD License
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '2.0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 2.4.1
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: Soft volume infrastructure for ruby
|
97
|
+
test_files: []
|
98
|
+
has_rdoc:
|