/
index.html
638 lines (449 loc) · 41.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8">
<title>USB multi-seat on Red Hat Enterprise Linux 6</title>
<meta name="author" content="Alexander Todorov">
<meta name="description" content="Multiseat configurations are well known in the Linux community and have been used for a number of years now. In the last few years USB docking …">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="canonical" href="http://atodorov.org/blog/2011/03/14/usb-multi-seat-on-red-hat-enterprise-linux-6/">
<link href="/favicon.png" rel="icon">
<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<script src="/javascripts/modernizr-2.0.js"></script>
<script src="/javascripts/ender.js"></script>
<script src="/javascripts/octopress.js" type="text/javascript"></script>
<link href="http://feeds.feedburner.com/atodorov" rel="alternate" title="atodorov.org - you can logoff, but you can never leave" type="application/atom+xml">
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet" type="text/css" />
<meta name="google-site-verification" content="XynqZtldWNBbmsynVQZremIxaaO8Wgs6AGR8UZ7KIkM" />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-37979549-1', 'atodorov.org');
ga('send', 'pageview');
</script>
</head>
<body >
<header role="banner"><hgroup>
<div id="logo-container">
<div id="logo">atodorov.org</div>
<div id="logo-sub"><em>
you can logoff, but you can never leave
</em></div>
</div>
</hgroup>
</header>
<nav role="navigation"><ul class="subscription" data-subscription="rss">
<li><a href="http://feeds.feedburner.com/atodorov" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
</ul>
<ul class="main-navigation">
<li><a href="/">Home</a></li>
<li><a href="/give-away/">Give Away List</a></li>
<li><a href="/projects/">Projects</a></li>
<li><a href="/domains/">Domains</a></li>
<li><a href="http://amzn.to/1wTPaLe">Previous: Traction</a></li>
<li><a href="http://amzn.to/1lLi5NU">Previous: How to Win Friends</a></li>
</ul>
</nav>
<div id="main">
<div id="content">
<div>
<article class="hentry" role="article">
<header>
<h1 class="entry-title">USB Multi-seat on Red Hat Enterprise Linux 6</h1>
<p class="meta">
<time datetime="2011-03-14T20:10:00+02:00" pubdate data-updated="true">Mar 14<span>th</span>, 2011</time>
| <a href="#disqus_thread">Comments</a>
</p>
</header>
<div class="entry-content"><p>Multiseat configurations are well known in the Linux community and have been used for a number of years now. In the last few years USB docking stations emerged on the market and are becoming popular among multiseat enthusiasts.</p>
<p>My company <a href="http://otb.bg">Open Technologies Bulgaria, Ltd.</a> offers full support of USB multiseat for Red Hat Enterprise Linux 6 as a downstream vendor. We use the name SUMU (simple usb multi user) to refer to the entire multiseat bundle and in this article I’m going to describe the current state of technologies surrounding multiseat, how that works on RHEL 6 and some practical observations.</p>
<h2>COMPONENTS</h2>
<p>To build a multiseat system you need a number of individual components:</p>
<p><img src="/images/plugable_docking_station.png" alt="UD-160-A" style="float: right;"/></p>
<ul>
<li>
USB docking station like Plugable’s <a href="http://plugable.com/products/UD-160-A">UD-160-A</a> or a combination of <a href="http://plugable.com/products/">USB video card</a> and stand alone USB hub. It is also possible to use USB docking stations from other vendors but I’m not aware of anyone who did it.
</li>
<li>
<em>udlfb</em> - a kernel driver for USB graphics adapters which use DisplayLink based chips. As of January 2011 udlfb.c is part of the mainline kernel tree and is on track for 2.6.38. On RHEL6 this can easily be built as a stand alone module. There are no issues with this package.
We also use a custom patch that will draw the string “fbX” onto the green screen. This is useful for easier identification of the display. The patch can be found <a href="http://otb-sources.googlecode.com/svn/trunk/sumu/udlfb-kmod/fbX-numbering.patch">here</a>.
</li>
<li>
<em>Xorg</em> - this is the standard graphics server on Linux. In RHEL 6 we have xorg-x11-server-Xorg-1.7.7-26 which works perfectly in a multiseat environment.
</li>
<li>
<em>xorg-x11-drv-fbdev</em> with extensions - Xorg driver based on the <em>fbdev</em> driver. The extensions add support for the X DAMAGE protocol. This is a temporary solution until Xorg adds support for the damage protocol. Our package is called <em>xorg-x11-drv-fbdev-displaylink</em> to avoid conflict with the stock package provided by the distribution and it installs the files in <em>/usr/local</em>. You can also change the compiler flags and produce a binary under a different name (say <em>displaylink_drv.so</em> instead of <em>fbdev_drv.so</em>).
</li>
<li>
<em>GDM</em> with multiseat support - GDM will manage multiple local displays and has the ability to add/remove displays dynamically. This functionality is present in versions up to 2.20 and since RHEL6 includes gdm-2.30.4-21.el6 this is a tough choice. There are several possibilities:
<ol>
<li>
Use older <em>GDM</em>, preferably from a previous RHEL release. This gives you a tested piece of software and as long as the previous release is maintained you have (at least some) opportunity of fixing bugs in this code base. However this conflicts with current <em>GDM</em> in the distro which is also integrated with <em>ConsoleKit</em>, <em>Plymouth</em> and <em>PulseAudio</em>.
</li>
<li>
Use <em>GDM</em> and <em>ConsoleKit</em> that are available in RHEL6 and apply the multiseat patches available at
https://bugs.freedesktop.org/show_bug.cgi?id=19333 and http://bugzilla.gnome.org/show_bug.cgi?id=536355.
Those patches are quite big (around 3000 lines each) and are not yet fully integrated upstream. They also conflict with custom patches that Red Hat is shipping into these packages. Your patched packages will also conflict with the stock distro packages and you will not receive any support for that. Since <em>ConsoleKit</em> seems like fairly important application I’d not recommend modifying it.
</li>
<li>
Use another display manager that can handle multiple displays. https://help.ubuntu.com/community/MultiseatX suggests to use <em>KDM</em> instead of <em>GDM</em>. As far as I can tell the configuration is only static and this can break any time due to the fact that USB device discovery is unpredictable and unreliable. It also lacks an alternative for <em>gdmdynamic</em> according to http://lists.kde.org/?l=kde-devel&m=129898381127854&w=2 which makes it a no-go for plug-and-play multiseat support.
There are other less popular display managers but I haven’t spend much time in research.
</li>
<li>
Just for the record it is also possible that one writes a custom display manager for multiseat operations. This sounds like an overkill and there are many factors which need to be taken into account. If you have enough resources and knowledge to write a display manager you’d better give upstream a hand instead of reinventing the wheel.
</li>
</ol>
We’ve decided to use <em>GDM 2.16</em> from RHEL5 due to the above factors. In practice it turns out that there aren’t many issues with this version.
</li>
<li>
<em>A GDM theme</em> - since the GDM version we’re using requires a theme which is missing in RHEL6 this is also provided as a separate package. A GDM theme is an XML file plus some images.
</li>
<li>
<em>udev rules, scripts and config files</em> - this is the glue between all the other components. Their primary job is to group the display-mouse-keyboard pairs for a given seat and start the display with the appropriate configuration settings. We also have support for <em>PulseAudio</em>.
</li>
</ul>
<h2>RHEL6 SPECIFICS</h2>
<p>For detailed description of multiseat configuration take a look at http://plugable.com/2009/11/16/setting-up-usb-multiseat-with-displaylink-on-linux-gdm-up-to-2-20/ or at our <a href="http://otb-sources.googlecode.com/svn/trunk/sumu/">source code</a>. I’m going to describe only the differences in RHEL6.</p>
<p><em>GDM</em>, <em>udlfb</em> and <em>xorg-x11-drv-fbdev-displaylink</em> need to be compiled and installed on the system.</p>
<p>To build an older <em>GDM</em> on RHEL6 you will need to adjust some of the patches in the src.rpm package to apply cleanly and tweak the .spec file to your needs. This also includes using the appropriate version of <em>ltmain.sh</em> from the distro.</p>
<p>The udev rules and scripts are slightly different due to the different device paths in RHEL6:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>SYSFS<span class="o">{</span>idVendor<span class="o">}==</span><span class="s2">"17e9"</span>, SYSFS<span class="o">{</span>bConfigurationValue<span class="o">}==</span><span class="s2">"2"</span>, <span class="nv">RUN</span><span class="o">=</span><span class="s2">"/bin/echo 1 > /sys%p/bConfigurationValue"</span>
</span><span class='line'>
</span><span class='line'><span class="nv">ACTION</span><span class="o">==</span><span class="s2">"add"</span>, <span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"fb*"</span>, <span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"graphics"</span>, <span class="nv">SUBSYSTEMS</span><span class="o">==</span><span class="s2">"usb"</span>, <span class="nv">PROGRAM</span><span class="o">=</span><span class="s2">"/usr/bin/sumu-hub-id /sys/%p/device/../"</span>, SYMLINK+<span class="o">=</span><span class="s2">"usbseat/%c/display"</span>, RUN+<span class="o">=</span><span class="s2">"/etc/udev/scripts/start-seat %c"</span>
</span><span class='line'><span class="nv">ACTION</span><span class="o">==</span><span class="s2">"remove"</span>, <span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"fb*"</span>, <span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"graphics"</span>, RUN+<span class="o">=</span><span class="s2">"/etc/udev/scripts/stop-seat %k"</span>
</span><span class='line'>
</span><span class='line'><span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"control*"</span>, <span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"sound"</span>, <span class="nv">BUS</span><span class="o">==</span><span class="s2">"usb"</span>, <span class="nv">PROGRAM</span><span class="o">=</span><span class="s2">"/usr/bin/sumu-hub-id /sys/%p/device/../../../../"</span>, SYMLINK+<span class="o">=</span><span class="s2">"usbseat/%c/sound"</span>
</span><span class='line'><span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"event*"</span>, <span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"input"</span>, <span class="nv">BUS</span><span class="o">==</span><span class="s2">"usb"</span>, SYSFS<span class="o">{</span>bInterfaceClass<span class="o">}==</span><span class="s2">"03"</span>, SYSFS<span class="o">{</span>bInterfaceProtocol<span class="o">}==</span><span class="s2">"01"</span>, <span class="nv">PROGRAM</span><span class="o">=</span><span class="s2">"/usr/bin/sumu-hub-id /sys/%p/device/../../../../"</span>, SYMLINK+<span class="o">=</span><span class="s2">"usbseat/%c/keyboard"</span>, RUN+<span class="o">=</span><span class="s2">"/etc/udev/scripts/start-seat %c"</span>
</span><span class='line'><span class="nv">KERNEL</span><span class="o">==</span><span class="s2">"event*"</span>, <span class="nv">SUBSYSTEM</span><span class="o">==</span><span class="s2">"input"</span>, <span class="nv">BUS</span><span class="o">==</span><span class="s2">"usb"</span>, SYSFS<span class="o">{</span>bInterfaceClass<span class="o">}==</span><span class="s2">"03"</span>, SYSFS<span class="o">{</span>bInterfaceProtocol<span class="o">}==</span><span class="s2">"02"</span>, <span class="nv">PROGRAM</span><span class="o">=</span><span class="s2">"/usr/bin/sumu-hub-id /sys/%p/device/../../../../"</span>, SYMLINK+<span class="o">=</span><span class="s2">"usbseat/%c/mouse"</span>, RUN+<span class="o">=</span><span class="s2">"/etc/udev/scripts/start-seat %c"</span>
</span></code></pre></td></tr></table></div></figure>
<p>We also use only <em>/dev/event*</em> devices for both mouse and keyboard.</p>
<p>The <em>sumu-hub-id</em> script returns the string busX-devY indicating the location of the device:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c">#!/bin/bash</span>
</span><span class='line'><span class="k">if</span> <span class="o">[</span> -d <span class="s2">"$1"</span> <span class="o">]</span>; <span class="k">then</span>
</span><span class='line'><span class="k"> </span><span class="nb">echo</span> <span class="s2">"bus$(cat $1/busnum)-dev$(cat $1/devnum)"</span>
</span><span class='line'> <span class="nb">exit </span>0
</span><span class='line'><span class="k">else</span>
</span><span class='line'><span class="k"> </span><span class="nb">exit </span>1
</span><span class='line'><span class="k">fi</span>
</span></code></pre></td></tr></table></div></figure>
<p>USB device numbering is unique per bus and there isn’t a global device identifier as far as I know. On systems with 2 or more USB buses this can lead to mismatch between devices/seats.</p>
<p>For seat/display numbering we use the number of the framebuffer device associated with the seat. This is unique, numbers start from 1 (<em>fb0</em> is the text console) and are sequential unlike USB device numbers. This also ensures easy match between <em>$DISPLAY</em> and <em>/dev/fbX</em> for debugging purposes.</p>
<p>Our <em>xorg.conf.sed</em> template uses evdev as the input driver. This driver is the default in RHEL6:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>Section <span class="s2">"InputDevice"</span>
</span><span class='line'> Identifier <span class="s2">"keyboard"</span>
</span><span class='line'> Driver <span class="s2">"evdev"</span>
</span><span class='line'> Option <span class="s2">"CoreKeyboard"</span>
</span><span class='line'> Option <span class="s2">"Device"</span> <span class="s2">"/dev/usbseat/%SEAT_PATH%/keyboard"</span>
</span><span class='line'> Option <span class="s2">"XkbModel"</span> <span class="s2">"evdev"</span>
</span><span class='line'>EndSection
</span><span class='line'>
</span><span class='line'>Section <span class="s2">"InputDevice"</span>
</span><span class='line'> Identifier <span class="s2">"mouse"</span>
</span><span class='line'> Driver <span class="s2">"evdev"</span>
</span><span class='line'> Option <span class="s2">"CorePointer"</span>
</span><span class='line'> Option <span class="s2">"Protocol"</span> <span class="s2">"auto"</span>
</span><span class='line'> Option <span class="s2">"Device"</span> <span class="s2">"/dev/usbseat/%SEAT_PATH%/mouse"</span>
</span><span class='line'> Option <span class="s2">"Buttons"</span> <span class="s2">"5"</span>
</span><span class='line'> Option <span class="s2">"ZAxisMapping"</span> <span class="s2">"4 5"</span>
</span><span class='line'>EndSection
</span></code></pre></td></tr></table></div></figure>
<p>We also use a custom <em>gdm.conf</em> file to avoid conflicts with stock packages. Only the important settings are shown:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="o">[</span>daemon<span class="o">]</span>
</span><span class='line'><span class="nv">AlwaysRestartServer</span><span class="o">=</span><span class="nb">false</span>
</span><span class='line'><span class="nv">DynamicXServers</span><span class="o">=</span><span class="nb">true</span>
</span><span class='line'><span class="nv">FlexibleXServers</span><span class="o">=</span>0
</span><span class='line'><span class="nv">VTAllocation</span><span class="o">=</span><span class="nb">false</span>
</span><span class='line'>
</span><span class='line'><span class="o">[</span>servers<span class="o">]</span>
</span><span class='line'><span class="nv">0</span><span class="o">=</span>inactive
</span></code></pre></td></tr></table></div></figure>
<p>AlwaysRestartServer=false is necessary to avoid a bug in <em>Xorg</em>. See below for issues description.</p>
<p>Audio is supported by setting $PULSE_SINK/$PULSE_SOURCE environment variables using a script in <em>/etc/profile.d</em> which executes after login.</p>
<h2>SCALABILITY AND PERFORMANCE</h2>
<p><strong>Maximum seats</strong>:<br />
The USB standard specifies a maximum of 127 USB devices connected to a single host controller. This means around 30 seats per USB controller depending on the number of devices connected to a USB hub. In practice you will have hard time finding a system which has that many port available. I’ve used Fujitsu’s <a href="http://ts.fujitsu.com/products/standard_servers/tower/primergy_tx100s1.html">TX100 S1</a> and <a href="http://ts.fujitsu.com/products/standard_servers/tower/primergy_tx100s2.html">TX100 S2</a> which can be expanded to 15 or 16 USB ports using all external and internal ports and additional PCI-USB extension card.</p>
<p>While larger configuration are possible by using more PCI cards or intermediate hubs those are limited by the USB 2.0 transfer speed (more devices on a single hub, slower graphics) and a <a href="https://bugzilla.kernel.org/show_bug.cgi?id=28682">bug</a> in the Linux kernel.</p>
<p><strong>Space and cable length</strong>:<br />
USB 2.0 limits the cable length to 5 meters. On the market I’ve found good quality cables running 4.5 meters. This means that your multiseat system needs to be confined is small physical space due to these limitations. In practice using medium sized multiseat system in a 30 square meters space is doable and fits into these limits. This is roughly the size of a class-room in a school.</p>
<p>You can of course use daisy chaining (up to 5 hubs) and active USB extension cords (11 meters) or USB over CAT5 cables (up to 45 meters) but all of these interfere with USB signal strength and can lead to unpredictable behavior. For example I’ve see errors opening USB devices when power is not sufficient or too high. Modern computer systems have built in hardware protection and shut off USB ports or randomly reboot when the current on the wire is too strong. I’ve seen this on a number of occasions and the fix was to completely power off and unplug the system then power it on again.</p>
<p>Also don’t forget that USB video consumes a great deal of the limited USB 2.0 bandwidth. Depending on the workload of the system (e.g. office applications vs. multimedia) you could experience slow graphical response if using extension cords and daisy chaining.</p>
<p><strong>Performance</strong>:<br />
For regular desktop use (i.e. nothing in particular) I’d recommend using 32bit operating system. On 64bit systems objects take a lot more memory and you’ll need 3-4 times more for the same workload as on 32bit. For example 16 users running Eclipse, gnome-terminal and Firefox will need less that 8GB of memory on 32bit and more than 16GB on 64bit. Python and Java are particularly known to use much more memory on 64bit.</p>
<p>Regular desktop usage is not CPU intensive and a modern Xeon CPU has no issues with it. One exception is Flash which always causes your CPU to choke. On multiseat that becomes even a bigger problem. If possible disable/remove Flash from the system.</p>
<p>Multiseat doesn’t make any difference when browsing, sending e-mail, etc. You shouldn’t experience issues with networking unless your workload doesn’t require hi-speed connection or your bandwidth is too low. If this is the case you’d better use the USB NICs available in the docking stations and bond them together, add external PCI NICs or upgrade your networking infrastructure.</p>
<p>Disk performance is critical in multiseat especially because it affects the look and feel of the system and is visible by the end users. It is usually good practice to place /home on a separate partition and even on a separate disk. Also consider disabling unnecessary caching in user space applications such as Firefox and Nautilus (thumbnails and cache).</p>
<p>On a system with 2 x 7,2K RPM disks in BIOS RAID1 configuration and a standard RHEL6 installation (i.e. no optimizations configured) where /, swap and /home are on the same RAID array we have 15 users using GNOME, gedit, Firefox, gnome-terminal and gcc. The performance is comparable to stand alone desktop with occasional spikes which cause GNOME to freeze for a second or two. It is expected that disabling unnecessary caching will make things better.</p>
<p>Depending on the workload (reads vs. writes) you should consider different RAID levels, file system types and settings and changing disk parameters. A good place to start is the “Storage Administration Guide” and “I/O Tuning Guide” at http://docs.redhat.com.</p>
<h2>KNOWN ISSUES</h2>
<ul>
<li>
<a href="https://bugzilla.kernel.org/show_bug.cgi?id=28682">Bug 28682 - input drivers support limited device numbers (EVDEV_MINORS is 32)</a> - this bug will block you from adding more than 32 input devices of the same type. For multiseat that means 32 devices which are handled by the event driver which includes mice, keyboards, joystick and special platform events such as the Reboot/Poweroff buttons. This limits the available seats to around 15.
</li>
<li>
<a href="https://bugzilla.redhat.com/show_bug.cgi?id=679122">Bug 679122 - gnome-volume-control: Sound at 100% and no sound output</a> - upon first login the user will not hear any sound regardless of the fact that the volume control application shows volume is at 100%.
</li>
<li>
<a href="https://bugzilla.redhat.com/show_bug.cgi?id=682562">Bug 682562 - gnome-volume-control doesn’t respect PULSE_SINK/PULSE_SOURCE</a> - the volume control application will not behave correctly and may confuse users.
</li>
<li>
Xorg will cause 100% CPU usage after logout - this is due to several factors. The <a href="http://plugable.com/2009/11/16/setting-up-usb-multiseat-with-displaylink-on-linux-gdm-up-to-2-20/">initial multiseat configuration</a> had a problem with input duplication. This was fixed by removing “-sharevts -novtswitch” from the X start line and substituting a specific VT - “vt07”.
This works fine unless one of the users logs out of their GNOME session. After that GDM will kill and restart it’s process and new Xorg process will be spawned. The restarted instance will loop endlessly executing the following code:
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="n">ioctl</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">TCFLSH</span><span class="p">,</span> <span class="mh">0x2</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">EIO</span> <span class="p">(</span><span class="n">Input</span><span class="o">/</span><span class="n">output</span> <span class="n">error</span><span class="p">)</span>
</span><span class='line'><span class="n">setitimer</span><span class="p">(</span><span class="n">ITIMER_REAL</span><span class="p">,</span> <span class="p">{</span><span class="n">it_interval</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">20000</span><span class="p">},</span> <span class="n">it_value</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">20000</span><span class="p">}},</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
</span><span class='line'><span class="n">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="p">{</span><span class="mi">247</span><span class="p">,</span> <span class="mi">684817842</span><span class="p">})</span> <span class="o">=</span> <span class="mi">0</span>
</span><span class='line'><span class="n">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="p">{</span><span class="mi">247</span><span class="p">,</span> <span class="mi">684921278</span><span class="p">})</span> <span class="o">=</span> <span class="mi">0</span>
</span><span class='line'><span class="n">setitimer</span><span class="p">(</span><span class="n">ITIMER_REAL</span><span class="p">,</span> <span class="p">{</span><span class="n">it_interval</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">},</span> <span class="n">it_value</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">}},</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
</span><span class='line'><span class="n">select</span><span class="p">(</span><span class="mi">256</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">3</span> <span class="mi">5</span> <span class="mi">13</span> <span class="mi">14</span> <span class="mi">15</span> <span class="mi">16</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="p">{</span><span class="mi">409</span><span class="p">,</span> <span class="mi">254000</span><span class="p">})</span> <span class="o">=</span> <span class="mi">1</span> <span class="p">(</span><span class="n">in</span> <span class="p">[</span><span class="mi">5</span><span class="p">],</span> <span class="n">left</span> <span class="p">{</span><span class="mi">409</span><span class="p">,</span> <span class="mi">253990</span><span class="p">})</span>
</span><span class='line'><span class="n">ioctl</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">TCFLSH</span><span class="p">,</span> <span class="mh">0x2</span><span class="p">)</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span> <span class="n">EIO</span> <span class="p">(</span><span class="n">Input</span><span class="o">/</span><span class="n">output</span> <span class="n">error</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
If you search on the Internet you will find plenty of bug reports related to this code block. The problem is in <em>Xorg</em> which doesn’t properly handle the situation where it can’t take control over the terminal. The solution is to not restart <em>Xorg</em> after user session ends. This is done by setting AlwaysRestartServer=false in <em>gdm.conf</em>.
</li>
<li>
No integration with <em>SELinux</em> and <em>ConsoleKit</em> - while configuring <em>SELinux</em> in Permissive mode is easy workaround there’s no easy workaround for <em>ConsoleKit</em>.
Newer <em>GDM</em> versions register the user session with <em>ConsoleKit</em> and integrate that into the desktop. Missing integration means that some things will fail. For example <em>NetworkManager</em> will not allow the user to connect to a VPN connection because it thinks this user is not logged in:
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='c'><span class='line'><span class="o">**</span> <span class="p">(</span><span class="n">nm</span><span class="o">-</span><span class="n">applet</span><span class="o">:</span><span class="mi">1168</span><span class="p">)</span><span class="o">:</span> <span class="n">WARNING</span> <span class="o">**:</span> <span class="o">&</span><span class="n">lt</span><span class="p">;</span><span class="n">WARN</span><span class="o">&</span><span class="n">gt</span><span class="p">;</span> <span class="n">activate_vpn_cb</span><span class="p">()</span><span class="o">:</span> <span class="n">VPN</span> <span class="n">Connection</span> <span class="n">activation</span> <span class="n">failed</span><span class="o">:</span>
</span><span class='line'><span class="p">(</span><span class="n">org</span><span class="p">.</span><span class="n">freedesktop</span><span class="p">.</span><span class="n">NetworkManager</span><span class="p">.</span><span class="n">PermissionDenied</span><span class="p">)</span> <span class="n">No</span> <span class="n">user</span> <span class="n">settings</span> <span class="n">service</span> <span class="n">available</span>
</span></code></pre></td></tr></table></div></figure>
</li>
<li>
No ACLs for external USB flash drives - this is missing upstream and is supposed to land in <em>ConsoleKit</em>. When a user plugs their USB flash drive on a multiseat system GNOME will try to mount it automatically. If there are multiple users logged in this will either fail or all of them will be able to access the flash drive.
</li>
</ul>
<h2>PICTURES AND VIDEO</h2>
<p>Pictures from one of our deployments can be found on Facebook (no login required):
<a href="http://www.facebook.com/album.php?aid=54571&id=180150925328433">http://www.facebook.com/album.php?aid=54571&id=180150925328433</a>.
A demonstration video from the same deployment can be found at <a href="http://www.youtube.com/watch?v=7GYbCDGTz-4">http://www.youtube.com/watch?v=7GYbCDGTz-4</a></p>
<p>If you are interested in commercial support please contact me!</p>
<h2>FUTURE</h2>
<p>In the open source world everything is changing and multiseat is no exception. While <em>GDM</em> and <em>ConsoleKit</em> patches are not yet integrated upstream there’s a new project called <a href="http://www.freedesktop.org/wiki/Software/systemd">systemd</a> which aims at replacing the SysV init scripts system. It already has several configuration files for multiseat and I expect it will influence multiseat deployments in the future. Systemd will be available in Fedora 15.</p>
</div>
<footer>
<p class="meta">
<span class="byline author vcard">Posted by <span class="fn">Alexander Todorov</span></span>
<time datetime="2011-03-14T20:10:00+02:00" pubdate data-updated="true">Mar 14<span>th</span>, 2011</time>
<span class="categories">
<a class='category' href='/blog/categories/rhel/'>RHEL</a>
</span>
</p>
<div class="sharing">
<!-- AddThis Button BEGIN -->
<div class="addthis_toolbox addthis_default_style addthis_32x32_style">
<a class="addthis_button_preferred_1"></a>
<a class="addthis_button_preferred_2"></a>
<a class="addthis_button_preferred_3"></a>
<a class="addthis_button_preferred_4"></a>
<a class="addthis_button_preferred_5"></a>
<a class="addthis_button_preferred_6"></a>
<a class="addthis_button_preferred_7"></a>
<a class="addthis_button_preferred_8"></a>
<a class="addthis_button_preferred_9"></a>
<a class="addthis_button_compact"></a>
<a class="addthis_counter addthis_bubble_style"></a>
</div>
<script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5103cc5a2bc6ba17"></script>
<!-- AddThis Button END -->
</div>
<p class="meta">
<a class="basic-alignment right" href="/blog/2011/09/15/protected-rpm-repositories-with-yum-and-ssl/" title="Next Post: Protected RPM repositories with yum and SSL">Protected RPM repositories with yum and SSL »</a>
</p>
</footer>
</article>
<section>
<h1>Comments</h1>
<div id="disqus_thread" aria-live="polite"><noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</section>
</div>
<aside class="sidebar">
<section>
<p>
I am a QA contractor at Red Hat responsible for over
<a href="/blog/2014/02/19/7-years-1400-bugs-red-hat-qa/">1500 bugs</a>,
a general purpose open source developer, Red Hat Certified professional,
cloud hacker and an <a href="/projects/">entrepreneur</a>.
</p>
<p>
I'm living in the <a href="http://planet.sofiavalley.com">Sofia Valley</a>
which is emerging as a busy place for start-up founders and tech enthusiasts
in Eastern Europe! You can find more about me <a href="/about/">here</a>.
</p>
</section>
<section>
<a href="http://twitter.com/atodorov_" class="twitter-follow-button" data-show-count="true">Follow @atodorov_</a>
</section>
<form action="http://google.com/search" method="get">
<fieldset role="search">
<input type="hidden" name="sitesearch" value="atodorov.org" />
<input class="search" type="text" name="q" results="0" placeholder="Search"/>
</fieldset>
</form>
<section>
<h1>
<a href="/blog/categories/books/">Book Reviews</a>
</h1>
</section>
<section>
<h1>Recent Posts</h1>
<ul id="recent_posts">
<li class="post">
<a href="/blog/2015/07/27/call-for-ideas-graphical-test-coverage-reports/">Call for Ideas: Graphical Test Coverage Reports</a>
</li>
<li class="post">
<a href="/blog/2015/07/01/open-data-event-coming-to-sofia/">Open Data Event Coming to Sofia</a>
</li>
<li class="post">
<a href="/blog/2015/05/22/devit-conf-2015-impressions/">DEVit Conf 2015 Impressions</a>
</li>
<li class="post">
<a href="/blog/2015/05/20/free-software-testing-books/">Free Software Testing Books</a>
</li>
<li class="post">
<a href="/blog/2015/05/13/why-does-sysctl-not-write-under-slash-sys/">Why does sysctl not write under /sys</a>
</li>
<li class="post">
<a href="/blog/2015/05/05/using-usb-to-vga-adapter-on-macbook-air-with-linux/">Using USB to VGA Adapter on MacBook Air with Linux</a>
</li>
<li class="post">
<a href="/blog/2015/05/04/thunderbolt-to-ethernet-adapter-on-linux/">Thunderbolt to Ethernet Adapter on Linux</a>
</li>
<li class="post">
<a href="/blog/2015/05/01/compiling-twinkle-sip-phone-on-rhel-7/">Compiling Twinkle SIP Phone on RHEL 7</a>
</li>
<li class="post">
<a href="/blog/2015/04/30/fixing-tilde-and-function-keys-mapping-for-macbook-air-on-linux/">Fixing Tilde and Function Keys Mapping for MacBook Air on Linux</a>
</li>
<li class="post">
<a href="/blog/2015/04/29/rhel-7-repository-for-macbook-air/">RHEL 7 Repository for MacBook Air</a>
</li>
</ul>
</section>
<section>
<h1>Disclaimer</h1>
<p>
Some of the links contained within this site have my referral id (e.g., Amazon), which provides me with a small commission for each sale. Thank you for your support.
</p>
</section>
</aside>
</div>
</div>
<footer role="contentinfo"><p>
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_US">CC-BY-SA</a>
&
<a rel="license" href="http://opensource.org/licenses/MIT">MIT</a>
2011-2015 ♦ Alexander Todorov
♦
<a href="/about/">About Me</a>
♦
Popular categories:
<a href="/blog/categories/rhel/">Red Hat</a>,
<a href="/blog/categories/cloud/">Cloud</a>,
<a href="/blog/categories/fedora/">Fedora</a>,
<a href="/blog/categories/qa/">QA</a>,
<a href="/blog/categories/start-up/">Start-up</a>
<a href="http://planet.sofiavalley.com" style="float:right">SofiaValley Blog</a>
</p>
<script type="text/javascript">
var uri = window.location.toString();
if (uri.indexOf("?") > 0) {
var clean_uri = uri.substring(0, uri.indexOf("?"));
window.history.replaceState({}, document.title, clean_uri);
}
</script>
</footer>
<script type="text/javascript">
var disqus_shortname = 'atodorov';
// var disqus_developer = 1;
var disqus_identifier = 'http://atodorov.org/blog/2011/03/14/usb-multi-seat-on-red-hat-enterprise-linux-6/';
var disqus_url = 'http://atodorov.org/blog/2011/03/14/usb-multi-seat-on-red-hat-enterprise-linux-6/';
var disqus_script = 'embed.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#appId=212934732101925&xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<script type="text/javascript">
(function() {
var script = document.createElement('script'); script.type = 'text/javascript'; script.async = true;
script.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(script, s);
})();
</script>
<script type="text/javascript">
(function(){
var twitterWidgets = document.createElement('script');
twitterWidgets.type = 'text/javascript';
twitterWidgets.async = true;
twitterWidgets.src = 'http://platform.twitter.com/widgets.js';
document.getElementsByTagName('head')[0].appendChild(twitterWidgets);
})();
</script>
</body>
</html>