Blog O' Matty


Using Linux extended attributes

This article was posted by Matty on 2007-01-03 21:38:00 -0400 -0400

The Linux EXT2/EXT3 file systems comes with support for extended attributes. Extended attributes can be used to enforce administrative policies beyond standard permissions on individual files, which allows things like compression, secure deletion, no atime updates, file immutability, etc. to be controlled on a per file basis. Each extended attribute has a unique character associated to it, and the current set of supported attributes are described in the following table (you can also view these in the chattr(1) man page):

a - Append only
c - Compress file
d - Exclude from dump
i - Make the file immutable
j - Journal file data
s - Securely delete file
u - When a file is deleted, save it's contents
A - Don't update the files atime
S - When a file is written, it is written to disk synchronously

To check if one of the extended attributes has been assigned to a file, the lsattr command can be run without any arguments to see if extended attributes are assigned to files in the current directory, or with a file name or regular expression to check if those files contain extended attributes:

$ lsattr foo

------------- foo

To set an extended attribute, the chattr command can be run with a file name, or a regular expression to indicate the files the attributes should be applied to:

$ chattr +cs foo

$ lsattr foo

s-------c---- foo

Extended attributes are super useful, but unfortunately a few attributes like secure delete and compression are not yet supported w/o additional kernel patches ( hopefully this will be one of the items added in ext4 and a future kernel release!). If you would like to use compression now, Solaris 10 and ZFS is the way to go.

Measuring Apache request processing time

This article was posted by Matty on 2007-01-02 14:27:00 -0400 -0400

I support a fair number of Apache web server instances, and periodically need to measure the time it takes Apache (and it’s various modules) to process a request. On Solaris 10 hosts, I can use DTrace to retrieve this information on the fly. Since Solaris 9 and CentOS and Redhat Linux don’t come with DTrace, I use a different approach on these platforms.

To get the time when each request was received by Apache, I used mod_header’s “Header” directive, and “%t” option (time when a request was received, measured in milliseconds from the epoch), to add a response header with the time each request was received:

Header set X-Request-Received: %t

To get the total time Apache spent processing a request, I use mod_header’s “Header” directive, and “%D” option (milliseconds spent processing the request), to add a response header with the total time Apache spent processing each request:

Header set X-Request-Processing-Time: %D

Since I don’t always need the headers to be present, I like to be able to enable and disable them from the command line. The easiest way to do this is by enclosing the directives in a conditional block similar to the following:

<IfDefine RequestTime>
Header set X-Request-Received: %t
Header set X-Request-Processing-Time: %D
</IfDefine>

And using the httpd “-D” option to enable them:

$ httpd -k start -DRequestTime

After the headers are enabled, you will see entries similar to the following in each HTTP response:

$ curl -v http://192.168.1.13:8080/

About to connect() to 192.168.1.13 port 8080

< ..... >

< HTTP/1.1 200 OK
< Date: Tue, 02 Jan 2007 17:59:42TGMT:00-04:00
< Server: Apache/2.2.3 (Unix) DAV/2
< Last-Modified: Sat, 20 Nov 2004 20:16:24 GMT
< ETag: "34d37-2c-4c23b600"
< Accept-Ranges: bytes
< Content-Length: 44
< X-Request-Received: t=1167760782452525
< X-Request-Processing-Time: D=3513
< Content-Type: text/html

Similar capabilities are available for measuring request processing time on the client. Total time is helpful, but knowing how much of that time was consumed by Apache is invaluable!

Using ZFS clones to simplify upgrades

This article was posted by Matty on 2006-12-29 16:34:00 -0400 -0400

One cool ZFS feature that was introduced in Solaris 10 11/06 is the ability to clone a file system. This is a truly powerful tool, since it allows admins to create copies of file systems prior to performing upgrades, and a way to roll a file system back to a previous state (this provides a simple lightweight method to back out changes if upgrades go awry). To illustrated just how useful this is, let’s create a clone of the file system oradata. To clone oradata, we first need to take a sapshot of the oradata file system:

$ zfs snapshot striped/oradata@ordata_snap

Once a snapshot is created, the zfs utilities’ “clone” option can be used to create a clone of the file system from the snaphost we just created:

$ zfs clone striped/oradata@ordata_snap striped/oradata_clone

After the clone is created, it can be “promoted” to a file system with the zfs utilities’ “promote” option:

$ zfs promote striped/oradata_clone

If everything works correctly (which it should), the clone and the file system the clone was created from will appear in the df output:

$ df -h

