From: Damien Le Moal <hidden> Date: 2021-10-27 02:22:26
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
This series adds support to the scsi disk driver to retreive this
information and advertize it to user space through sysfs. libata is
also modified to handle ATA drives.
The first patch adds the block layer plumbing to expose concurrent
sector ranges of the device through sysfs as a sub-directory of the
device sysfs queue directory. Patch 2 and 3 add support to sd and
libata. Finally patch 4 documents the sysfs queue attributed changes.
Patch 5 fixes a typo in the document file (strictly speaking, not
related to this series).
This series does not attempt in any way to optimize accesses to
multi-actuator devices (e.g. block IO schedulers or filesystems). This
initial support only exposes the independent access ranges information
to user space through sysfs.
Changes from v8:
* Rebase on latest for-5.16/block tree
* Added reviewed-by tags
Changes from v7:
* Renamed functions to spell out "independent_access_range" instead of
using contracted names such as iaranges. Structure fields names are
changed to ia_ranges from iaranges.
* Added reviewed-by tags in patch 4 and 5
Changes from v6:
* Changed patch 1 to prevent a device from registering overlapping
independent access ranges.
Changes from v5:
* Changed type names in patch 1:
- struct blk_crange -> sturct blk_independent_access_range
- struct blk_cranges -> sturct blk_independent_access_ranges
All functions and variables are renamed accordingly, using shorter
names related to the new type names, e.g.
sturct blk_independent_access_ranges -> iaranges or iars.
* Update the commit message of patch 1 to 4. Patch 1 and 4 titles are
also changed.
* Dropped reviewed-tags on modified patches. Patch 3 and 5 are
unmodified
Changes from v4:
* Fixed kdoc comment function name mismatch for disk_register_cranges()
in patch 1
Changes from v3:
* Modified patch 1:
- Prefix functions that take a struct gendisk as argument with
"disk_". Modified patch 2 accordingly.
- Added a functional release operation for struct blk_cranges kobj to
ensure that this structure is freed only after all references to it
are released, including kobject_del() execution for all crange sysfs
entries.
* Added patch 5 to separate the typo fix from the crange documentation
addition.
* Added reviewed-by tags
Changes from v2:
* Update patch 1 to fix a compilation warning for a potential NULL
pointer dereference of the cr argument of blk_queue_set_cranges().
Warning reported by the kernel test robot [off-list ref]).
Changes from v1:
* Moved libata-scsi hunk from patch 1 to patch 3 where it belongs
* Fixed unintialized variable in patch 2
Reported-by: kernel test robot [off-list ref]
Reported-by: Dan Carpenter <dan.carpenter@oracle.com
* Changed patch 3 adding struct ata_cpr_log to contain both the number
of concurrent ranges and the array of concurrent ranges.
* Added a note in the documentation (patch 4) about the unit used for
the concurrent ranges attributes.
Damien Le Moal (5):
block: Add independent access ranges support
scsi: sd: add concurrent positioning ranges support
libata: support concurrent positioning ranges log
doc: document sysfs queue/independent_access_ranges attributes
doc: Fix typo in request queue sysfs documentation
Documentation/block/queue-sysfs.rst | 33 ++-
block/Makefile | 2 +-
block/blk-ia-ranges.c | 348 ++++++++++++++++++++++++++++
block/blk-sysfs.c | 26 ++-
block/blk.h | 4 +
drivers/ata/libata-core.c | 57 ++++-
drivers/ata/libata-scsi.c | 48 +++-
drivers/scsi/sd.c | 81 +++++++
drivers/scsi/sd.h | 1 +
include/linux/ata.h | 1 +
include/linux/blkdev.h | 39 ++++
include/linux/libata.h | 15 ++
12 files changed, 634 insertions(+), 21 deletions(-)
create mode 100644 block/blk-ia-ranges.c
--
2.31.1
From: Damien Le Moal <hidden> Date: 2021-10-27 02:22:30
The Concurrent Positioning Ranges VPD page (for SCSI) and data log page
(for ATA) contain parameters describing the set of contiguous LBAs that
can be served independently by a single LUN multi-actuator hard-disk.
Similarly, a logically defined block device composed of multiple disks
can in some cases execute requests directed at different sector ranges
in parallel. A dm-linear device aggregating 2 block devices together is
an example.
This patch implements support for exposing a block device independent
access ranges to the user through sysfs to allow optimizing device
accesses to increase performance.
To describe the set of independent sector ranges of a device (actuators
of a multi-actuator HDDs or table entries of a dm-linear device),
The type struct blk_independent_access_ranges is introduced. This
structure describes the sector ranges using an array of
struct blk_independent_access_range structures. This range structure
defines the start sector and number of sectors of the access range.
The ranges in the array cannot overlap and must contain all sectors
within the device capacity.
The function disk_set_independent_access_ranges() allows a device
driver to signal to the block layer that a device has multiple
independent access ranges. In this case, a struct
blk_independent_access_ranges is attached to the device request queue
by the function disk_set_independent_access_ranges(). The function
disk_alloc_independent_access_ranges() is provided for drivers to
allocate this structure.
struct blk_independent_access_ranges contains kobjects (struct kobject)
to expose to the user through sysfs the set of independent access ranges
supported by a device. When the device is initialized, sysfs
registration of the ranges information is done from blk_register_queue()
using the block layer internal function
disk_register_independent_access_ranges(). If a driver calls
disk_set_independent_access_ranges() for a registered queue, e.g. when a
device is revalidated, disk_set_independent_access_ranges() will execute
disk_register_independent_access_ranges() to update the sysfs attribute
files. The sysfs file structure created starts from the
independent_access_ranges sub-directory and contains the start sector
and number of sectors of each range, with the information for each range
grouped in numbered sub-directories.
E.g. for a dual actuator HDD, the user sees:
$ tree /sys/block/sdk/queue/independent_access_ranges/
/sys/block/sdk/queue/independent_access_ranges/
|-- 0
| |-- nr_sectors
| `-- sector
`-- 1
|-- nr_sectors
`-- sector
For a regular device with a single access range, the
independent_access_ranges sysfs directory does not exist.
Device revalidation may lead to changes to this structure and to the
attribute values. When manipulated, the queue sysfs_lock and
sysfs_dir_lock mutexes are held for atomicity, similarly to how the
blk-mq and elevator sysfs queue sub-directories are protected.
The code related to the management of independent access ranges is
added in the new file block/blk-ia-ranges.c.
Signed-off-by: Damien Le Moal <redacted>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
---
block/Makefile | 2 +-
block/blk-ia-ranges.c | 348 +++++++++++++++++++++++++++++++++++++++++
block/blk-sysfs.c | 26 ++-
block/blk.h | 4 +
include/linux/blkdev.h | 39 +++++
5 files changed, 410 insertions(+), 9 deletions(-)
create mode 100644 block/blk-ia-ranges.c
@@ -0,0 +1,348 @@+// SPDX-License-Identifier: GPL-2.0+/*+*Blockdeviceconcurrentpositioningranges.+*+*Copyright(C)2021WesternDigitalCorporationoritsAffiliates.+*/+#include<linux/kernel.h>+#include<linux/blkdev.h>+#include<linux/slab.h>+#include<linux/init.h>++#include"blk.h"++staticssize_t+blk_ia_range_sector_show(structblk_independent_access_range*iar,+char*buf)+{+returnsprintf(buf,"%llu\n",iar->sector);+}++staticssize_t+blk_ia_range_nr_sectors_show(structblk_independent_access_range*iar,+char*buf)+{+returnsprintf(buf,"%llu\n",iar->nr_sectors);+}++structblk_ia_range_sysfs_entry{+structattributeattr;+ssize_t(*show)(structblk_independent_access_range*iar,char*buf);+};++staticstructblk_ia_range_sysfs_entryblk_ia_range_sector_entry={+.attr={.name="sector",.mode=0444},+.show=blk_ia_range_sector_show,+};++staticstructblk_ia_range_sysfs_entryblk_ia_range_nr_sectors_entry={+.attr={.name="nr_sectors",.mode=0444},+.show=blk_ia_range_nr_sectors_show,+};++staticstructattribute*blk_ia_range_attrs[]={+&blk_ia_range_sector_entry.attr,+&blk_ia_range_nr_sectors_entry.attr,+NULL,+};+ATTRIBUTE_GROUPS(blk_ia_range);++staticssize_tblk_ia_range_sysfs_show(structkobject*kobj,+structattribute*attr,char*buf)+{+structblk_ia_range_sysfs_entry*entry=+container_of(attr,structblk_ia_range_sysfs_entry,attr);+structblk_independent_access_range*iar=+container_of(kobj,structblk_independent_access_range,kobj);+ssize_tret;++mutex_lock(&iar->queue->sysfs_lock);+ret=entry->show(iar,buf);+mutex_unlock(&iar->queue->sysfs_lock);++returnret;+}++staticconststructsysfs_opsblk_ia_range_sysfs_ops={+.show=blk_ia_range_sysfs_show,+};++/*+*Independentaccessrangeentriesarenotfreedindividually,butalltogether+*withstructblk_independent_access_rangesanditsarrayofranges.Since+*kobject_add()takesareferenceontheparentkobjectcontainedin+*structblk_independent_access_ranges,thearrayofindependentaccessrange+*entriescannotbefreeduntilkobject_del()iscalledforallentries.+*Sowedonotneedtodoanythinghere,butstillneedthisno-oprelease+*operationtoavoidcomplaintsfromthekobjectcode.+*/+staticvoidblk_ia_range_sysfs_nop_release(structkobject*kobj)+{+}++staticstructkobj_typeblk_ia_range_ktype={+.sysfs_ops=&blk_ia_range_sysfs_ops,+.default_groups=blk_ia_range_groups,+.release=blk_ia_range_sysfs_nop_release,+};++/*+*Thiswillbeexecutedonlyafterallindependentaccessrangeentriesare+*removedwithkobject_del(),atwhichpoint,itissafetofreeeverything,+*includingthearrayofranges.+*/+staticvoidblk_ia_ranges_sysfs_release(structkobject*kobj)+{+structblk_independent_access_ranges*iars=+container_of(kobj,structblk_independent_access_ranges,kobj);++kfree(iars);+}++staticstructkobj_typeblk_ia_ranges_ktype={+.release=blk_ia_ranges_sysfs_release,+};++/**+*disk_register_ia_ranges-registerwithsysfsasetofindependent+*accessranges+*@disk:Targetdisk+*@new_iars:Newsetofindependentaccessranges+*+*Registerwithsysfsasetofindependentaccessrangesfor@disk.+*If@new_iarsisnotNULL,thissetofrangesisregisteredandtheoldset+*specifiedbyq->ia_rangesisunregistered.Otherwise,q->ia_rangesis+*registeredifitisnotalready.+*/+intdisk_register_independent_access_ranges(structgendisk*disk,+structblk_independent_access_ranges*new_iars)+{+structrequest_queue*q=disk->queue;+structblk_independent_access_ranges*iars;+inti,ret;++lockdep_assert_held(&q->sysfs_dir_lock);+lockdep_assert_held(&q->sysfs_lock);++/* If a new range set is specified, unregister the old one */+if(new_iars){+if(q->ia_ranges)+disk_unregister_independent_access_ranges(disk);+q->ia_ranges=new_iars;+}++iars=q->ia_ranges;+if(!iars)+return0;++/*+*Atthispoint,iarsisthenewsetofsectoraccessrangesthatneeds+*toberegisteredwithsysfs.+*/+WARN_ON(iars->sysfs_registered);+ret=kobject_init_and_add(&iars->kobj,&blk_ia_ranges_ktype,+&q->kobj,"%s","independent_access_ranges");+if(ret){+q->ia_ranges=NULL;+kfree(iars);+returnret;+}++for(i=0;i<iars->nr_ia_ranges;i++){+iars->ia_range[i].queue=q;+ret=kobject_init_and_add(&iars->ia_range[i].kobj,+&blk_ia_range_ktype,&iars->kobj,+"%d",i);+if(ret){+while(--i>=0)+kobject_del(&iars->ia_range[i].kobj);+kobject_del(&iars->kobj);+kobject_put(&iars->kobj);+returnret;+}+}++iars->sysfs_registered=true;++return0;+}++voiddisk_unregister_independent_access_ranges(structgendisk*disk)+{+structrequest_queue*q=disk->queue;+structblk_independent_access_ranges*iars=q->ia_ranges;+inti;++lockdep_assert_held(&q->sysfs_dir_lock);+lockdep_assert_held(&q->sysfs_lock);++if(!iars)+return;++if(iars->sysfs_registered){+for(i=0;i<iars->nr_ia_ranges;i++)+kobject_del(&iars->ia_range[i].kobj);+kobject_del(&iars->kobj);+kobject_put(&iars->kobj);+}else{+kfree(iars);+}++q->ia_ranges=NULL;+}++staticstructblk_independent_access_range*+disk_find_ia_range(structblk_independent_access_ranges*iars,+sector_tsector)+{+structblk_independent_access_range*iar;+inti;++for(i=0;i<iars->nr_ia_ranges;i++){+iar=&iars->ia_range[i];+if(sector>=iar->sector&&+sector<iar->sector+iar->nr_sectors)+returniar;+}++returnNULL;+}++staticbooldisk_check_ia_ranges(structgendisk*disk,+structblk_independent_access_ranges*iars)+{+structblk_independent_access_range*iar,*tmp;+sector_tcapacity=get_capacity(disk);+sector_tsector=0;+inti;++/*+*WhilesortingtherangesinincreasingLBAorder,checkthatthe+*rangesdonotoverlap,thattherearenosectorholesandthatall+*sectorsbelongtoonerange.+*/+for(i=0;i<iars->nr_ia_ranges;i++){+tmp=disk_find_ia_range(iars,sector);+if(!tmp||tmp->sector!=sector){+pr_warn("Invalid non-contiguous independent access ranges\n");+returnfalse;+}++iar=&iars->ia_range[i];+if(tmp!=iar){+swap(iar->sector,tmp->sector);+swap(iar->nr_sectors,tmp->nr_sectors);+}++sector+=iar->nr_sectors;+}++if(sector!=capacity){+pr_warn("Independent access ranges do not match disk capacity\n");+returnfalse;+}++returntrue;+}++staticbooldisk_ia_ranges_changed(structgendisk*disk,+structblk_independent_access_ranges*new)+{+structblk_independent_access_ranges*old=disk->queue->ia_ranges;+inti;++if(!old)+returntrue;++if(old->nr_ia_ranges!=new->nr_ia_ranges)+returntrue;++for(i=0;i<old->nr_ia_ranges;i++){+if(new->ia_range[i].sector!=old->ia_range[i].sector||+new->ia_range[i].nr_sectors!=old->ia_range[i].nr_sectors)+returntrue;+}++returnfalse;+}++/**+*disk_alloc_independent_access_ranges-Allocateanindependentaccessranges+*datastructure+*@disk:targetdisk+*@nr_ia_ranges:Numberofindependentaccessranges+*+*Allocateastructblk_independent_access_rangesstructurewith@nr_ia_ranges+*accessrangedescriptors.+*/+structblk_independent_access_ranges*+disk_alloc_independent_access_ranges(structgendisk*disk,intnr_ia_ranges)+{+structblk_independent_access_ranges*iars;++iars=kzalloc_node(struct_size(iars,ia_range,nr_ia_ranges),+GFP_KERNEL,disk->queue->node);+if(iars)+iars->nr_ia_ranges=nr_ia_ranges;+returniars;+}+EXPORT_SYMBOL_GPL(disk_alloc_independent_access_ranges);++/**+*disk_set_independent_access_ranges-Setadiskindependentaccessranges+*@disk:targetdisk+*@iars:independentaccessrangesstructure+*+*Settheindependentaccessrangesinformationoftherequestqueue+*of@diskto@iars.If@iarsisNULLandtheindependentaccessranges+*structurealreadysetiscleared.Iftherearenodifferencesbetween+*@iarsandtheindependentaccessrangesstructurealreadyset,@iars+*isfreed.+*/+voiddisk_set_independent_access_ranges(structgendisk*disk,+structblk_independent_access_ranges*iars)+{+structrequest_queue*q=disk->queue;++if(WARN_ON_ONCE(iars&&!iars->nr_ia_ranges)){+kfree(iars);+iars=NULL;+}++mutex_lock(&q->sysfs_dir_lock);+mutex_lock(&q->sysfs_lock);++if(iars){+if(!disk_check_ia_ranges(disk,iars)){+kfree(iars);+iars=NULL;+gotoreg;+}++if(!disk_ia_ranges_changed(disk,iars)){+kfree(iars);+gotounlock;+}+}++/*+*Thismaybecalledforaregisteredqueue.E.g.duringadevice+*revalidation.Ifthatisthecase,weneedtounregistertheold+*setofindependentaccessrangesandregisterthenewset.Ifthe+*queueisnotregistered,registrationofthedevicerequestqueue+*willregistertheindependentaccessranges,soonlyswapinthe+*newsetandfreetheoldone.+*/+reg:+if(blk_queue_registered(q)){+disk_register_independent_access_ranges(disk,iars);+}else{+swap(q->ia_ranges,iars);+kfree(iars);+}++unlock:+mutex_unlock(&q->sysfs_lock);+mutex_unlock(&q->sysfs_dir_lock);+}+EXPORT_SYMBOL_GPL(disk_set_independent_access_ranges);
From: Damien Le Moal <hidden> Date: 2021-10-27 02:22:31
Add the sd_read_cpr() function to the sd scsi disk driver to discover
if a device has multiple concurrent positioning ranges (i.e. multiple
actuators on an HDD). The existence of VPD page B9h indicates if a
device has multiple concurrent positioning ranges. The page content
describes each range supported by the device.
sd_read_cpr() is called from sd_revalidate_disk() and uses the block
layer functions disk_alloc_independent_access_ranges() and
disk_set_independent_access_ranges() to represent the set of actuators
of the device as independent access ranges.
The format of the Concurrent Positioning Ranges VPD page B9h is defined
in section 6.6.6 of SBC-5.
Signed-off-by: Damien Le Moal <redacted>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
---
drivers/scsi/sd.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/scsi/sd.h | 1 +
2 files changed, 82 insertions(+)
@@ -3088,6 +3088,86 @@ static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer)sdkp->security=1;}+staticinlinesector_tsd64_to_sectors(structscsi_disk*sdkp,u8*buf)+{+returnlogical_to_sectors(sdkp->device,get_unaligned_be64(buf));+}++/**+*sd_read_cpr-Queryconcurrentpositioningranges+*@sdkp:disktoquery+*/+staticvoidsd_read_cpr(structscsi_disk*sdkp)+{+structblk_independent_access_ranges*iars=NULL;+unsignedchar*buffer=NULL;+unsignedintnr_cpr=0;+inti,vpd_len,buf_len=SD_BUF_SIZE;+u8*desc;++/*+*Weneedtohavethecapacitysetfirstfortheblocklayertobe+*abletochecktheranges.+*/+if(sdkp->first_scan)+return;++if(!sdkp->capacity)+gotoout;++/*+*ConcurrentPositioningRangesVPD:therecanbeatmost256ranges,+*leadingtoamaximumpagesizeof64+256*32bytes.+*/+buf_len=64+256*32;+buffer=kmalloc(buf_len,GFP_KERNEL);+if(!buffer||scsi_get_vpd_page(sdkp->device,0xb9,buffer,buf_len))+gotoout;++/* We must have at least a 64B header and one 32B range descriptor */+vpd_len=get_unaligned_be16(&buffer[2])+3;+if(vpd_len>buf_len||vpd_len<64+32||(vpd_len&31)){+sd_printk(KERN_ERR,sdkp,+"Invalid Concurrent Positioning Ranges VPD page\n");+gotoout;+}++nr_cpr=(vpd_len-64)/32;+if(nr_cpr==1){+nr_cpr=0;+gotoout;+}++iars=disk_alloc_independent_access_ranges(sdkp->disk,nr_cpr);+if(!iars){+nr_cpr=0;+gotoout;+}++desc=&buffer[64];+for(i=0;i<nr_cpr;i++,desc+=32){+if(desc[0]!=i){+sd_printk(KERN_ERR,sdkp,+"Invalid Concurrent Positioning Range number\n");+nr_cpr=0;+break;+}++iars->ia_range[i].sector=sd64_to_sectors(sdkp,desc+8);+iars->ia_range[i].nr_sectors=sd64_to_sectors(sdkp,desc+16);+}++out:+disk_set_independent_access_ranges(sdkp->disk,iars);+if(nr_cpr&&sdkp->nr_actuators!=nr_cpr){+sd_printk(KERN_NOTICE,sdkp,+"%u concurrent positioning ranges\n",nr_cpr);+sdkp->nr_actuators=nr_cpr;+}++kfree(buffer);+}+/**Determinethedevice'spreferredI/Osizeforreadsandwrites*unlessthereportedvalueisunreasonablysmall,large,nota
@@ -3203,6 +3283,7 @@ static int sd_revalidate_disk(struct gendisk *disk)sd_read_app_tag_own(sdkp,buffer);sd_read_write_same(sdkp,buffer);sd_read_security(sdkp,buffer);+sd_read_cpr(sdkp);}/*
@@ -106,6 +106,7 @@ struct scsi_disk {u8protection_type;/* Data Integrity Field */u8provisioning_mode;u8zeroing_mode;+u8nr_actuators;/* Number of actuators */unsignedATO:1;/* state of disk ATO bit */unsignedcache_override:1;/* temp override of WCE,RCD */unsignedWCE:1;/* state of disk WCE bit */
From: Damien Le Moal <hidden> Date: 2021-10-27 02:22:31
Add support to discover if an ATA device supports the Concurrent
Positioning Ranges data log (address 0x47), indicating that the device
is capable of seeking to multiple different locations in parallel using
multiple actuators serving different LBA ranges.
Also add support to translate the concurrent positioning ranges log
into its equivalent Concurrent Positioning Ranges VPD page B9h in
libata-scsi.c.
The format of the Concurrent Positioning Ranges Log is defined in ACS-5
r9.
Signed-off-by: Damien Le Moal <redacted>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
---
drivers/ata/libata-core.c | 57 +++++++++++++++++++++++++++++++++++++--
drivers/ata/libata-scsi.c | 48 ++++++++++++++++++++++++++-------
include/linux/ata.h | 1 +
include/linux/libata.h | 15 +++++++++++
4 files changed, 110 insertions(+), 11 deletions(-)
@@ -1895,7 +1895,7 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)*/staticunsignedintata_scsiop_inq_00(structata_scsi_args*args,u8*rbuf){-intnum_pages;+inti,num_pages=0;staticconstu8pages[]={0x00,/* page 0x00, this page */0x80,/* page 0x80, unit serial no page */
From: Damien Le Moal <hidden> Date: 2021-10-27 02:22:38
Update the file Documentation/block/queue-sysfs.rst to add a description
of a device queue sysfs entries related to independent access ranges
(e.g. concurrent positioning ranges for multi-actuator hard-disks).
Signed-off-by: Damien Le Moal <redacted>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
---
Documentation/block/queue-sysfs.rst | 31 +++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
@@ -286,4 +286,35 @@ sequential zones of zoned block devices (devices with a zoned attributed that reports "host-managed" or "host-aware"). This value is always 0 for regular block devices.+independent_access_ranges (RO)+------------------------------++The presence of this sub-directory of the /sys/block/xxx/queue/ directory+indicates that the device is capable of executing requests targeting+different sector ranges in parallel. For instance, single LUN multi-actuator+hard-disks will have an independent_access_ranges directory if the device+correctly advertizes the sector ranges of its actuators.++The independent_access_ranges directory contains one directory per access+range, with each range described using the sector (RO) attribute file to+indicate the first sector of the range and the nr_sectors (RO) attribute file+to indicate the total number of sectors in the range starting from the first+sector of the range. For example, a dual-actuator hard-disk will have the+following independent_access_ranges entries.::++ $ tree /sys/block/<device>/queue/independent_access_ranges/+ /sys/block/<device>/queue/independent_access_ranges/+ |-- 0+| |-- nr_sectors+| `-- sector+ `-- 1+ |-- nr_sectors+ `-- sector++The sector and nr_sectors attributes use 512B sector unit, regardless of+the actual block size of the device. Independent access ranges do not+overlap and include all sectors within the device capacity. The access+ranges are numbered in increasing order of the range start sector,+that is, the sector attribute of range 0 always has the value 0.+ Jens Axboe <jens.axboe@oracle.com>, February 2009
From: Damien Le Moal <hidden> Date: 2021-10-27 02:22:38
Fix a typo (are -> as) in the introduction paragraph of
Documentation/block/queue-sysfs.rst.
Signed-off-by: Damien Le Moal <redacted>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
---
Documentation/block/queue-sysfs.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -4,7 +4,7 @@ Queue sysfs files This text file will detail the queue files that are located in the sysfs tree for each block device. Note that stacked devices typically do not export-any settings, since their queue merely functions are a remapping target.+any settings, since their queue merely functions as a remapping target. These files are the ones found in the /sys/block/xxx/queue/ directory. Files denoted with a RO postfix are readonly and the RW postfix means
On Wed, 27 Oct 2021 11:22:18 +0900, Damien Le Moal wrote:
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
[...]
Applied, thanks!
[1/5] block: Add independent access ranges support
commit: a2247f19ee1c5ad75ef095cdfb909a3244b88aa8
Best regards,
--
Jens Axboe
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
This series adds support to the scsi disk driver to retreive this
information and advertize it to user space through sysfs. libata is
also modified to handle ATA drives.
The first patch adds the block layer plumbing to expose concurrent
sector ranges of the device through sysfs as a sub-directory of the
device sysfs queue directory. Patch 2 and 3 add support to sd and
libata. Finally patch 4 documents the sysfs queue attributed changes.
Patch 5 fixes a typo in the document file (strictly speaking, not
related to this series).
This series does not attempt in any way to optimize accesses to
multi-actuator devices (e.g. block IO schedulers or filesystems). This
initial support only exposes the independent access ranges information
to user space through sysfs.
I've applied 1/9 for now, as that clearly belongs in the block tree.
Might be the cleanest if SCSI does a post tree that depends on
for-5.16/block. Or I can apply it all as they are reviewed. Let me
know.
--
Jens Axboe
From: Damien Le Moal <hidden> Date: 2021-10-27 02:46:29
On 2021/10/27 11:38, Jens Axboe wrote:
On 10/26/21 8:22 PM, Damien Le Moal wrote:
quoted
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
This series adds support to the scsi disk driver to retreive this
information and advertize it to user space through sysfs. libata is
also modified to handle ATA drives.
The first patch adds the block layer plumbing to expose concurrent
sector ranges of the device through sysfs as a sub-directory of the
device sysfs queue directory. Patch 2 and 3 add support to sd and
libata. Finally patch 4 documents the sysfs queue attributed changes.
Patch 5 fixes a typo in the document file (strictly speaking, not
related to this series).
This series does not attempt in any way to optimize accesses to
multi-actuator devices (e.g. block IO schedulers or filesystems). This
initial support only exposes the independent access ranges information
to user space through sysfs.
I've applied 1/9 for now, as that clearly belongs in the block tree.
Might be the cleanest if SCSI does a post tree that depends on
for-5.16/block. Or I can apply it all as they are reviewed. Let me
know.
Patch 4 & 5 are doc updates and I think they belong to the block tree too.
Patch 3 applies cleanly to libata for-5.16 branch as is, so you can take it, or
I can take it in libata tree too, whichever works for me.
As for patch 2, it applies cleanly to 5.16/scsi-queue so I guess you can take it
too, but I will defer this decision to Martin.
--
Damien Le Moal
Western Digital Research
From: Damien Le Moal <hidden> Date: 2021-10-27 02:49:11
On 2021/10/27 11:38, Jens Axboe wrote:
On 10/26/21 8:22 PM, Damien Le Moal wrote:
quoted
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
This series adds support to the scsi disk driver to retreive this
information and advertize it to user space through sysfs. libata is
also modified to handle ATA drives.
The first patch adds the block layer plumbing to expose concurrent
sector ranges of the device through sysfs as a sub-directory of the
device sysfs queue directory. Patch 2 and 3 add support to sd and
libata. Finally patch 4 documents the sysfs queue attributed changes.
Patch 5 fixes a typo in the document file (strictly speaking, not
related to this series).
This series does not attempt in any way to optimize accesses to
multi-actuator devices (e.g. block IO schedulers or filesystems). This
initial support only exposes the independent access ranges information
to user space through sysfs.
I've applied 1/9 for now, as that clearly belongs in the block tree.
Might be the cleanest if SCSI does a post tree that depends on
for-5.16/block. Or I can apply it all as they are reviewed. Let me
know.
Forgot: They are all reviewed, including Martin who sent a Reviewed-by for the
series, but not an Acked-by for patch 2. As for libata patch 3, obviously, this
is Acked-by me.
--
Damien Le Moal
Western Digital Research
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
This series adds support to the scsi disk driver to retreive this
information and advertize it to user space through sysfs. libata is
also modified to handle ATA drives.
The first patch adds the block layer plumbing to expose concurrent
sector ranges of the device through sysfs as a sub-directory of the
device sysfs queue directory. Patch 2 and 3 add support to sd and
libata. Finally patch 4 documents the sysfs queue attributed changes.
Patch 5 fixes a typo in the document file (strictly speaking, not
related to this series).
This series does not attempt in any way to optimize accesses to
multi-actuator devices (e.g. block IO schedulers or filesystems). This
initial support only exposes the independent access ranges information
to user space through sysfs.
I've applied 1/9 for now, as that clearly belongs in the block tree.
Might be the cleanest if SCSI does a post tree that depends on
for-5.16/block. Or I can apply it all as they are reviewed. Let me
know.
Forgot: They are all reviewed, including Martin who sent a Reviewed-by for the
series, but not an Acked-by for patch 2. As for libata patch 3, obviously, this
is Acked-by me.
Queued up 2-5 in the for-5.16/scsi-ma branch.
--
Jens Axboe
On Wed, 27 Oct 2021 11:22:18 +0900, Damien Le Moal wrote:
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
[...]
From: Damien Le Moal <hidden> Date: 2021-10-27 03:42:18
On 2021/10/27 12:03, Jens Axboe wrote:
On 10/26/21 8:49 PM, Damien Le Moal wrote:
quoted
On 2021/10/27 11:38, Jens Axboe wrote:
quoted
On 10/26/21 8:22 PM, Damien Le Moal wrote:
quoted
From: Damien Le Moal <redacted>
Single LUN multi-actuator hard-disks are cappable to seek and execute
multiple commands in parallel. This capability is exposed to the host
using the Concurrent Positioning Ranges VPD page (SCSI) and Log (ATA).
Each positioning range describes the contiguous set of LBAs that an
actuator serves.
This series adds support to the scsi disk driver to retreive this
information and advertize it to user space through sysfs. libata is
also modified to handle ATA drives.
The first patch adds the block layer plumbing to expose concurrent
sector ranges of the device through sysfs as a sub-directory of the
device sysfs queue directory. Patch 2 and 3 add support to sd and
libata. Finally patch 4 documents the sysfs queue attributed changes.
Patch 5 fixes a typo in the document file (strictly speaking, not
related to this series).
This series does not attempt in any way to optimize accesses to
multi-actuator devices (e.g. block IO schedulers or filesystems). This
initial support only exposes the independent access ranges information
to user space through sysfs.
I've applied 1/9 for now, as that clearly belongs in the block tree.
Might be the cleanest if SCSI does a post tree that depends on
for-5.16/block. Or I can apply it all as they are reviewed. Let me
know.
Forgot: They are all reviewed, including Martin who sent a Reviewed-by for the
series, but not an Acked-by for patch 2. As for libata patch 3, obviously, this
is Acked-by me.
Queued up 2-5 in the for-5.16/scsi-ma branch.
Thanks !
--
Damien Le Moal
Western Digital Research
Hi Damien,
On Wed, 27 Oct 2021, Damien Le Moal wrote:
Add support to discover if an ATA device supports the Concurrent
Positioning Ranges data log (address 0x47), indicating that the device
is capable of seeking to multiple different locations in parallel using
multiple actuators serving different LBA ranges.
Also add support to translate the concurrent positioning ranges log
into its equivalent Concurrent Positioning Ranges VPD page B9h in
libata-scsi.c.
The format of the Concurrent Positioning Ranges Log is defined in ACS-5
r9.
Signed-off-by: Damien Le Moal <redacted>
Thanks for your patch, which is now commit fe22e1c2f705676a ("libata:
support concurrent positioning ranges log") upstream.
During resume from s2ram on Renesas Salvator-XS, I now see more scary
messages than before:
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: qc timeout (cmd 0x2f)
+ata1.00: Read log page 0x00 failed, Emask 0x4
+ata1.00: ATA Identify Device Log not supported
+ata1.00: failed to set xfermode (err_mask=0x40)
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: ATA Identify Device Log not supported
+ata1.00: ATA Identify Device Log not supported
ata1.00: configured for UDMA/133
I guess this is expected?
The hard drive (old Maxtor 6L160M0 that received a third life as a test
bed for Renesas SATA regression testing) seems to still work fine.
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
From: Damien Le Moal <hidden> Date: 2021-11-02 11:42:13
On 2021/11/02 19:40, Geert Uytterhoeven wrote:
Hi Damien,
On Wed, 27 Oct 2021, Damien Le Moal wrote:
quoted
Add support to discover if an ATA device supports the Concurrent
Positioning Ranges data log (address 0x47), indicating that the device
is capable of seeking to multiple different locations in parallel using
multiple actuators serving different LBA ranges.
Also add support to translate the concurrent positioning ranges log
into its equivalent Concurrent Positioning Ranges VPD page B9h in
libata-scsi.c.
The format of the Concurrent Positioning Ranges Log is defined in ACS-5
r9.
Signed-off-by: Damien Le Moal <redacted>
Thanks for your patch, which is now commit fe22e1c2f705676a ("libata:
support concurrent positioning ranges log") upstream.
During resume from s2ram on Renesas Salvator-XS, I now see more scary
messages than before:
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: qc timeout (cmd 0x2f)
+ata1.00: Read log page 0x00 failed, Emask 0x4
+ata1.00: ATA Identify Device Log not supported
+ata1.00: failed to set xfermode (err_mask=0x40)
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: ATA Identify Device Log not supported
+ata1.00: ATA Identify Device Log not supported
ata1.00: configured for UDMA/133
I guess this is expected?
Nope, it is not. The problem is actually not the concurrent positioning log, or
any other log, being supported or not.
Notice the qc timeout ? On device scan after coming out of sleep, or even simply
doing a rmmod ahci+modprobe ahci, the read log commands issued during device
revalidate timeout fairly easily as they are issued while the drive is not
necessarilly fully restarted yet. These errors happen fairly easily due to the
command timeout setting in libata being too short, I think, for the "restart"
case. On a clean boot, they do not happen as longer timeouts are used in that case.
I identified this problem recently while testing stuff: I was doing rmmod of ata
modules and then modprobe of newly compiled modules for tests and noticed these
timeouts. Increasing the timeout values, they disappear. I am however still
scratching my head about the best way to address this. Still digging about this
to first make sure this is really about timeouts being set too short.
The hard drive (old Maxtor 6L160M0 that received a third life as a test
bed for Renesas SATA regression testing) seems to still work fine.
I have plenty of brand new drives in my box that show similar error patterns.
The drive is not at fault and libata recovers so the user may not notice the
error. I didn't notice for a while too...
Thanks!
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
Hi Damien,
On Tue, Nov 2, 2021 at 12:42 PM Damien Le Moal
[off-list ref] wrote:
On 2021/11/02 19:40, Geert Uytterhoeven wrote:
quoted
On Wed, 27 Oct 2021, Damien Le Moal wrote:
quoted
Add support to discover if an ATA device supports the Concurrent
Positioning Ranges data log (address 0x47), indicating that the device
is capable of seeking to multiple different locations in parallel using
multiple actuators serving different LBA ranges.
Also add support to translate the concurrent positioning ranges log
into its equivalent Concurrent Positioning Ranges VPD page B9h in
libata-scsi.c.
The format of the Concurrent Positioning Ranges Log is defined in ACS-5
r9.
Signed-off-by: Damien Le Moal <redacted>
Thanks for your patch, which is now commit fe22e1c2f705676a ("libata:
support concurrent positioning ranges log") upstream.
During resume from s2ram on Renesas Salvator-XS, I now see more scary
messages than before:
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: qc timeout (cmd 0x2f)
+ata1.00: Read log page 0x00 failed, Emask 0x4
+ata1.00: ATA Identify Device Log not supported
+ata1.00: failed to set xfermode (err_mask=0x40)
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: ATA Identify Device Log not supported
+ata1.00: ATA Identify Device Log not supported
ata1.00: configured for UDMA/133
I guess this is expected?
Nope, it is not. The problem is actually not the concurrent positioning log, or
any other log, being supported or not.
Notice the qc timeout ? On device scan after coming out of sleep, or even simply
doing a rmmod ahci+modprobe ahci, the read log commands issued during device
revalidate timeout fairly easily as they are issued while the drive is not
necessarilly fully restarted yet. These errors happen fairly easily due to the
command timeout setting in libata being too short, I think, for the "restart"
case. On a clean boot, they do not happen as longer timeouts are used in that case.
I identified this problem recently while testing stuff: I was doing rmmod of ata
modules and then modprobe of newly compiled modules for tests and noticed these
timeouts. Increasing the timeout values, they disappear. I am however still
scratching my head about the best way to address this. Still digging about this
to first make sure this is really about timeouts being set too short.
There's indeed something timing-related going on. Sometimes I get
during resume (s2idle or s2ram):
ata1.00: qc timeout (cmd 0x2f)
ata1.00: Read log page 0x00 failed, Emask 0x4
ata1.00: ATA Identify Device Log not supported
ata1.00: failed to set xfermode (err_mask=0x40)
ata1.00: limiting speed to UDMA/133:PIO3
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
ata1.00: NODEV after polling detection
ata1.00: revalidation failed (errno=-2)
ata1.00: disabled
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
sd 0:0:0:0: [sda] Start/Stop Unit failed: Result: hostbyte=0x04
driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Read Capacity(16) failed: Result: hostbyte=0x04
driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Sense not available.
sd 0:0:0:0: [sda] Read Capacity(10) failed: Result: hostbyte=0x04
driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Sense not available.
sd 0:0:0:0: [sda] 0 512-byte logical blocks: (0 B/0 B)
sda: detected capacity change from 320173056 to 0
after which the drive is no longer functional...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
From: Damien Le Moal <hidden> Date: 2021-11-04 06:20:35
On Tue, 2021-11-02 at 15:02 +0100, Geert Uytterhoeven wrote:
Hi Damien,
On Tue, Nov 2, 2021 at 12:42 PM Damien Le Moal
[off-list ref] wrote:
quoted
On 2021/11/02 19:40, Geert Uytterhoeven wrote:
quoted
On Wed, 27 Oct 2021, Damien Le Moal wrote:
quoted
Add support to discover if an ATA device supports the Concurrent
Positioning Ranges data log (address 0x47), indicating that the device
is capable of seeking to multiple different locations in parallel using
multiple actuators serving different LBA ranges.
Also add support to translate the concurrent positioning ranges log
into its equivalent Concurrent Positioning Ranges VPD page B9h in
libata-scsi.c.
The format of the Concurrent Positioning Ranges Log is defined in ACS-5
r9.
Signed-off-by: Damien Le Moal <redacted>
Thanks for your patch, which is now commit fe22e1c2f705676a ("libata:
support concurrent positioning ranges log") upstream.
During resume from s2ram on Renesas Salvator-XS, I now see more scary
messages than before:
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: qc timeout (cmd 0x2f)
+ata1.00: Read log page 0x00 failed, Emask 0x4
+ata1.00: ATA Identify Device Log not supported
+ata1.00: failed to set xfermode (err_mask=0x40)
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
+ata1.00: ATA Identify Device Log not supported
+ata1.00: ATA Identify Device Log not supported
ata1.00: configured for UDMA/133
I guess this is expected?
Nope, it is not. The problem is actually not the concurrent positioning log, or
any other log, being supported or not.
Notice the qc timeout ? On device scan after coming out of sleep, or even simply
doing a rmmod ahci+modprobe ahci, the read log commands issued during device
revalidate timeout fairly easily as they are issued while the drive is not
necessarilly fully restarted yet. These errors happen fairly easily due to the
command timeout setting in libata being too short, I think, for the "restart"
case. On a clean boot, they do not happen as longer timeouts are used in that case.
I identified this problem recently while testing stuff: I was doing rmmod of ata
modules and then modprobe of newly compiled modules for tests and noticed these
timeouts. Increasing the timeout values, they disappear. I am however still
scratching my head about the best way to address this. Still digging about this
to first make sure this is really about timeouts being set too short.
There's indeed something timing-related going on. Sometimes I get
during resume (s2idle or s2ram):
ata1.00: qc timeout (cmd 0x2f)
ata1.00: Read log page 0x00 failed, Emask 0x4
ata1.00: ATA Identify Device Log not supported
ata1.00: failed to set xfermode (err_mask=0x40)
ata1.00: limiting speed to UDMA/133:PIO3
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
ata1.00: NODEV after polling detection
ata1.00: revalidation failed (errno=-2)
ata1.00: disabled
ata1: link resume succeeded after 1 retries
ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300)
sd 0:0:0:0: [sda] Start/Stop Unit failed: Result: hostbyte=0x04
driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Read Capacity(16) failed: Result: hostbyte=0x04
driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Sense not available.
sd 0:0:0:0: [sda] Read Capacity(10) failed: Result: hostbyte=0x04
driverbyte=DRIVER_OK
sd 0:0:0:0: [sda] Sense not available.
sd 0:0:0:0: [sda] 0 512-byte logical blocks: (0 B/0 B)
sda: detected capacity change from 320173056 to 0
after which the drive is no longer functional...
Geert,
Could you try with the following patch added to see if the problem goes away ?
@@ -93,6 +93,12 @@ static const unsigned long ata_eh_identify_timeouts[] = {ULONG_MAX,};+staticconstunsignedlongata_eh_revalidate_timeouts[]={+15000,/* Some drives are slow to read log pages when waking-up */+15000,/* combined time till here is enough even for media access */+ULONG_MAX,+};+staticconstunsignedlongata_eh_flush_timeouts[]={15000,/* be generous with flush */15000,/* ditto */
@@ -394,7 +394,7 @@ enum {/* This should match the actual table size of*ata_eh_cmd_timeout_tableinlibata-eh.c.*/-ATA_EH_CMD_TIMEOUT_TABLE_SIZE=6,+ATA_EH_CMD_TIMEOUT_TABLE_SIZE=4,/* Horkage types. May be set by libata or controller on drives(somehorkagemaybedrive/controllerpairdependent*/
On my test box, I can reliably generate the same qc timeout errors you are
seeing by doing:
rmmod sd_mod ahci libahci libata
modprobe ahci
The first command will hard reset the drives (causing them to "reboot").
When the second command starts, revalidate is executed with the drives slow to
respond to read log commands. The patch adds an auto timeout for read log
commands, to set the timeout to 15s instead of the default 5s. With that, all
timeout errors disappear. Note that these timeout numbers are totally
arbitrary...
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds