<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Scott James Remnant</title>
	<atom:link href="http://netsplit.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://netsplit.com</link>
	<description></description>
	<lastBuildDate>Fri, 18 May 2012 22:02:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Since my blog is available on IPv6</title>
		<link>http://netsplit.com/2012/05/18/since-my-blog-is-available-on-ipv6/</link>
		<comments>http://netsplit.com/2012/05/18/since-my-blog-is-available-on-ipv6/#comments</comments>
		<pubDate>Fri, 18 May 2012 22:02:21 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=475</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.worldipv6launch.org"><img title="WORLD IPV6 LAUNCH is 6 June 2012 – The Future is Forever" src="http://www.worldipv6launch.org/wp-content/themes/ipv6/downloads/World_IPv6_launch_banner_512.png" alt="WORLD IPV6 LAUNCH is 6 June 2012 – The Future is Forever" width="512" height="512" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2012/05/18/since-my-blog-is-available-on-ipv6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>iOS App Design Notes</title>
		<link>http://netsplit.com/2012/05/03/ios-app-design-notes/</link>
		<comments>http://netsplit.com/2012/05/03/ios-app-design-notes/#comments</comments>
		<pubDate>Thu, 03 May 2012 22:15:56 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=473</guid>
		<description><![CDATA[Since iOS apps are now worth a billion dollars, here&#8217;s a few design notes worth bearing in mind when writing your new app: Users love receiving push notifications, and love it when you take them to the appropriate page in &#8230; <a href="http://netsplit.com/2012/05/03/ios-app-design-notes/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Since iOS apps are now worth a billion dollars, here&#8217;s a few design notes worth bearing in mind when writing your new app:</p>
<ul>
<li>Users love receiving push notifications, and love it when you take them to the appropriate page in your app, but they hate it if they see the notification there. Make sure that the page you show contains stale information and does not automatically update to show the notification they just tapped on.</li>
<li>Increase the number of times users open your app by keeping them in a continual state of confusion as to whether they have any unread notifications. At no time should the notifications shown in the iOS Notification tray, the number of notifications shown in the app icon badge, the number of notifications in your app&#8217;s own button badge for notifications, or indeed the list of notifications in your app match.</li>
<li>For additional bonus confusion, none of the above should match the set or number of notifications the user would see if they opened the notification list on a computer.</li>
<li>Users love pulling down to refresh. Even if your app is only ever used in a &#8220;read new things&#8221; kind of mode, always force the user to pull down to refresh, never update for them.</li>
<li>Your app is only ever going to be used online, on a super-fast internet connection. Never cache data between invocations. Always clear the screen when loading the new data, users love seeing a spinner and a &#8220;Loading&#8221; message when on a slow connection.</li>
<li>If you build your app around WebView you may be forced to accept that there will be some caching, fight against it and avoid a consistent experience at all costs by never saving this cache between invocations. Since it&#8217;s almost random whether your app will remain in memory between uses, this means it will be almost random whether your user sees stale cached data (which you don&#8217;t auto-refresh, obviously) or a white loading screen while you pull all new data.</li>
<li>Tap targets should be as small as possible, testing in the Simulator with your mouse proves that Apple&#8217;s 44px guideline is way too large!</li>
<li>The app should regularly reflow its content so that tap targets move under the user&#8217;s finger between the time they start their finger moving and the time it reaches the screen.</li>
<li>Using a WebView for your app is great, the lack of JIT and other performance improvements means you don&#8217;t need too many servers to serve content to your app. Users love it when shared photos show up as black boxes because the servers are too busy.</li>
<li>Using a WebView also means you can continually adjust the layout of your page. For the ultimate rapid deployment, never cache resources such as CSS or images client-side. Users love that retro look and feel when your page renders without them on a slow connection.</li>
<li>Your app probably has to let users post content too. Users are always on fast, reliable data networks. Don&#8217;t worry about handling error cases, timeouts, etc. it&#8217;s ok to just throw an error, and ideally throw away their post too. Never double-check whether the post succeeded, for that to happen and the response being lost is impossible.</li>
<li>Whenever Apple release a new API feature, make sure you update your code to take advantage of it. Apple&#8217;s documentation can be kinda waffly though, don&#8217;t bother reading all of it, you never need to handle the edge cases like someone taking a phone call on their phone (who does that?) or receiving a notification while you&#8217;re dragging your neat side bar out. Users love it when that side bar sticks half way, it&#8217;s hilarious.</li>
</ul>
<p>For a perfect score on all of the above tips, I highly recommend taking a look at <a href="itunes.apple.com/us/app/facebook/id284882215?mt=8">Facebook&#8217;s iPhone app</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2012/05/03/ios-app-design-notes/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Book Review: The Years of Rice and Salt</title>
		<link>http://netsplit.com/2012/04/24/book-review-the-years-of-rice-and-salt/</link>
		<comments>http://netsplit.com/2012/04/24/book-review-the-years-of-rice-and-salt/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 04:30:51 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Book]]></category>
		<category><![CDATA[Reviews]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=468</guid>
		<description><![CDATA[Enough people have recommended that I read Kim Stanley Robinson&#8217;s The Years of Rice and Salt that it&#8217;s surprising that it&#8217;s taken me as long as it has to finally get around to it. This was my first of his books, &#8230; <a href="http://netsplit.com/2012/04/24/book-review-the-years-of-rice-and-salt/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://itunes.apple.com/us/book/the-years-of-rice-and-salt/id420037362?mt=11"><img class="alignleft" title="The Years of Rice and Salt" src="http://a5.mzstatic.com/us/r30/Publication/0d/8e/46/mzi.kwmhkwrj.225x225-75.jpg" alt="" width="149" height="225" /></a> Enough people have recommended that I read Kim Stanley Robinson&#8217;s <em>The Years of Rice and Salt</em> that it&#8217;s surprising that it&#8217;s taken me as long as it has to finally get around to it.</p>
<p>This was my first of his books, I hadn&#8217;t read the <em>Mars Trilogy</em>, so as with any new author I wasn&#8217;t sure what to expect from it; especially since I&#8217;d been warned that in style it was fairly different from his other work, and that it also had slow parts that would take a bit of getting through.</p>
<p>All the reviews and recommendations were glowing though, praising the re-invention of a world without the influence of Christian Europe and the epic scope of the story across the ages.</p>
<p>Unfortunately mine isn&#8217;t. I can&#8217;t recall a novel that I&#8217;ve struggled through as much as this one. I kept at it hoping for a grand denouement that would explain the praise lavished on it, but that never happened. As ridiculous as it sounds, the book&#8217;s grand ending was a chapter explaining the style the book was written in, and the grand reveal was a cute schtick it had used throughout and that anyone with half a brain would have figured out within the first hundred pages.</p>
<p>Yes, the world building was clever and thorough; but I read a lot, especially Science-Fiction and Fantasy, and good world building is de rigour in the best works of those genres. A novel needs some other story or message beyond the world itself.</p>
<p>And if Kim Stanley Robinson had a point or message with this book, it was entirely lost on me. A novel set in a world without Western culture would provide ample opportunity to take a critical look at that culture, and say something about ourselves, but instead it ignores it and focuses itself on Islamic and Chinese culture and finds many faults therein.</p>
<p>A novel in which reincarnation plays such a significant part would provide ample opportunity to consider mortality, or the eternal struggle to better ourselves, but the book doesn&#8217;t go there either and instead if anything suggests futility as the central characters manage to be responsible for every significant scientific breakthrough throughout history without ever changing in themselves.</p>
<p>Maybe the central message was just supposed to be that all people and cultures are ultimately the same, that we all make the same mistakes and share the same victories, but even then it tries hard to avoid saying any such thing.</p>
<p>Honestly, as far as I could tell, the only significant point the author wanted to make was that San Francisco should have been built on the North side of the Golden Gate and not the South. He makes that point <em>a lot!</em></p>
<p>★ ☆ ☆ ☆ ☆</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2012/04/24/book-review-the-years-of-rice-and-salt/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>git smash</title>
		<link>http://netsplit.com/2012/02/06/git-smash/</link>
		<comments>http://netsplit.com/2012/02/06/git-smash/#comments</comments>
		<pubDate>Mon, 06 Feb 2012 18:21:33 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=464</guid>
		<description><![CDATA[A common thing I end up doing while working on code is to make a series of commits, and  then end up work changes in my working directory which I need to apply to an earlier revision in the history &#8230; <a href="http://netsplit.com/2012/02/06/git-smash/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>A common thing I end up doing while working on code is to make a series of commits, and  then end up work changes in my working directory which I need to apply to an earlier revision in the history than the top-most one.</p>
<p>One common way to do this is to make a temporary commit with those changes, then use <em>git rebase -i</em> and move that commit below the one I want to amend and choose <em>fixup</em> to have it applied.</p>
<p>But that&#8217;s annoying manual work. There&#8217;s a more fun way. I have this script in my path as <em>git-smash</em>, it takes a revision as a single argument, e.g. <em>git smash deadbeef</em>:</p>
<pre>git reset --keep "$1"
EDITOR=true git commit -a --amend
git checkout HEAD@{2}
git rebase --onto HEAD@{1} HEAD@{2}</pre>
<p>This resets the revision history, keeping local changes, back to the given revision. Unfortunately <em>git reset</em> doesn&#8217;t have a mode which preserves the index so we then have to use <em>commit -a</em> to capture all of the local changes.</p>
<p>Now we use the reflog (history of revisions in the working tree) to manipulate the tree back to the previous state, first checking out the revision that was two back (before the amended commit and the reset, i.e. where we began). Then we rebase that onto the revision one back (before the checkout, i.e. the amended revision) using the revision that&#8217;s now two back (before the checkout and commit, i.e. the original revision we changed).</p>
<p>Mental gymnastics over, this is the same as what we were doing before, just in one handy command.</p>
<p>Git still <a href="http://netsplit.com/2009/02/17/git-sucks/">sucks</a> though.</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2012/02/06/git-smash/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Halloween is over!</title>
		<link>http://netsplit.com/2011/11/01/halloween-is-over/</link>
		<comments>http://netsplit.com/2011/11/01/halloween-is-over/#comments</comments>
		<pubDate>Tue, 01 Nov 2011 06:32:58 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=455</guid>
		<description><![CDATA[Not just the festival, but my project to write a short story or part thereof every day of October and publish them on the website. See my blog post from a couple of weeks ago for more information All of the &#8230; <a href="http://netsplit.com/2011/11/01/halloween-is-over/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Not just the festival, but my project to write a short story or part thereof every day of October and publish them on the website. See my blog post from <a href="http://netsplit.com/2011/10/10/halloween/">a couple of weeks ago</a> for more information</p>
<p>All of the stories are now written and published at <a href="http://netsplit.com/halloween/">http://netsplit.com/halloween/</a> - up to and including today&#8217;s. It&#8217;s a good feeling to be finally finished. I&#8217;ll leave them up for at least a little while longer before I decide what to next with them, a round of editing and tidying up or two is certainly in order; and my current plan is to publish them collected together in printed or eBook form if people want it.</p>
<p>But until then I have a new project&#8230;</p>
<p><img class="aligncenter size-full wp-image-457" title="NaNoWriMo Participant 2011" src="http://netsplit.com/wp-content/uploads/2011/10/Participant2_180_180_white.png" alt="NaNoWriMo Participant 2011" width="180" height="180" /></p>
<p>&#8230;I&#8217;m going to be taking part in <a href="http://www.nanowrimo.org/">NaNoWriMo</a>. For those that have not heard of it, which included myself until a month ago, it&#8217;s a competition of sorts to write a 50,000 word (minimum) first draft of a novel in the month of November.</p>
<p>I&#8217;ve had the idea for the story for a couple of years now, and what with wetting my apetite for writing again with the October project. I&#8217;m eager to get started on it. Now I just need to wait until midnight&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2011/11/01/halloween-is-over/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Halloween</title>
		<link>http://netsplit.com/2011/10/10/halloween/</link>
		<comments>http://netsplit.com/2011/10/10/halloween/#comments</comments>
		<pubDate>Mon, 10 Oct 2011 08:16:08 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=451</guid>
		<description><![CDATA[Readers of this blog will mostly know me for the software I&#8217;ve written, most likely Upstart or my work on Ubuntu, but there&#8217;s another kind of writing I enjoy doing and it&#8217;s something I haven&#8217;t taken much time to do &#8230; <a href="http://netsplit.com/2011/10/10/halloween/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Readers of this blog will mostly know me for the software I&#8217;ve written, most likely Upstart or my work on Ubuntu, but there&#8217;s another kind of writing I enjoy doing and it&#8217;s something I haven&#8217;t taken much time to do in the last few years.</p>
<p>Like everyone else I had to do some creative writing at school, but I really enjoyed it and took it quite a bit further writing many short stories over the years.</p>
<p>A friend of mine is taking part in <a title="National Novel Writing Month" href="http://www.nanowrimo.org/">NaNoWriMo</a> this year, and the two of us discussed ways of practicing and, most of all, warming up for it. After all, writing over 1,650 words of a novel a day is no mean feat to go into stone cold. She&#8217;s been using <a href="http://750words.com/">750words.com</a> for a while, and I suggested she use that to write short stories along the lines of her planned novel, but not to be used for it, to practice.</p>
<p>Discussing it really fired up my desire to do some writing again myself, so I decided to join her. But obviously rather than copying, I decided to do something completely different in tone.</p>
<p>Each day in October, leading up to Halloween, I&#8217;m writing a short story myself. Since that&#8217;s a spooky event, I&#8217;m vaguely sticking to a horror theme for the stories. I say vaguely because it&#8217;s quite easy to slip from horror to other genres, such as science-fiction or thrillers, but the intent is certainly there that these all have a darker theme than usual.</p>
<p>I&#8217;ve also been using 750words.com for the most part, with an aim that each story be a minimum of that in length. One of the most interesting outcomes is that the earliest stories were hard work to reach 750 words from a simple idea, whereas the latest ones easily reach 1,000. In fact my latest story is almost twice the minimum length.</p>
<p>But at the end of the day, they are roughly 3-5 pages each and since they&#8217;re posted and published each day, they&#8217;re more akin to first drafts of ideas than polished works. I remember reading once about an author who would pin up the pages of a story he was writing to a shop window as each one came off the typewriter (Google tells me this was almost certainly Harlan Ellison), I like to think I&#8217;m doing the Internet-era equivalent.</p>
<p>Perhaps they will give some people joy and delight, or perhaps they will give some people nightmares. Even if not, I&#8217;m enjoying writing them!</p>
<p>You can read those so far at <a title="Halloween" href="http://netsplit.com/halloween/">http://netsplit.com/halloween/</a> in all the usual formats, and check back every day or so for new ones if you like what you read.</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2011/10/10/halloween/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>A new release process for Ubuntu?</title>
		<link>http://netsplit.com/2011/09/08/new-ubuntu-release-process/</link>
		<comments>http://netsplit.com/2011/09/08/new-ubuntu-release-process/#comments</comments>
		<pubDate>Thu, 08 Sep 2011 23:06:02 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=445</guid>
		<description><![CDATA[With the nomination period beginning for the Ubuntu Technical Board, big changes like Unity having arrived in Ubuntu recently, and the upcoming UDS for being what will likely be a new LTS release of Ubuntu, it&#8217;s as good as time &#8230; <a href="http://netsplit.com/2011/09/08/new-ubuntu-release-process/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>With the nomination period beginning for the Ubuntu Technical Board, big changes like Unity having arrived in Ubuntu recently, and the upcoming UDS for being what will likely be a new LTS release of Ubuntu, it&#8217;s as good as time as any to ask big questions about the development process, challenge assumptions, and make suggestions for big changes.</p>
<h2>Cadence</h2>
<p>The Ubuntu release process is well known, and its developers talk regularly about the <em>cadence</em> of it. A new release of Ubuntu comes out every six months, and each release follows a predictable pattern. I&#8217;ve stolen the following image from OMG! Ubuntu&#8217;s recent series about Ubuntu Development.</p>
<p><img class="aligncenter" title="Ubuntu Release Cycle" src="http://cdn.omgubuntu.co.uk/wp-content/uploads/2011/08/cycle-items.png" alt="" width="636" height="236" /></p>
<p>Each developer working on Ubuntu follows this cycle. When Ubuntu 11.10 is released on October 13th, they&#8217;ll begin again. After they recover, of course.</p>
<p>First there&#8217;ll be a bit of a wait for the archive to be open, this gets quicker and quicker each release but since it depends on a toolchain being built and other similarly fundamental things, it tends to be a period where most people figure out what they&#8217;re going to discuss at UDS.</p>
<p>UDS is a bit late for the 12.04 cycle, so the <em>merge period</em> will probably occupy developer time both before and after UDS. This isn&#8217;t represented on Daniel&#8217;s chart above, but this is the time when massive amounts of updates arrive from Debian; it&#8217;s a time of great instability for Ubuntu. At some point there will be an <em>Alpha 1</em>, but you won&#8217;t want to try and install that.</p>
<p>Planning for UDS is going to take up some time, and writing up the results of the plans afterwards and turning that into <em>work items</em>. There&#8217;s also a UDS Hangover which nobody (except Robbie Williamson, when drafting the 10.10 Release Cycle) seems to like to talk about. Nothing gets done in the week or two following UDS, everybody is too wiped out.</p>
<p>So realistically speaking, development of features for 12.04 is going to start around mid-November at the earliest. And by features I mean the big headline things in Ubuntu; like Unity, like the Software Center, like the Installer. These things are important to get right.</p>
<p>Pretending for a moment that features are developed over the winter holidays like Thanksgiving, Christmas and New Year, you&#8217;ve got clear development time until Feature Freeze. The 12.04 Release Schedule isn&#8217;t published yet, but I figure that&#8217;s going to be somewhere around February 16th after which everyone switches to bug fixing and release testing.</p>
<p><strong>That&#8217;s just 13 weeks of development time!</strong></p>
<h2>Chaos</h2>
<p>So you&#8217;re an Ubuntu developer working on features for the upcoming release, you don&#8217;t have anywhere near as much time as you&#8217;d expect to actually do the development work. What happens if you&#8217;re replacing something that works with something completely new? Can&#8217;t you just target a later release, and work continually until the feature freeze of that release?</p>
<p>It turns out that you can&#8217;t. There is an incredible emphasis on the Ubuntu planning process of targeting features for particular releases. This is the exact thing <em>you&#8217;re not supposed to do</em> with a time-based release schedule.</p>
<p>Unfortunately Canonical&#8217;s own performance-review and management is also based around this schedule. The Ubuntu developers so employed (the vast majority) have such fundamentals as their pay, bonuses, etc. dictated by how many of their assigned features and work items are into the release by feature freeze. It&#8217;s not the only requirement, but it&#8217;s the biggest one.</p>
<p>Your new feature is going to take twelve months of development time to fully develop before it&#8217;s truly a replacement for the existing feature in Ubuntu. What you <em>don&#8217;t</em> do is spend twelve months developing and land it when it&#8217;s a perfect replacement.</p>
<p>What you <em>do</em> do is develop it in 12-13 week bursts, which means it&#8217;s going to take you roughly four release cycles before it&#8217;s ready rather than two. <strong>And you land the quarter-complete feature in the first release, replacing the older stable feature.</strong></p>
<h2>Consequence</h2>
<p>If this were true, you would expect to see new features repeatedly arriving in Ubuntu before they were ready. Removing the old, deprecated feature and breaking things temporarily with the promise that everything will be better in the next release, certainly the one after that, definitely by the LTS.</p>
<p>Maybe you don&#8217;t believe that characterizes Ubuntu, in which case you should probably just stop reading now because we&#8217;re not going to agree with my fundamental complaint.</p>
<p>But I will say this: I know I&#8217;m responsible for doing this on more than one occasion <em>because I had to</em>; and I saw the exact same pattern in others&#8217; work, when I was a manager my reports complained that they had to follow this pattern and I still see the same pattern today with features such as Unity and the Software Center.</p>
<p>Follow this pattern and developers are going to complain that they need a release where they don&#8217;t have any features to work on, and can just spend the time stabilizing and bug fixing.</p>
<p>Worse, follow this pattern and you&#8217;re going to create a user expectation that releases are going to be largely unstable and contain sweeping changes that are going to be surprising to administrators of Enterprise desktop deployments, and discourage them from using your distribution at all.</p>
<p>A kludge to this would be to overlay a second release schedule onto your first one, with more of an emphasis on stability and support. It&#8217;s a target for your developers to complete their features, or at least stabilize them in those 12 weeks; and it&#8217;s a target for your users to consider deployment. <strong>So three out of four of your releases are really just unstable previews of that final fourth release.</strong></p>
<h2>Complacency</h2>
<p>This second LTS release cycle solves the unstable release issue, so why is this a problem?</p>
<p>Because developer time is wasted; because user time is wasted; because user confidence is lost.</p>
<p>Because features can take longer than two years to develop; or if even if a feature takes just two years, if it&#8217;s not begun immediately after the previous LTS release, it&#8217;s not going to be ready for the next one so you might postpone and lose the lead.</p>
<p>Because you might expect a knock-on degeneracy effect in the LTS releases as well; with 12.04 LTS being less stable than 10.04 LTS, which was less stable than 8.04 LTS which was less stable than 6.06 LTS. And it&#8217;s far too late now to have considered the 10.10/11.04/11.10/12.04 cycle to have been a Super-Long-Term-Support release and kept back the complete replacement of the desktop environment.</p>
<p>Because the original reason for the six-month cycle has already been forgotten: features are targeted towards releases, rather than released when ready; because the original base for the release schedule (GNOME) is no longer a key component of the distribution; because no other key component has adopted this schedule.</p>
<p><strong>Because these might be a better way.</strong></p>
<h2>Cataclysm</h2>
<p>What I&#8217;m going to suggest here is a completely new development process for Ubuntu, complete with details about how it would be implemented.</p>
<p><strong>I&#8217;m going to suggest a monthly release process, beginning with the 11.10 release.</strong> It so happens that this fits perfectly with Ubuntu&#8217;s version numbering system, the next release would be 11.11, followed by 11.12, followed by 12.01 and so on.</p>
<p>This monthly release would be simply known as <strong>release</strong> in your <em>sources.list</em>, updates would be published to it on the first week of the month. There would be no codenames, and due to the rapid releases, changes would be largely unsurprising and iterative on the previous releases.</p>
<p>In order to provide user testing, a second release known as <strong>beta</strong> would exist. It&#8217;s from this release that <strong>release</strong> would be copied from on that first week of the month. <strong>beta</strong> would be updated every two weeks, on the first week of the month after it became the new <strong>release</strong>, and then on the half-way point of the month. Users who like a little bleeding on their edge can change their <em>sources.list</em> to use this more exciting release, or download appropriate disk images.</p>
<p>Developers wouldn&#8217;t run either of these, they would run the third release branch <strong>alpha</strong>. It&#8217;s from here that <strong>beta</strong> is updated; and from here that daily disk images would be generated.</p>
<p>Publishing from <strong>alpha</strong> to <strong>beta</strong>, and then from <strong>beta</strong> to <strong>release</strong> is handled semi-automatically. The release manager will track Release Critical bugs, and will hold up packages from copying from one to the other if they have outstanding problems. If this sounds familiar, it&#8217;s because this is exactly how the <a href="http://www.debian.org/devel/testing">Debian testing</a> distribution works and I recommend using the same software (which Ubuntu already uses to check for archive issues).</p>
<p>So where do developers upload? It&#8217;s tempting to just say to <strong>alpha</strong>, but if we say that, <strong>alpha</strong> will end up looking very different from <strong>release</strong> because it will be filled with unstable software that&#8217;s not ready for users yet. This will make it harder for problems in the <strong>release</strong> branch to be fixed, because none of the components are left in <strong>alpha</strong> because they&#8217;ve been replaced by something that&#8217;s not ready yet.</p>
<p><strong>Developers will upload to an <em>unpublished</em> trunk branch.</strong> Packages will be copied to <strong>alpha </strong>provided:</p>
<ul>
<li>there is a signed-off code review for the upload</li>
<li>the upload meets policy (lintian clean)</li>
<li>the upload builds on all released architectures</li>
<li>unit tests pass on all released architectures</li>
<li>functional and verification tests pass on all architectures for the archive as a whole</li>
</ul>
<p>I just introduced a bunch of new checks to the developer process there; I just introduced <em>code review</em>, mandatory <em>unit tests</em> and then piled<em> functional tests</em> and <em>verification tests</em> on top.</p>
<p>The first four are relatively self-explanatory; fail any of these tests and your upload has marked the <em><strong>tree</strong><strong> red</strong></em>. In which case not only will your package fail to copy to <strong>alpha</strong>, but you&#8217;re about to have a conversation with the Release Manager.</p>
<p>For functional and verification tests, this means doing more automated QA. A failing test could be an automated installer run, or an automated boot-and-test run, etc. They&#8217;ll run sometime after the fact and will make the entire<strong> </strong><em><strong>tree red</strong></em>. The Release Manager or their team will have to examine the logs to figure out the culprit.</p>
<p>So things aren&#8217;t copying to <strong>alpha</strong>, now one of two things is going to happen.</p>
<ul>
<li>the Release Manager <em>reverts</em> your upload. Because <strong>trunk</strong> is unpublished, this is simply overwriting with the older package from <strong>alpha</strong>; nobody except the original developer is going to have known about it</li>
<li>after talking with the developer, it&#8217;s decided that further uploads of other packages are required (e.g. due to dep-wait, or the bug being elsewhere) in which case the <em><strong>tree remains red</strong></em> while the developer (or another in rare cases) prepares that fix upload.</li>
</ul>
<p>While the <em><strong>tree is red</strong></em>, nobody else is allowed to upload unless it&#8217;s a fix for the problem. All effort should go to fixing the tree.</p>
<p>If the archive has to always remain stable, how do you develop large features such as Upstart, Unity, Ubiquity, Software Center, etc.? <strong>You use a PPA to do development, on your own timeline.</strong></p>
<p>If your feature takes twelve months to develop, you take twelve months to develop it in that PPA. You&#8217;re going to be posting regularly to mailing lists or blogging about your feature to encourage users to add your PPA to their <em>sources.list</em> to gain testing. Obviously you&#8217;ll be doing various uploads to the main series over time to get all your dependencies in early where they don&#8217;t conflict with what&#8217;s already there.</p>
<h2>Conclusion</h2>
<p>My proposal is a radical change to the Ubuntu Release Process, but surprisingly it would take very little technical effort to implement because all the pieces are already there including the work on performing automated functional and verification tests.</p>
<p>I believe it solves the problem of landing unstable features before they&#8217;re ready, because it almost entirely removes releases as a <em>thing</em>. As a developer you simply work in a PPA until you&#8217;ll pass review, and land a stable feature that can replace what was there before.</p>
<p>It solves the need for occasional stabilization and bug-fixing releases because the main series is always stable and can receive bug-fixes easily separate to any development work going on. A developer can chose to focus on looking after the main series for some of their time in addition to their feature development work, or devote all of their time to it.</p>
<p>Another problem I&#8217;ve not talked about is that of building software on an unstable foundation, also solved by this change. Since developers will run <strong>alpha</strong>, and vendor developers can just run a relatively up-to-date, yet stable, <strong>release</strong> branch, software can be built on a solid foundation. Only the new feature or software itself is unstable until ready.</p>
<p>Canonical can keep its review schedule, and use developer uploads and work items; except rather than landing in a release, they can now land in a PPA.</p>
<p>Merges from Debian unstable can be handled pretty much continually as long as they keep the tree green, alternatively one can decide that users ultimately don&#8217;t care about an updated version of <em>cat</em> and until a case can be made (e.g. an open bug) for a package&#8217;s update, it need not be merged.</p>
<p>Users can now be confident of always receiving a stable operating system, because of the multiple testing and QA passes each change continually receives. Updates come in monthly, two-weekly or dailyish batches depending where in the main series they chose to run.</p>
<p>Enterprise administrators can run this stable release, because it only changes <em>gradually</em> with well-tested updates. The big changes and features have a long gestation period in PPAs, with many advance notices and blog posts about them. They&#8217;re not a surprise and can be planned for well in advance of their landing.</p>
<p>Downsides will, doubtless, be found in the comments below.</p>
<p><em>For your consideration.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2011/09/08/new-ubuntu-release-process/feed/</wfw:commentRss>
		<slash:comments>189</slash:comments>
		</item>
		<item>
		<title>Tracing on Linux</title>
		<link>http://netsplit.com/2011/03/07/tracing-on-linux/</link>
		<comments>http://netsplit.com/2011/03/07/tracing-on-linux/#comments</comments>
		<pubDate>Mon, 07 Mar 2011 20:18:54 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=433</guid>
		<description><![CDATA[The Linux tracing APIs are a relatively new addition to the kernel and one of the most powerful new features its gained in a long time. Unfortunately the plethora of terms and names for the system can be confusing, so &#8230; <a href="http://netsplit.com/2011/03/07/tracing-on-linux/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The Linux tracing APIs are a relatively new addition to the kernel and one of the most powerful new features its gained in a long time. Unfortunately the plethora of terms and names for the system can be confusing, so in this follow-up to my previous post on the proc connector and socket filter, I&#8217;ll take a look at achieving the same result using tracing and hopefully unravel a little of the mystery along the way.</p>
<p>Rather than write a program along the way, I&#8217;ll be referring to sample code found in the kernel tree itself so you&#8217;ll want a checkout. If you&#8217;re doing any work that touches the kernel further than standard POSIX APIs, I highly recommend this anyway; it&#8217;s quite readable and once you find your way around, is the quickest way to answer questions.</p>
<p>Grab your checkout with <em>git</em>:</p>
<pre># git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
# cd linux-2.6</pre>
<h2>Tracepoints</h2>
<p>One of the reasons there are so many terms and names is that, like most kernel systems, there are many layers and each of those layers is exposed as different developers have different requirements. An important lower layer is that of <em>tracepoints</em>, also known as <em>static tracepoints</em>. For these we&#8217;ll be looking at the code in the <em>samples/tracepoints</em> directory of the kernel source; kernelese documentation of the API can be found in <em>Documentation/trace/tracepoints.txt</em></p>
<p>A tracepoint is a placeholder function call in kernel code that the developer of that subsystem has deemed a useful point for debugging code to be able to hook into. Static refers to the fact they are fixed in point by the original developer. You can think of them as the kind of code you&#8217;d tend to guard with <em>#if DEBUG</em> in traditional C development, and like those statements they&#8217;re nearly free when they&#8217;re not in use except that you can turn these on and off at runtime.</p>
<p>The <em>samples/tracepoints/tracepoint-sample.</em>c file is a kernel module that creates a <em>/proc/tracepoint-sample</em> file, and has a couple of tracepoints coded into it by the developer. First it includes the <em>samples/tracepoints/tp-samples-trace.h</em> which actually declares the tracepoints.</p>
<pre>DECLARE_TRACE(subsys_event,
        TP_PROTO(struct inode *inode, struct file *file),
        TP_ARGS(inode, file));
DECLARE_TRACE_NOARGS(subsys_eventb);</pre>
<p>You can think of these as declaring the function prototypes, one trace function has two arguments: an <em>inode</em> and a <em>file</em>; the other has no arguments. And if they&#8217;re function prototypes, we need to define a function; this is done back in the main <em>tracepoint-sample.c</em> file.</p>
<pre>DEFINE_TRACE(subsys_event);
DEFINE_TRACE(subsys_eventb);</pre>
<p>These tracepoints can now be called from the kernel code, passing the arguments that may need to be traced; remember that these have no side-effects unless enabled. The code that calls out to the tracepoints is in the <em>my_open()</em> function.</p>
<pre>trace_subsys_event(inode, file);
for (i = 0; i &lt; 10; i++)
        trace_subsys_eventb();</pre>
<p>Simple, huh? Don&#8217;t worry about the rest, this primer is simply so you can recognise tracepoints in the kernel source when you see them. I don&#8217;t expect you to go leaping around the kernel adding tracepoints and rebuilding it, unless you want to, of course.</p>
<p>So how do you hook into tracepoints? The answer is from other kernel code, usually in the form of a loadable module such as that defined by <em>samples/tracepoints/tracepoint-probe-sample.c</em>; this includes the same header file as before to get the prototypes.</p>
<pre>#include "tp-samples-trace.h"</pre>
<p>In the module <em>__init</em> function it registers two functions of its own as hooks into the tracepoint, this activates the tracepoint and turns the code in the previous module from a near no-op to a function call that will call these functions.</p>
<pre>ret = register_trace_subsys_event(probe_subsys_event, NULL);
WARN_ON(ret);
ret = register_trace_subsys_eventb(probe_subsys_eventb, NULL);
WARN_ON(ret);</pre>
<p>And obviously in the module <em>__exit</em> function we have to unregister these, otherwise we leave dangling things.</p>
<pre>unregister_trace_subsys_eventb(probe_subsys_eventb, NULL);
unregister_trace_subsys_event(probe_subsys_event, NULL);
tracepoint_synchronize_unregister();</pre>
<p>As to those functions, they take an argument which is a pointer to the same data as the second argument to the register call, and then otherwise take the arguments defined in <em>DECLARE_TRACE</em>. You can do pretty much what you want here, the example simply extracts the filename and outputs it with a a <em>printk(</em>)</p>
<pre>static void probe_subsys_event(void *ignore,
                               struct inode *inode, struct file *file){
        path_get(&amp;file-&gt;f_path);
        dget(file-&gt;f_path.dentry);
        printk(KERN_INFO "Event is encountered with filename %s\n",
                file-&gt;f_path.dentry-&gt;d_name.name);
        dput(file-&gt;f_path.dentry);
        path_put(&amp;file-&gt;f_path);
}</pre>
<p>So that&#8217;s tracepoints; they&#8217;re a low-level method for a kernel developer to pick places in their code that may be useful for debugging and a method for loadable kernel code such as modules to hook into those places.</p>
<h2>Trace Events (Kernel API)</h2>
<p>So you know about tracepoints, and you&#8217;ve almost certainly heard about <em>Trace Events</em>, but what&#8217;s the difference? Well firstly trace events are actually built on tracepoints, you can think of them as a higher level API &#8211; and that&#8217;s why I covered tracepoints first. Secondly trace events are usable from userspace! we don&#8217;t need to write kernel modules to be able to hook into them, but obviously we can only read data this way.</p>
<p>In fact, since they&#8217;re tracepoints with extra benefits, you wouldn&#8217;t think anyone would use the basic tracepoints at all, and you&#8217;d be right! A <em>git grep DECLARE_TRACE</em> in a current kernel tree will show you that the only user of the raw tracepoint macros is actually the trace events system.</p>
<p>Since everyone just defines trace events, a primer on the kernel-side will be useful, so we&#8217;ll be looking at the code in <em>samples/trace_events</em> and if you want to read the userspace API documentation, it&#8217;s in <em>Documentation/trace/events.txt</em></p>
<p>Just one source file and header file this time, first we&#8217;ll look at the header <em>samples/trace_events/trace-events-sample.h</em>; this seems pretty complicated at first, but almost all of this is boiler-plate code that gets copied into every trace events header. The important bit is the <em>TRACE_EVENT</em> macro:</p>
<pre>TRACE_EVENT(foo_bar,
        TP_PROTO(char *foo, int bar),
        TP_ARGS(foo, bar),
        TP_STRUCT__entry(
                __array(        char,   foo,    10              )
                __field(        int,    bar                     )
        ),
        TP_fast_assign(
                strncpy(__entry-&gt;foo, foo, 10);
                __entry-&gt;bar    = bar;
        ),
        TP_printk("foo %s %d", __entry-&gt;foo, __entry-&gt;bar)
);</pre>
<p>The first part of this looks just like <em>DECLARE_TRACE</em>, and that&#8217;s no accident, we&#8217;re still declaring a tracepoint too so this will give us a function with the prototype declared in <em>TP_PROTO</em> and argument names in <em>TP_ARGS</em>.</p>
<p>The <em>TP_STRUCT__entry</em> and <em>TP_fast_assign</em> bits are new though. As well as declaring a tracepoint, trace events come with the equivalent &#8220;loadable module&#8221; code that copies data from the arguments of the function into a struct that can be examined from userspace. <em>TP_STRUCT__entry</em> defines that structure, and <em>TP_fast_assign</em> is C code that should quickly copy data into that structure.</p>
<p>So we&#8217;ve declared a tracepoint, we&#8217;ve defined a structure containing an array of 10 char and an int, and we&#8217;ve written C code to copy from the tracepoint arguments into that structure. The last bit of the trace event is <em>TP_printk</em>, which does exactly what you&#8217;d expect. Since the most common (at least, first) use of a trace event is going to be to output something, this macro defines a format string for that <em>printk()</em> call.</p>
<p>Back in the <em>samples/trace_events/trace-events-sample.c</em> file, we include this header but first set a special define. This is only set once in the entire kernel source, and this results in all of the functions being defined; i.e. <em>TRACE_EVENT</em> becomes <em>DEFINE_TRACE</em> rather than <em>DECLARE_TRACE</em>.</p>
<pre>#define CREATE_TRACE_POINTS
#include "trace-events-sample.h"</pre>
<p>All other users of this header simply include the header.</p>
<p>From here on in the source, the trace event is just a tracepoint and is called in the same way: as a function call.</p>
<pre>trace_foo_bar("hello", cnt);</pre>
<p>That&#8217;s a kernel-side primer, you should be able to <em>git grep</em> through the source and find trace events. But now it&#8217;s time to get into the fun bit and look at the userspace API for dealing with them; remember if you want anything more complicated, they&#8217;re just tracepoints so you can write kernel modules and hook into them as before.</p>
<h2>Trace Events (Userspace API)</h2>
<p>We&#8217;re in userspace now, so you can leave the kernel source directory, but you do need to be root and you may need to mount a filesystem. This is because some distributions (like Ubuntu) have an allergy to debugging (seriously, they even disable things like <em>gdb -p</em>).</p>
<p>Try and change into the <em>/sys/kernel/debug/tracing</em> directory.</p>
<pre># cd /sys/kernel/debug/tracing</pre>
<p>If this fails, you&#8217;ll need to mount the <em>debugfs</em> filesystem and try again.</p>
<pre># mount -t debugfs none /sys/kernel/debug
# cd /sys/kernel/debug/tracing</pre>
<p>With that done, we should make sure tracing is enabled.</p>
<pre># cat tracing_enabled
1</pre>
<p>If that&#8217;s 0, enable it:</p>
<pre># echo 1 &gt; tracing_enabled</pre>
<p>So we&#8217;ve enabled tracing, but what can we trace? Trace events are exposed in the events sub-directory in two levels, the first is the subsystem and the second are the trace events themselves. Since in my last blog post we were looking at tracing <em>forks</em>, it would be great if there were trace events for doing just that. This is where it helps to be able to <em>git grep</em> around the kernel source and recognise trace events, so you at least know the right subsystem name; and it turns out that the <em>sched</em> subsystem has exactly the events we wanted.</p>
<pre>deathspank tracing# ls events/sched
enable                   sched_process_exit/  sched_stat_sleep/
filter                   sched_process_fork/  sched_stat_wait/
sched_kthread_stop/      sched_process_free/  sched_switch/
sched_kthread_stop_ret/  sched_process_wait/  sched_wait_task/
sched_migrate_task/      sched_stat_iowait/   sched_wakeup/
sched_pi_setprio/        sched_stat_runtime/  sched_wakeup_new/</pre>
<p><em>sched_process_fork</em> sounds exactly right, if you look at it, it&#8217;s a directory that contains four files: <em>enable</em>, <em>filter</em>, <em>format</em> and <em>id</em>. I bet you can guess how to enable fork tracing, but if not:</p>
<pre># cat events/sched/sched_process_fork/enable
0
# echo 1 &gt; events/sched/sched_process_fork/enable</pre>
<p>Pretty painless, so go ahead and run a few things, and turn the tracing off again when you&#8217;re done.</p>
<pre># echo 0 &gt; events/sched/sched_process_fork/enable</pre>
<p>Now let&#8217;s look at the result of our trace; recall that every trace event comes with a free <em>printk()</em> of formatted output? We can find the output from those in the top-level <em>trace</em> file.</p>
<pre># tracer: nop
#
#           TASK-PID    CPU#    TIMESTAMP  FUNCTION
#              | |       |          |         |
             zsh-2667  [001]  6658.716936: sched_process_fork: comm=zsh pid=2667 child_comm=zsh child_pid=2748</pre>
<p>So for each process fork, we get the parent and child process ids along with the process name. Pretty much exactly what we want!</p>
<p>There&#8217;s plenty to play around with using this API, as you&#8217;ve probably noticed you can enable entire subsystems or all events using the <em>enable</em> files at the subsystem and events-levels; there&#8217;s also a <em>set_event</em> file at the <em>tracing</em> level which can be used to make batch changes to tracing, see the kernel documentation for more details.</p>
<p>You&#8217;re probably wondering though what happened to the rest of the struct, especially if there fields that aren&#8217;t included in the default <em>printk()</em>. You can examine the struct format by reading the <em>format</em> file of a trace event, and you can use this with the <em>filter</em> file to exclude events you&#8217;re not interested in. Again anything I write here would be just duplicating the kernel documentation, so go read <em>Documentation/trace/events.txt</em></p>
<h2>Perf</h2>
<p>After a little bit of playing you&#8217;ll realise that not only is tracing not limited to your current process or shell, you&#8217;ll get events for processes you&#8217;re not intersted in, but also events for subsystems you&#8217;re not interested in if other processes are doing traces of their own. There&#8217;s also only one global filter for the entire trace events system, so other users or processes doing tracing, could override yours.</p>
<p>There&#8217;s an even higher-level that we can use to work around those problems, the <em>perf</em> tool. Originally designed as a userspace component to the performance counters system, it&#8217;s grown a wide variety of extra features one of which is the ability to work with kernel tracepoints as an input source.</p>
<p>Since trace events are tracepoints, these count!</p>
<p>So let&#8217;s say we want to record the forks made by a process we run, without fear of contamination from other processes on the system or other users performing tracing. Using perf we can simply run</p>
<pre> # perf record -e sched:sched_process_fork record bash</pre>
<p>And run as many commands as we like in that shell. When the shell exits, perf will write the results of the tracing to a perf.data file for analysis.</p>
<pre># exit
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.017 MB perf.data (~735 samples) ]</pre>
<p>We can analyse this later using various <em>perf</em> sub-commands, the simplest of which is an argument-less <em>perf script</em> which outputs the equivalent of reading the trace file.</p>
<pre># perf script
            bash-3141  [003] 10201.049939: sched_process_fork: comm=bash pid=3141 child_comm=bash child_pid=3142
           :3142-3142  [001] 10201.050391: sched_process_fork: comm=bash pid=3142 child_comm=bash child_pid=3143</pre>
<h2>Conclusion</h2>
<p>As an administrator debugging their system, or a developer trying to understand the performance or events timeline of their work, <em>perf</em> is perfect. It&#8217;s a very well documented tool with all of the bells and whistles you need for tracing a wide variety of events.</p>
<p>Unfortuantely the API between <em>perf</em> and the kernel is a private one; the perf tool source is shipped as part of the kernel source, and they are version-mated with each other.</p>
<p>Recall that the topic of the previous blog post was to write a program to follow forks, rather than doing it as a system administrator.</p>
<p>If we want to write software to do it, the lower (but still high) level <em>trace events</em> API seems a better bet. There are a wide range of applications of this API, for example the <em>ureadahead</em> program in an Ubuntu system uses it to trace the <em>open()</em> and <em>exec()</em> syscalls the system performs during boot so it knows which files to cache for faster boot times. But it&#8217;s easy for another process, or a user, to interfere with the results of this tracing so it&#8217;s not ideal for our purpose either.</p>
<p>Finally the <em>tracepoints</em> API is too low-level, writing a kernel module and building and maintaining it for each kernel version is just not on the cards.</p>
<p>So it would appear we&#8217;re at a dead-end for using tracing to do what we want. That&#8217;s not the end of the story though; there are other tracing tools such as <em>kprobes</em> and <em>ftrace</em> that I haven&#8217;t covered yet. Unfortunately this blog post has gotten a little too long, and the coverage of tracepoints, trace events and perf was worthwhile in of itself, so we&#8217;ll have to pick those up next time!</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2011/03/07/tracing-on-linux/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>The Proc Connector and Socket Filters</title>
		<link>http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/</link>
		<comments>http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/#comments</comments>
		<pubDate>Wed, 09 Feb 2011 19:55:20 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Upstart]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=420</guid>
		<description><![CDATA[The proc connector is one of those interesting kernel features that most people rarely come across, and even more rarely find documentation on. Likewise the socket filter. This is a shame, because they&#8217;re both really quite useful interfaces that might &#8230; <a href="http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>The proc connector is one of those interesting kernel features that most people rarely come across, and even more rarely find documentation on. Likewise the socket filter. This is a shame, because they&#8217;re both really quite useful interfaces that might serve a variety of purposes if they were better documented.</p>
<p>The proc connector allows you to receive notification of process events such <em>fork</em> and <em>exec</em> calls, as well as changes to a process&#8217;s <em>uid</em>, <em>gid</em> or <em>sid</em> (session id). These are provided through a socket-based interface by reading instances of <em>struct proc_event</em> defined in the kernel header.</p>
<pre>#include &lt;linux/cn_proc.h&gt;</pre>
<p>The interface is built on the more generic <em>connector</em> API, which itself is built on the generic <em>netlink</em> API. These interfaces add some complexity as they are intended to provide bi-directional communication between the kernel and userspace; the connector API appears to have been largely forgotten as newer such socket interfaces simply declare their own first-class socket classes. So we need the headers for those too.</p>
<pre>#include &lt;linux/netlink.h&gt;
#include &lt;linux/connector.h&gt;</pre>
<p>(For brevity, I&#8217;ll omit any standard boilerplate such as the headers you need for syscalls and library functions that you should be used to as well as function definitions, error checking, and so-forth.)</p>
<p>Ok, now we&#8217;re ready to create the <em>connector</em> socket. This is straight-forward enough, since we&#8217;re dealing with atomic messages rather than a stream, datagram is appropriate.</p>
<pre>int sock;
sock = socket (PF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
               NETLINK_CONNECTOR);</pre>
<p>To select the <em>proc connector</em> we bind the socket using a <em>struct sockaddr_nl</em> object.</p>
<pre>struct sockaddr_nl addr;
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid ();
addr.nl_groups = CN_IDX_PROC;

bind (sock, (struct sockaddr *)&amp;addr, sizeof addr);</pre>
<p>Unfortunately that&#8217;s not quite enough yet; the proc connector socket is a bit of a firehose, so it doesn&#8217;t in fact send any messages until a process has subscribed to it. So we have to send a subscription message.</p>
<p>As I mentioned before, the <em>proc connector</em> is built on top of the generic <em>connector</em> and that itself is on top of <em>netlink</em> so sending that subscription message also involves embedded a message, inside a message inside a message.  If you understood Christopher Nolan&#8217;s Inception, you should do just fine.</p>
<p>Since we&#8217;re nesting a <em>proc connector operation</em> message inside a <em>connector</em> message inside a <em>netlink</em> message, it&#8217;s easiest to use an <em>iovec</em> for this kind of thing.</p>
<pre>struct iovec iov[3];
char nlmsghdrbuf[NLMSG_LENGTH (0)];
struct nlmsghdr *nlmsghdr = nlmsghdrbuf;
struct cn_msg cn_msg;
enum proc_cn_mcast_op op;

nlmsghdr-&gt;nlmsg_len = NLMSG_LENGTH (sizeof cn_msg + sizeof op);
nlmsghdr-&gt;nlmsg_type = NLMSG_DONE;
nlmsghdr-&gt;nlmsg_flags = 0;
nlmsghdr-&gt;nlmsg_seq = 0;
nlmsghdr-&gt;nlmsg_pid = getpid ();

iov[0].iov_base = nlmsghdrbuf;
iov[0].iov_len = NLMSG_LENGTH (0);

cn_msg.id.idx = CN_IDX_PROC;
cn_msg.id.val = CN_VAL_PROC;
cn_msg.seq = 0;
cn_msg.ack = 0;
cn_msg.len = sizeof op;

iov[1].iov_base = &amp;cn_msg;
iov[1].iov_len = sizeof cn_msg;

op = PROC_CN_MCAST_LISTEN;

iov[2].iov_base = &amp;op;
iov[2].iov_len = sizeof op;

writev (sock, iov, 3);</pre>
<p>The <em>netlink </em>message length is the combined length of the following <em>connector</em> and <em>proc connector operation</em> messages, and is otherwise simply a message from our process id with no following messages.  However all of the interfaces to netlink take a lot of care to make sure the following structure in the message is aligned as wide as possible using the <em>NLMSG_LENGTH</em> macro, to avoid issues with platforms that have fixed alignment for data types, so we have to be careful of that too.</p>
<p>So we actually have a bit of padding between the <em>struct nlmsghdr</em> and the <em>struct cn_msg</em>, this is accomplished by actually using a character buffer of the right size for the first iovec element and accessing it through a <em>struct nlmsghdr</em> pointer.</p>
<p>The <em>connector</em> message indicates that it is relevant to the <em>proc connector</em> through the <em>idx</em> and <em>val</em> fields, and the length is the legnth of the <em>proc connector operation</em> message.</p>
<p>Finally the <em>proc connector operation</em> message (just an enum) says we want to subscribe. Why isn&#8217;t there padding between the<em> connector</em> and <em>proc connector operation</em> messages? Because the last element in <em>struct cn_msg</em> is a zero-width type which results in the right padding, this interface is rather newer than netlink.</p>
<p><em>iovec</em> stitches it all together so it&#8217;s sent as a single message, visualized this message looks like this:</p>
<p><a href="http://netsplit.com/wp-content/uploads/2011/02/enum-proc_cn_mcast_op.png"><img class="aligncenter size-full wp-image-426" title="enum proc_cn_mcast_op" src="http://netsplit.com/wp-content/uploads/2011/02/enum-proc_cn_mcast_op.png" alt="" width="640" height="240" /></a></p>
<p>There&#8217;s a matching <em>PROC_CN_MCAST_IGNORE</em> message if you want to turn off the firehose without closing the socket.</p>
<p>Ok, the firehose is on now we need to read the stream of messages.  Just like the message we sent, the stream of messages we receive are actually <em>netlink</em> messages, and inside those <em>netlink</em> messages are <em>connector</em> messages, and inside those are <em>proc connector</em> messages.</p>
<p>Netlink allows for all sorts of things like multi-part messages, but in reality we can ignore most of that since connector doesn&#8217;t use the, but it&#8217;s worth future-protecting ourselves and being liberal in what we accept.</p>
<pre>struct msghdr msghdr;
struct sockaddr_nl addr;
struct iovec iov[1];
char buf[PAGE_SIZE];
ssize_t len;

msghdr.msg_name = &amp;addr;
msghdr.msg_namelen = sizeof addr;
msghdr.msg_iov = iov;
msghdr.msg_iovlen = 1;
msghdr.msg_control = NULL;
msghdr.msg_controllen = 0;
msghdr.msg_flags = 0;

iov[0].iov_base = buf;
iov[0].iov_len = sizeof buf;

len = recvmsg (sock, &amp;msghdr, 0);</pre>
<p>Why do we use <em>recvmsg</em> rather than just <em>read</em>? Because <em>netlink</em> allows arbitrary processes to send messages to each other, so we need to make sure the message actually comes from the kernel; otherwise you have a potential security vulnerability. <em>recvfrom</em> lets us receive the sender address as well as the data.</p>
<pre>if (addr.nl_pid != 0)
        continue;</pre>
<p>(I&#8217;m assuming you&#8217;re reading in a loop there.)</p>
<p>So now we have a <em>netlink</em> message package from the kernel, this may contain multiple individual netlink messages (it doesn&#8217;t, but it may). So we iterate over those.</p>
<pre>for (struct nlmsghdr *nlmsghdr = (struct nlmsghdr *)buf;
     NLMSG_OK (nlmsghdr, len);
     nlmsghdr = NLMSG_NEXT (nlmsghdr, len))</pre>
<p><span style="font-family: 'Courier 10 Pitch', Courier, monospace; color: #222222;"><span style="line-height: 21px;">And we should ignore error or no-op messages from netlink.</span></span></p>
<pre>if ((nlmsghdr-&gt;nlmsg_type == NLMSG_ERROR)
    || (nlmsghdr-&gt;nlmsg_type == NLMSG_NOOP))
        continue;</pre>
<p>Inside each individual <em>netlink</em> message is a <em>connector</em> message, we extract that and make sure it comes from the <em>proc connector</em> system.</p>
<pre>struct cn_msg *cn_msg = NLMSG_DATA (nlmsghdr);

if ((cn_msg-&gt;id.idx != CN_IDX_PROC)
    || (cn_msg-&gt;id.val != CN_VAL_PROC))
        continue;</pre>
<p>Now we can safely extract the <em>proc connector</em> message; this is a <em>struct proc_event</em> that we haven&#8217;t seen before. It&#8217;s quite a large structure definition so I won&#8217;t paste it here, since it contains a <em>union</em> for each of the different possible message types. Instead here&#8217;s code to actually print the relevant contents for an example message.</p>
<pre>struct proc_event *ev = (struct proc_event *)cn_msg-&gt;data;

switch (ev-&gt;what) {
case PROC_EVENT_FORK:
        printf ("FORK %d/%d -&gt; %d/%d\n",
                ev-&gt;event_data.fork.parent_pid,
                ev-&gt;event_data.fork.parent_tgid,
                ev-&gt;event_data.fork.child_pid,
                ev-&gt;event_data.fork.child_tgid);
        break;
/* more message types here */
}</pre>
<p>As you can see, each message type has an associated member of the <em>event_data</em> union containing the information fields for it. And as you can see, this gives you information about each individual kernel task, not just the top-level processes you&#8217;re normally used to seeing. In other words, you see threads as well as processes.</p>
<p>Like I keep saying, it&#8217;s a firehose. It would be great if there was some way to filter the socket in the kernel so that our process doesn&#8217;t even get woken up for messages. Wake-ups are bad, especially in the embedded space.</p>
<p>Fortunately there is a way to filter sockets on the kernel-side, the kernel <em>socket filter</em> interface. Unfortunately this isn&#8217;t too well documented either; but let&#8217;s use this opportunity to document an example.</p>
<p>We&#8217;ll filter the socket so that we only receive <em>fork</em> notifications, discarding the other types of <em>proc connector</em> event type and most importantly discarding the messages that indicate new threads being created (those where the <em>pid</em> and <em>tgid</em> fields differ). One important part of filtering is that you should be careful so that only expected messages are filtered, and that unexpected messages are still passed through.</p>
<p>The filter machine consists of a set of machine language instructions added to the socket through a special socket option. Fortunately this machine language is copied from the Berkeley Packet Filter from BSD, so we can find documentation for it in the <a href="http://www.gsp.com/cgi-bin/man.cgi?section=4&amp;topic=bpf#5">bpf(4)</a> manual page there. Just ignore the structure definitions, because they are different on Linux.</p>
<p>So let&#8217;s get started with our example; first we need to add the right header.</p>
<pre>#include &lt;linux/filter.h&gt;</pre>
<p>And now we need to insert the filter into the socket creation, before the subscription message is sent is usually a good place. On Linux the instructions are given as an array of <em>struct sock_filter</em> members which we can construct using the <em>BPF_STMT</em> and <em>BPF_JUMP</em> macros.</p>
<p>Just to make sure everything is working, we&#8217;ll create a simple &#8220;no-op&#8221; filter.</p>
<pre>struct sock_filter filter[] = {
        BPF_STMT (BPF_RET|BPF_K, 0xffffffff),
};

struct sock_fprog fprog;
fprog.filter = filter;
fprog.len = sizeof filter / sizeof filter[0];

setsockopt (sock, SOL_SOCKET, SO_ATTACH_FILTER, &amp;fprog, sizeof fprog);</pre>
<p>Not very useful, but it means we can now concentrate on writing the filter code itself. This filter consists of a single statement, <em>BPF_RET</em> that tells the kernel to deliver an amount of bytes of the packet to the receiving process and to return from the filter. The <em>BPF_K</em> option means that we give the amount of bytes as the argument to the statement, and in this case we give the largest possible value. In other words, this statement declares to deliver the whole packet and return from the filter.</p>
<p>To not wake up the process at all, and filter everything we deliver no bytes and return from the filter.</p>
<pre>BPF_STMT (BPF_RET|BPF_K, 0);</pre>
<p>You may want to test that too.</p>
<p>Ok, now let&#8217;s actually do some examination of the packets to filter out the noise. Recall that we&#8217;re dealing with nested messages here, messages inside messages, inside messages. Visualizing this is really important to understanding what you&#8217;re dealing with.</p>
<p><a href="http://netsplit.com/wp-content/uploads/2011/02/struct-proc_event.png"><img class="aligncenter size-full wp-image-427" title="struct proc_event" src="http://netsplit.com/wp-content/uploads/2011/02/struct-proc_event.png" alt="" width="640" height="240" /></a></p>
<p>The most basic filter code consists of three operations: load a value from the packet into the machine&#8217;s accumulator, compare that against a value and jump to a different instruction if equal (or not equal), and then possibly return or perform another operation.</p>
<p>All of the following filter code replaces whatever you had in the <em>filter[]</em> array before.</p>
<p>So first we should examine the <em>nlmsghdr</em> on the start of the packet, we want to make sure that there is just one <em>netlink</em> message in this packet. If there are multiple, we just pass the whole packet to userspace for dealing with. We check the <em>nlmsg_type</em> field to make sure it contains the value <em>NLMSG_DONE</em>.</p>
<pre>BPF_STMT (BPF_LD|BPF_H|BPF_ABS,
          offsetof (struct nlmsghdr, nlmsg_type));
BPF_JUMP (BPF_JMP|BPF_JEQ|BPF_K,
          htons (NLMSG_DONE),
          1, 0);
BPF_STMT (BPF_RET|BPF_K, 0xffffffff);</pre>
<p>The first statement says to load (<em>BPF_LD</em>) a <em>&#8220;halfword&#8221; </em>(16-bit) value (<em>BPF_H</em>) from the absolute offset (<em>BPF_ABS</em>) equivalent to the position of the <em>nlmsg_type</em> member in <em>struct nlmsghdr</em>. Since we expect that structure to be the start of the message, this means the accumulator should now have that value.</p>
<p>The next statement is a jump (<em>BPF_JMP</em>), it says to compare the accumulator for equality (<em>BPF_JEQ</em>) against the constant argument (<em>BPF_K</em>). We only want to continue if this is the sole message, so the value we compare against is <em>NLMSG_DONE</em> &#8211; first remembering to deal with host and network ordering.</p>
<p>If <em>true</em>, the jump will jump one statement; if <em>false</em> the jump will not jump any statements. These are the third and fourth arguments to the <em>BPF_JUMP</em> macro.</p>
<p>Note that the error case is always to return the whole packet to the process, waking it up. And the success case is future processing of the packet. This makes sure that we don&#8217;t filter unexpected packets that userspace may really need to deal with. Don&#8217;t use the socket filter for security filtering, it&#8217;s for reducing wake-ups.</p>
<p>So let&#8217;s filter the next set of values, we want to make sure that this netlink message is from the connector interface. Again we load the right <em>&#8220;word&#8221;</em> (32-bit) values (<em>BPF_W</em>) from the appropriate offsets and check them against constants.</p>
<pre>BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, id)
          + offsetof (struct cb_id, idx));
BPF_JUMP (BPF_JMP|BPF_JEQ|BPF_K,
          htonl (CN_IDX_PROC),
          1, 0);
BPF_STMT (BPF_RET|BPF_K, 0xffffffff);

BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, id)
          + offsetof (struct cb_id, idx));
BPF_JUMP (BPF_JMP|BPF_JEQ|BPF_K,
          htonl (CN_VAL_PROC),
          1, 0);
BPF_STMT (BPF_RET|BPF_K, 0xffffffff);</pre>
<p>So after this filter code has executed, we know the packet contains a single netlink message from the proc connector. Now we want to make sure it&#8217;s a fork message; this is a bit different from before, because now we explicitly <em>do</em> filter out the other message types so the return case for non-equality is to return zero bytes.</p>
<pre>BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, data)
          + offsetof (struct proc_event, what);
BPF_JUMP (BPF_JMP|BPF_JEQ|BF_K,
          htonl (PROC_EVENT_FORK),
          1, 0);
BPF_STMT (BPF_RET|BPF_K, 0);</pre>
<p>And now we can compare the <em>pid</em> and <em>tgid</em> values for the parent process and the child process fields. This is again slightly interesting because we can&#8217;t compare against an absolute offset with the jump instruction so we use the second <em>index register</em> instead (<em>BPF_X</em> in the jump instruction). Of course it would be too easy if we could load directly into that, so we have to do it via the <em>scratch memory store</em> instead; this requires loading into the accumulator (<em>BPF_LD</em>), storing into scratch memory (<span style="color: #000000;"><em>BPF_ST</em>) and loading the index register (<em>BPF_LDX</em>) from scratch memory (<em>BPF_MEM</em>).</span></p>
<pre>BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, data)
          + offsetof (struct proc_event, event_data)
          + offsetof (struct fork_proc_event, parent_pid));
BPF_STMT (BPF_ST, 0);
BPF_STMT (BPF_LDX|BPF_W|BPF_MEM, 0);</pre>
<p>Then we load the <em>tgid</em> value into the accumulator and we can compare and jump as before; if they are equal we want to continue, if they are inequal we want to filter the packet.</p>
<pre>BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, data)
          + offsetof (struct proc_event, event_data)
          + offsetof (struct fork_proc_event, parent_tgid));
BPF_JUMP (BPF_JMP|BPF_JEQ|BPF_X,
          0,
          1, 0);
BPF_STMT (BPF_RET|BPF_K, 0);</pre>
<p>Then we do the same for the child field.</p>
<pre>BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, data)
          + offsetof (struct proc_event, event_data)
          + offsetof (struct fork_proc_event, parent_pid));
BPF_STMT (BPF_ST, 0);
BPF_STMT (BPF_LDX|BPF_W|BPF_MEM, 0);

BPF_STMT (BPF_LD|BPF_W|BPF_ABS,
          NLMSG_LENGTH (0) + offsetof (struct cn_msg, data)
          + offsetof (struct proc_event, event_data)
          + offsetof (struct fork_proc_event, parent_tgid));

BPF_JUMP (BPF_JMP|BPF_JEQ|BPF_X,
          0,
          1, 0);

BPF_STMT (BPF_RET|BPF_K, 0);</pre>
<p>After all that filter hurdling, we have a packet that we want to pass through to the process, so the final instruction is a return of the largest packet size.</p>
<pre>BPF_STMT (BPF_RET|BPF_K, 0xffffffff);</pre>
<p>That&#8217;s it. Of course, what you do with this is up to you. One example could be a daemon that watches for excessive forks and kills fork bombs before they kill the machine. Since you get notification of changes of <em>uid</em> or <em>gid</em>, another example could be a security audit daemon, etc.</p>
<p>Upstart uses this interface for its own nefarious process tracking purposes.</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2011/02/09/the-proc-connector-and-socket-filters/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Leaving Canonical</title>
		<link>http://netsplit.com/2011/01/11/leaving-canonical/</link>
		<comments>http://netsplit.com/2011/01/11/leaving-canonical/#comments</comments>
		<pubDate>Tue, 11 Jan 2011 02:34:45 +0000</pubDate>
		<dc:creator>scott</dc:creator>
				<category><![CDATA[Canonical]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://netsplit.com/?p=398</guid>
		<description><![CDATA[This will be my last week working for Canonical Ltd. I joined the company almost seven years ago, right at its inception.  I was contracting at the time and a member of the Debian project maintaining the dpkg package manager, &#8230; <a href="http://netsplit.com/2011/01/11/leaving-canonical/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>This will be my last week working for <a href="http://www.canonical.com/">Canonical Ltd</a>.</p>
<p>I joined the company almost seven years ago, right at its inception.  I was contracting at the time and a member of the <a href="http://www.debian.org/">Debian</a> project maintaining the dpkg package manager, when I received an e-mail out of the blue that led to a phone call with a South African I&#8217;d never heard of who wanted to offer me a dream job working on a Debian-based Linux distribution.  Sadly I never kept that original e-mail, but I tried to replicate it from memory for Canonical&#8217;s 5th birthday:</p>
<blockquote><p>Dear Friend,</p>
<p>How are you and your family hope fine?</p>
<p>I am Mark SHUTTLEWORTH, from the great country of SOUTH AFRICA.</p>
<p>Due to good fortune mine in business, I have come into money of 	the sum $575,000,000 (US).</p>
<p>I would like to with you discuss BUSINESS OPPORTUNITY, and 	solicit your confidentiality in this transaction.</p>
<p>Pleased to discuss by phone at your earliest convenience.</p></blockquote>
<p>Ok, Mark wasn&#8217;t really a Nigerian 419 scammer, but some people did discard his e-mail as spam!  The job sounded interesting, and I was largely waiting for him to stop talking on the phone so I could say yes.  Even better, he was going to pay me up front for the first couple of months because the company hadn&#8217;t been formed yet let alone contracts signed and such.  No, I didn&#8217;t have to send him any money first to make the transaction happen <img src='http://netsplit.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>So I joined the super-secret IRC channel (#weirdos, on the FreeNode IRC network, just fire up Pidgin in Ubuntu and&#8230;) and discovered <a href="http://bethesignal.org/">Jeff Waugh</a>, Robert Collins and <a href="https://twitter.com/thommay">Thom May</a> already onboard.  This was going to be big.  After a month of being in awe at each new person being brought on, we had our first meeting in London over Easter.  For many this was their decision time about whether to join, or not.  Plans were drawn up, mostly on napkins at <a href="http://www.pizzaexpress.com/">Pizza Express</a> in Sloane Square:</p>
<div id="attachment_402" class="wp-caption aligncenter" style="width: 310px"><a href="http://netsplit.com/wp-content/uploads/2011/01/dscn0998.jpg"><img class="size-medium wp-image-402" title="The Original Group" src="http://netsplit.com/wp-content/uploads/2011/01/dscn0998-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">Photo by Lamont Jones</p></div>
<p>Funnily enough, there&#8217;s a Pizza Express in <a href="http://en.wikipedia.org/wiki/Millbank_Tower">Millbank Tower</a>, the current location of Canonical&#8217;s Offices.</p>
<p>We weren&#8217;t very good at coming up with names, the original domain name of the company was no-name-yet.com and the Debian folk called us the Super-Secret-Debian-Startup.  The company started out as MRS Virtual Development (Mark&#8217;s middle name is Richard).  And the nickname for the distribution before Ubuntu was settled as the final name was The Warty Warthog.</p>
<p>Everything was announced at Debconf in Porto Alegre, Brazil.  The first of many long economy class flights taken on behalf of the company.  This meant that by the time Jeff and I attended GUADEC in Kristiansand, word had got around.  There was much joking about our insane plans:</p>
<blockquote><p>Mrs VD&#8217;s Warty Ubuntu?  Sounds like an STI cream!<br />
Yes, it cures Red Hat.</p></blockquote>
<p>Many were of the opinion that users just didn&#8217;t want a six-monthly release of Debian, with a hard emphasis on the Desktop, hotplug and making things just work.  Fortunately they were wrong, but we didn&#8217;t have time to be smug because things got a bit out of hand.  I remember Mark saying that his goal for the first two years was that Ubuntu be in the top three Linux distributions.  Ah.</p>
<p>Next up was our first ever big company meeting.  Lots of variations happened of these over the years before we finally settled into the Ubuntu Developer Summit (UDS) format.  Initially they were all-hands events, and started off a bit more like sprints/rallies than anything like the current schedule-frenzy that is UDS.  Fortunately one of the changes is that they&#8217;ve gotten a bit shorter.  After a two week coding sprint at Mark&#8217;s apartment in London, there was a two week all-hands in Oxford, UK.</p>
<div id="attachment_403" class="wp-caption aligncenter" style="width: 310px"><a href="http://netsplit.com/wp-content/uploads/2011/01/dscfd002-Lifeless-strokes-the-Hoverbook-lovingly.jpg"><img class="size-medium wp-image-403" title="Robert and the Hoverbook" src="http://netsplit.com/wp-content/uploads/2011/01/dscfd002-Lifeless-strokes-the-Hoverbook-lovingly-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">Robert and the Hoverbook</p></div>
<p>I wanted to find a photo with laptops in, for some this event was painful.  We learned that hotel cleaners are not always to be trusted.  Fortunately Robert&#8217;s laptop was far too heavy to be stolen.</p>
<p>Then Ubuntu 4.10 was out!  And the world changed.  Well, maybe a bit.</p>
<p>The next conference was LCA in Canberra, followed by our own third developer meeting in Sydney.  This developer meeting was pretty recognizable as a UDS in fact, except two weeks long and all-hands again.  I was granted the very rare privilege of flying to Australia on Mark&#8217;s personal private jet.</p>
<div id="attachment_404" class="wp-caption aligncenter" style="width: 310px"><a href="http://netsplit.com/wp-content/uploads/2011/01/dscf0242-Canberra-ground-staff.jpg"><img class="size-medium wp-image-404" title="&quot;Canonical One&quot;" src="http://netsplit.com/wp-content/uploads/2011/01/dscf0242-Canberra-ground-staff-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">&quot;Canonical One&quot;</p></div>
<p>I actually got to fly on this a few more times over the years, and after an amazing night-time landing flying across San Francisco into San Jose airport, got the bug and learned to fly myself!  But I&#8217;m digressing.</p>
<p>On the plane we&#8217;d bought Ubuntu 5.04 CDs, our second release.  We&#8217;d got a few boxes of them, and it was my responsibility to look after them and try and persuade the conference staff to let us put some out to pick up.  I took a small handful and wandered to the reception desk, with a sheepish look on my face.  I was accompanied back to my dorm with the reception staff who wanted the rest!  I think that&#8217;s when I finally realized how popular Ubuntu had become, seeing almost everyone at the conference running Ubuntu machines only solidified that.</p>
<p>We had a big printed-out version of the 5.04 CD cover that we got people at the conference to sign.  It&#8217;s still on the wall of the Canonical Offices to this day.</p>
<div id="attachment_405" class="wp-caption aligncenter" style="width: 310px"><a href="http://netsplit.com/wp-content/uploads/2011/01/dscf0266-Matthew-signing-the-Ubuntu-poster.jpg"><img class="size-medium wp-image-405" title="Matthew signing the Ubuntu poster" src="http://netsplit.com/wp-content/uploads/2011/01/dscf0266-Matthew-signing-the-Ubuntu-poster-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">Matthew signing the Ubuntu poster</p></div>
<p>I&#8217;ve probably made all this sounds a bit glamorous, jet set life style, celebrity, probably even danger.  But at the end of the day, it was a job.  For example, at no point did we find ourselves white-water rafting in Brazil with an instructor who didn&#8217;t speak English.</p>
<div id="attachment_406" class="wp-caption aligncenter" style="width: 310px"><a href="http://netsplit.com/wp-content/uploads/2011/01/canonical-rafting-1.jpg"><img class="size-medium wp-image-406" title="White-water rafting" src="http://netsplit.com/wp-content/uploads/2011/01/canonical-rafting-1-300x200.jpg" alt="" width="300" height="200" /></a><p class="wp-caption-text">White-water rafting</p></div>
<p>To this day I don&#8217;t know whether &#8220;Frenchie!&#8221; means &#8220;Faster!&#8221; or &#8220;STOP! We&#8217;re going to DIE!&#8221;.</p>
<p>There was a lot of hard work too.  When we were preparing to release our first Late To Ship, err, sorry, Long Term Support release a few of us decided to use the space at Canonical&#8217;s new offices at Mossop Street to get together and test the hell out of it.  The idea being that any serious issues could be fixed there and then.  We still do these &#8220;Release Sprints&#8221; to this day, though the next one breaks the tradition of being in London due to some Prince getting married that week.</p>
<div id="attachment_407" class="wp-caption aligncenter" style="width: 310px"><a href="http://netsplit.com/wp-content/uploads/2011/01/DSC00018.jpg"><img class="size-medium wp-image-407" title="Everything will be OK" src="http://netsplit.com/wp-content/uploads/2011/01/DSC00018-300x225.jpg" alt="" width="300" height="225" /></a><p class="wp-caption-text">Everything will be OK</p></div>
<p>We kept track of the release status using a sign helpfully provided for us by the then-COO Jane Silber, it has two sides.  This is the happy side.</p>
<p>More releases followed, more conferences, more meetings.  We got better at the releases, and even started getting better at the conferences after enough goes at it.  The meetings were generally ok, except sometimes there was a bit of a problem <em>getting</em> to them!</p>
<p>You see, myself and a colleague <a href="http://smackerelofopinion.blogspot.com/">Colin King</a> are cursed.  Seriously, if you ever find yourself getting on a plane and see both of us on that same plane, get off the plane.  No, better yet, get the hell out of the city!</p>
<p>You remember that great big snow storm in the UK back in the winter of 2009?  That was our fault!  Colin and I were booked to fly on the same flight.</p>
<div id="attachment_408" class="wp-caption aligncenter" style="width: 235px"><a href="http://netsplit.com/wp-content/uploads/2011/01/2180886.jpg"><img class="size-medium wp-image-408" title="Cancelled" src="http://netsplit.com/wp-content/uploads/2011/01/2180886-225x300.jpg" alt="" width="225" height="300" /></a><p class="wp-caption-text">Cancelled</p></div>
<p>Things went well until we were sat in the Gatwick business lounge, and it started snowing outside.  Our plane never arrived so our flight was cancelled.  Since the queue for the Easyjet desk went around the airport three times, our travel agent got us booked on a flight out of City Airport in the morning, and sorted us a hotel by that airport.  Easy.  Gatwick Express into London, District Line tube, then transfer onto a bus for City Airport.  Only problem is by the time we&#8217;d left the tube, there were several feet of snow on the ground and more falling all the time, the buses were not running and we were a couple of hours walk from the airport.  Oh well, needs must!</p>
<p>The next day we rebooked repeatedly onto later flights until the afternoon, when we finally managed to get Eurostar tickets to Brussels.  Another night in a hotel, another 6am start, ICE to Köln and another to Berlin.  Finally arriving Tuesday afternoon.  Our average pace from Gatwick to Berlin turned out to be roughly walking speed.</p>
<p>Now this might have been an interesting story for the dinner table, except it <em>happened again!</em> That volcano in Iceland?  Our fault!  Just over a year since the previous time, we were at a conference in San Francisco together, and we ground all air traffic in the skies of Northern Europe.  We really are sorry about that, and since the disasters seem to be escalating, that&#8217;s why I have to leave Canonical.</p>
<div id="attachment_409" class="wp-caption aligncenter" style="width: 235px"><a href="http://netsplit.com/wp-content/uploads/2011/01/86969404.jpg"><img class="size-medium wp-image-409" title="Running in San Francisco" src="http://netsplit.com/wp-content/uploads/2011/01/86969404-225x300.jpg" alt="" width="225" height="300" /></a><p class="wp-caption-text">Running in San Francisco</p></div>
<p>While an amusing thought, there&#8217;s actually a small amount of truth to it.  You see, due to airlines, flight priorities and so-forth I was actually stuck in San Francisco for three weeks as a result of the volcano.  Instead of attending the release sprint, I worked from the offices of Ubuntu-friendly companies in the bay area and fixed problems flagged the previous day by the release manager.  At night I explored the city.</p>
<p>I&#8217;d been to SF before quite a few times, including a long holiday with my then-partner, and I&#8217;ve always loved the place.  I was for all intents and purposes living there for three weeks, and a previous dream to move there got stronger.</p>
<p>I also bought an iPad which made me realize that perhaps the desktop distribution was approaching a decline.</p>
<p>I also got a chance to do pure development again, having bugs triaged for me and I fell in love with programming again &#8211; rather than the oddball effort that is distribution engineering.</p>
<p>And I was working in offices, and while I&#8217;ve enjoyed working from home for the past seven years, I was far more productive in the office environment.</p>
<p>There are lots of other reasons of course, but ultimately they all come down to it being time for a change.  So where next?</p>
<div id="attachment_410" class="wp-caption aligncenter" style="width: 235px"><a href="http://netsplit.com/wp-content/uploads/2011/01/167760050.jpg"><img class="size-medium wp-image-410" title="One Infinite Loop" src="http://netsplit.com/wp-content/uploads/2011/01/167760050-225x300.jpg" alt="" width="225" height="300" /></a><p class="wp-caption-text">One Infinite Loop</p></div>
<p>No.</p>
<p>While I do really admire what <a href="http://www.apple.com/">Apple</a> have done, they&#8217;ve already got their ideas set in stone and I want to <em>beat</em> them.</p>
<div id="attachment_412" class="wp-caption aligncenter" style="width: 235px"><a href="http://netsplit.com/wp-content/uploads/2011/01/167126083.jpg"><img class="size-medium wp-image-412" title="Google" src="http://netsplit.com/wp-content/uploads/2011/01/167126083-225x300.jpg" alt="" width="225" height="300" /></a><p class="wp-caption-text">Google</p></div>
<p>So I&#8217;m going to be joining <a href="http://www.google.com/">Google</a>.  After months of waiting, and worrying, my US Visa was approved last week and I&#8217;m half way through procrastinating about packing my house and life up for the big move!</p>
<p>Don&#8217;t worry though, I won&#8217;t be disappearing into a black hole!  I&#8217;m retaining my Ubuntu membership, Core Developer upload privileges and my seat on the Ubuntu Technical Board (which means there will be a non-Canonical person on the board once again!).  I&#8217;ve even re-activated my Debian membership.</p>
<p>I&#8217;m also going to continue developing <a href="http://upstart.at/">Upstart</a>, I&#8217;ve been working hard on the new version for what seems like an age now, and I&#8217;m not giving up now; not in the least because Google use Upstart themselves on many projects, including <a href="http://www.google.com/chromeos/">Chrome OS</a>.</p>
<p>The only real worry is whether I end up spending more time at the Google Gym or the wide variety of Google cafés.</p>
]]></content:encoded>
			<wfw:commentRss>http://netsplit.com/2011/01/11/leaving-canonical/feed/</wfw:commentRss>
		<slash:comments>70</slash:comments>
		</item>
	</channel>
</rss>