Filesystem size used avail capacity Mounted on
/dev/dsk/c0d0s0 17G 2.9G 14G 18% /
/devices 0K 0K 0K 0% /devices
/dev 0K 0K 0K 0% /dev
ctfs 0K 0K 0K 0% /system/contract
proc 0K 0K 0K 0% /proc
mnttab 0K 0K 0K 0% /etc/mnttab
swap 1016M 768K 1015M 1% /etc/svc/volatile
objfs 0K 0K 0K 0% /system/object
/usr/lib/libc/libc_hwcap1.so.1
17G 2.9G 14G 18% /lib/libc.so.1
fd 0K 0K 0K 0% /dev/fd
swap 1015M 0K 1015M 0% /tmp
swap 1015M 24K 1015M 1% /var/run
striped 52G 27K 50G 1% /striped
striped/oradata 52G 300M 50G 1% /striped/oradata
striped/oradata_clone
52G 300M 50G 1% /striped/oradata_clone

Now let’s pretend that a DBA accidentally deletes the Oracle datafiles in /striped/oradata:

$ rm -f /striped/oradata/

Oops! Since oradata_clone is a clone of the oradata file system, we can restore oradata by first deleting the original file system (you could also rename it if you wanted to keep it around):

$ zfs destroy -f striped/oradata

And then renaming the clone to take it’s place:

$ zfs rename striped/oradata_clone striped/oradata

Once the rename occurs, everything is as it once was:

$ df -h

Filesystem size used avail capacity Mounted on
/dev/dsk/c0d0s0 17G 2.9G 14G 18% /
/devices 0K 0K 0K 0% /devices
/dev 0K 0K 0K 0% /dev
ctfs 0K 0K 0K 0% /system/contract
proc 0K 0K 0K 0% /proc
mnttab 0K 0K 0K 0% /etc/mnttab
swap 1015M 768K 1014M 1% /etc/svc/volatile
objfs 0K 0K 0K 0% /system/object
/usr/lib/libc/libc_hwcap1.so.1
17G 2.9G 14G 18% /lib/libc.so.1
fd 0K 0K 0K 0% /dev/fd
swap 1014M 0K 1014M 0% /tmp
swap 1014M 24K 1014M 1% /var/run
striped 52G 26K 50G 1% /striped
striped/oradata 52G 300M 50G 1% /striped/oradata

$ ls -la /striped/oradata

total 614555
drwxr-xr-x 2 root sys 5 Dec 24 11:49 .
drwxr-xr-x 3 root sys 3 Dec 24 11:59 ..
-rw-r--r-- 1 root root 104857600 Dec 24 11:47 iklts01.dbf
-rw-r--r-- 1 root root 104857600 Dec 24 11:48 iklts02.dbf
-rw-r--r-- 1 root root 104857600 Dec 24 11:49 iklts03.dbf

This has so many uses, and once ZFS boot is incorporated, using clones to protect yourself from rogue patches will be one of the coolest things ever! Shibby!

Disabling old wordpress comments

This article was posted by Matty on 2006-12-29 16:20:00 -0400 -0400

As with most individuals that manage a blog, I get inundated with comment spam. Based on some research I did, it looks like almost all of the blog spam occurs for older posts, especially those over 30 days old. Based on this information, I decided to disable comments for all old posts older than 30 days. It turns out that you can’t do this directly from wordpress without a plugin, so I decided to adjust the “comment_status” column in the wp_posts table directly. To remove comment spam for all posts older than 30 days, I first used the GNU date utility to find the date 30 days ago:

$ date --date="30 days ago" "+%Y-%m-%d"
2006-11-29

Once I had the date string from 30 days ago, I connected to the MySQL database that hosts my blog, and ran the following SQL query to disable posts for all entries greater than the date returned form GNU date:

$ mysql -umatty -p -h mysql.prefetch.net
Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 16155903 to server version: 4.0.27-standard-log

Type ‘help;’ or ‘\h’ for help. Type ' mysql> use matty Database changed

mysql> UPDATE wp_posts SET comment_status = ‘closed’ WHERE post_date < ‘2006-11-29’ AND post_status = ‘publish’

mysql> quit Bye

Now that old posts don’t have comments enabled, I am curious to see how the comment spammers react.

Configuring crontab mail destinations with MAILTO

This article was posted by Matty on 2006-12-29 02:40:00 -0400 -0400

When scripts executing from cron write to stdout or stderr, the results are emailed to the user the job is running in the context of. One way to control where the mail is sent is by adding a “MAILTO” line to the top of the crontab entry for the user that is running the cron job. Here is an example:

$ crontab -l
MAILTO=matty

Each time this job runs, the user matty will get emailed with the results of the script. You can also use /etc/aliases to assist with this on a global scale, but sometimes that isn’t an option.