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

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3 root 1.9 Linux::NBD::Client - client (device) side of a network block device
4 root 1.1
5     =head1 SYNOPSIS
6    
7     use Linux::NBD::Client;
8    
9     =head1 DESCRIPTION
10    
11 root 1.4 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 root 1.1
24     =head1 METHODS
25    
26     =over 4
27    
28     =cut
29    
30     package Linux::NBD::Client;
31    
32 root 1.14 $VERSION = 0.22;
33 root 1.1
34     use Linux::NBD ();
35    
36     use Carp qw(croak);
37     use Errno ();
38    
39 root 1.12 =item $client = new Linux::NBD::Client [socket => $fh][, device => "/dev/nbdX"], ...
40 root 1.1
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 root 1.10 =item $client->socket ([$tcp_socket])
47 root 1.1
48     Returns the current socket after setting a new one (if an argument is
49 root 1.10 supplied). The socket I<MUST> be a tcp socket. Believe me, bad things will
50     happen if not.
51 root 1.1
52     The special argument C<undef> will try to clear the socket, if any was
53     set.
54    
55 root 1.10 =item $client->device ([$new_device])
56 root 1.1
57 root 1.12 Returns the current device node (e.g. C</dev/nbd2>) after setting a new one if
58 root 1.1 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 root 1.12 exists $self->{socket} and $self->socket ($self->{socket});
71 root 1.1
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 root 1.13 # 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 root 1.1 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 root 1.12 my $path = "/dev/nbd$_";
112 root 1.6 -e $path or system "mknod", $path, "b", 43, $_;
113 root 1.1 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 root 1.10 Tries to exit the server by sending a special disconnect message.
134 root 1.1
135     =item $client->clear_queue
136    
137     Clears the request queue, if possible. Should be used before setting a new
138     socket.
139    
140 root 1.11 =item $client->set_timeout ($timeout)
141    
142     Set the request timeout, in seconds.
143    
144 root 1.10 =item $client->set_blocksize ($blksize)
145 root 1.1
146 root 1.11 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 root 1.1
151 root 1.11 =item $client->set_blocks ($nblocks)
152 root 1.1
153 root 1.11 Set the device size in block units.
154 root 1.1
155 root 1.11 =item $client->set_size ($bytes)
156 root 1.1
157 root 1.11 Set the device size in octet units, will be rounded down to be a multiple
158     of the block size.
159 root 1.1
160 root 1.14 =item $client->set_flags ($flags)
161    
162     Set flags (NBD_FLAG_*) on the device.
163    
164 root 1.1 =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 root 1.11 sub set_timeout {
179     my $self = shift;
180    
181     _set_timeout fileno $self->{device_fd}, $_[0];
182     }
183    
184 root 1.1 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 root 1.14 sub set_flags {
203     my $self = shift;
204    
205     _set_flags fileno $self->{device_fd}, $_[0];
206     }
207    
208 root 1.11 sub print_debug {
209     my $self = shift;
210    
211     _print_debug fileno $self->{device_fd};
212     }
213    
214 root 1.1 =item $client->run
215    
216 root 1.11 Closes all file descriptors except the server socket and enters
217     the service loop (waits for read/write requests on the device and
218 root 1.10 forwards them over the given socket). Only returns when somebody calls
219     C<disconnect> or the server is killed.
220 root 1.1
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 root 1.2 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 root 1.1
231     =cut
232    
233     sub run {
234     my $self = shift;
235 root 1.11
236 root 1.1 _doit fileno $self->{device_fd};
237     }
238    
239     sub run_async {
240     my $self = shift;
241    
242     $self->{pid} = fork;
243 root 1.10
244 root 1.1 defined $self->{pid} or croak "fork: $!";
245 root 1.10 return $self->{pid} if $self->{pid};
246 root 1.1
247 root 1.10 _doit fileno $self->{device_fd}, 1;
248 root 1.1 }
249    
250     sub kill_async {
251     my $self = shift;
252    
253     if (my $pid = delete $self->{pid}) {
254 root 1.3 #_clear_que fileno $self->{device_fd};
255     #_disconnect fileno $self->{device_fd};
256     #_clear_sock fileno $self->{device_fd};
257 root 1.5 # just kill -9 it, seems to be safest (all other ways just oops sooner or later)
258     kill 9, $pid;
259 root 1.1 }
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 root 1.8 Marc Lehmann <schmorp@schmorp.de>
277     http://home.schmorp.de/
278 root 1.1
279     =cut
280