ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Linux-NBD/lib/Linux/NBD/Client.pm
Revision: 1.14
Committed: Tue May 30 03:58:30 2017 UTC (9 years, 4 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.13: +11 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Linux::NBD::Client - client (device) side of a network block device
4
5 =head1 SYNOPSIS
6
7 use Linux::NBD::Client;
8
9 =head1 DESCRIPTION
10
11 WARNING: I talked to the author of the nbd driver because nbd is so
12 extremely racy (right now, stopping it often causes oopses, a server
13 crashing also often oopses etc..).
14
15 It turned out that he doesn't care at all and nbd is basically
16 unmaintained, so YMMV when using this module, especially when writing
17 servers.
18
19 He really should have said that on his nbd pages ;[.
20
21 OTOH, it works relatively reliable when you don't stop the servers, so
22 watch out and keep your fingers crossed.
23
24 =head1 METHODS
25
26 =over 4
27
28 =cut
29
30 package Linux::NBD::Client;
31
32 $VERSION = 0.22;
33
34 use Linux::NBD ();
35
36 use Carp qw(croak);
37 use Errno ();
38
39 =item $client = new Linux::NBD::Client [socket => $fh][, device => "/dev/nbdX"], ...
40
41 Create a new client.
42
43 Unless C<device> is given, an unused device node is looked up using the
44 C<device> method (this might result in an exception!).
45
46 =item $client->socket ([$tcp_socket])
47
48 Returns the current socket after setting a new one (if an argument is
49 supplied). The socket I<MUST> be a tcp socket. Believe me, bad things will
50 happen if not.
51
52 The special argument C<undef> will try to clear the socket, if any was
53 set.
54
55 =item $client->device ([$new_device])
56
57 Returns the current device node (e.g. C</dev/nbd2>) after setting a new one if
58 an argument is supplied.
59
60 If the argument is C<undef> it will search for an unallocated nbd-device
61 and use it.
62
63 =cut
64
65 sub new {
66 my $class = shift;
67 my $self = bless { @_ }, $class;
68
69 $self->device (exists $self->{device} ? $self->{device} : undef);
70 exists $self->{socket} and $self->socket ($self->{socket});
71
72 $self;
73 }
74
75 sub socket {
76 my $self = shift;
77
78 if (@_) {
79 $self->{socket} = $_[0];
80
81 if (defined $self->{socket}) {
82 my $fileno = $_[0] =~ /[^0-9]/ ? fileno $_[0] : $_[0];
83 _set_sock fileno $self->{device_fd}, $fileno;
84 } else {
85 _clear_sock fileno $self->{device_fd};
86 }
87 }
88
89 $self->{socket};
90 }
91
92 sub device {
93 my $self = shift;
94
95 if (@_) {
96 my $device = shift;
97
98 # try to load the module if the device nodes don't exist
99 # might be better to handle this via mknod?
100 -b "/dev/nbd0"
101 or system "modprobe nbd >/dev/null 2>&1";
102
103 if (defined $device) {
104 open my $dev, "+<$device" or croak "$device: $!";
105 $self->{device} = $device;
106 $self->{device_fd} = $dev;
107 } else {
108 for (0..256) {
109 $_ < 256 or croak "unable to find an available nbd device";
110
111 my $path = "/dev/nbd$_";
112 -e $path or system "mknod", $path, "b", 43, $_;
113 open my $dev, "+<$path" or croak "$device: $!";
114 _set_sock fileno $dev, -1;
115 if ($!{EINVAL}) {
116 $self->{device} = $path;
117 $self->{device_fd} = $dev;
118 last;
119 } elsif ($!{EBUSY}) {
120 next;
121 } else {
122 croak "$path: $!";
123 }
124 }
125 }
126 }
127
128 $self->{device};
129 }
130
131 =item $client->disconnect
132
133 Tries to exit the server by sending a special disconnect message.
134
135 =item $client->clear_queue
136
137 Clears the request queue, if possible. Should be used before setting a new
138 socket.
139
140 =item $client->set_timeout ($timeout)
141
142 Set the request timeout, in seconds.
143
144 =item $client->set_blocksize ($blksize)
145
146 Set the device block size in bytes, i.e. how big each block is (must be
147 >512, <PAGESIZE and a power of two).
148
149 Also rounds down the device size to be a multiple of the block size.
150
151 =item $client->set_blocks ($nblocks)
152
153 Set the device size in block units.
154
155 =item $client->set_size ($bytes)
156
157 Set the device size in octet units, will be rounded down to be a multiple
158 of the block size.
159
160 =item $client->set_flags ($flags)
161
162 Set flags (NBD_FLAG_*) on the device.
163
164 =cut
165
166 sub disconnect {
167 my $self = shift;
168
169 _disconnect fileno $self->{device_fd};
170 }
171
172 sub clear_queue {
173 my $self = shift;
174
175 _clear_que fileno $self->{device_fd};
176 }
177
178 sub set_timeout {
179 my $self = shift;
180
181 _set_timeout fileno $self->{device_fd}, $_[0];
182 }
183
184 sub set_blocksize {
185 my $self = shift;
186
187 _set_blksize fileno $self->{device_fd}, $_[0];
188 }
189
190 sub set_size {
191 my $self = shift;
192
193 _set_size fileno $self->{device_fd}, $_[0];
194 }
195
196 sub set_blocks {
197 my $self = shift;
198
199 _set_size_blocks fileno $self->{device_fd}, $_[0];
200 }
201
202 sub set_flags {
203 my $self = shift;
204
205 _set_flags fileno $self->{device_fd}, $_[0];
206 }
207
208 sub print_debug {
209 my $self = shift;
210
211 _print_debug fileno $self->{device_fd};
212 }
213
214 =item $client->run
215
216 Closes all file descriptors except the server socket and enters
217 the service loop (waits for read/write requests on the device and
218 forwards them over the given socket). Only returns when somebody calls
219 C<disconnect> or the server is killed.
220
221 =item $pid = $client->run_async
222
223 Runs the service loop asynchronously and returns the pid of the newly
224 created service process.
225
226 =item $client->kill_async
227
228 Kills any running async service. Please note that this also kills the
229 socket, so you need to re-set the socket after this call.
230
231 =cut
232
233 sub run {
234 my $self = shift;
235
236 _doit fileno $self->{device_fd};
237 }
238
239 sub run_async {
240 my $self = shift;
241
242 $self->{pid} = fork;
243
244 defined $self->{pid} or croak "fork: $!";
245 return $self->{pid} if $self->{pid};
246
247 _doit fileno $self->{device_fd}, 1;
248 }
249
250 sub kill_async {
251 my $self = shift;
252
253 if (my $pid = delete $self->{pid}) {
254 #_clear_que fileno $self->{device_fd};
255 #_disconnect fileno $self->{device_fd};
256 #_clear_sock fileno $self->{device_fd};
257 # just kill -9 it, seems to be safest (all other ways just oops sooner or later)
258 kill 9, $pid;
259 }
260 }
261
262 sub DESTROY {
263 my $self = shift;
264
265 $self->kill_async;
266 }
267
268 =cut
269
270 1;
271
272 =back
273
274 =head1 AUTHOR
275
276 Marc Lehmann <schmorp@schmorp.de>
277 http://home.schmorp.de/
278
279 =cut
280