linux/arch/ia64/kernel
Arnd Bergmann 6038f373a3 llseek: automatically add .llseek fop
All file_operations should get a .llseek operation so we can make
nonseekable_open the default for future file operations without a
.llseek pointer.

The three cases that we can automatically detect are no_llseek, seq_lseek
and default_llseek. For cases where we can we can automatically prove that
the file offset is always ignored, we use noop_llseek, which maintains
the current behavior of not returning an error from a seek.

New drivers should normally not use noop_llseek but instead use no_llseek
and call nonseekable_open at open time.  Existing drivers can be converted
to do the same when the maintainer knows for certain that no user code
relies on calling seek on the device file.

The generated code is often incorrectly indented and right now contains
comments that clarify for each added line why a specific variant was
chosen. In the version that gets submitted upstream, the comments will
be gone and I will manually fix the indentation, because there does not
seem to be a way to do that using coccinelle.

Some amount of new code is currently sitting in linux-next that should get
the same modifications, which I will do at the end of the merge window.

Many thanks to Julia Lawall for helping me learn to write a semantic
patch that does all this.

===== begin semantic patch =====
// This adds an llseek= method to all file operations,
// as a preparation for making no_llseek the default.
//
// The rules are
// - use no_llseek explicitly if we do nonseekable_open
// - use seq_lseek for sequential files
// - use default_llseek if we know we access f_pos
// - use noop_llseek if we know we don't access f_pos,
//   but we still want to allow users to call lseek
//
@ open1 exists @
identifier nested_open;
@@
nested_open(...)
{
<+...
nonseekable_open(...)
...+>
}

@ open exists@
identifier open_f;
identifier i, f;
identifier open1.nested_open;
@@
int open_f(struct inode *i, struct file *f)
{
<+...
(
nonseekable_open(...)
|
nested_open(...)
)
...+>
}

@ read disable optional_qualifier exists @
identifier read_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
expression E;
identifier func;
@@
ssize_t read_f(struct file *f, char *p, size_t s, loff_t *off)
{
<+...
(
   *off = E
|
   *off += E
|
   func(..., off, ...)
|
   E = *off
)
...+>
}

@ read_no_fpos disable optional_qualifier exists @
identifier read_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
@@
ssize_t read_f(struct file *f, char *p, size_t s, loff_t *off)
{
... when != off
}

@ write @
identifier write_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
expression E;
identifier func;
@@
ssize_t write_f(struct file *f, const char *p, size_t s, loff_t *off)
{
<+...
(
  *off = E
|
  *off += E
|
  func(..., off, ...)
|
  E = *off
)
...+>
}

@ write_no_fpos @
identifier write_f;
identifier f, p, s, off;
type ssize_t, size_t, loff_t;
@@
ssize_t write_f(struct file *f, const char *p, size_t s, loff_t *off)
{
... when != off
}

@ fops0 @
identifier fops;
@@
struct file_operations fops = {
 ...
};

@ has_llseek depends on fops0 @
identifier fops0.fops;
identifier llseek_f;
@@
struct file_operations fops = {
...
 .llseek = llseek_f,
...
};

@ has_read depends on fops0 @
identifier fops0.fops;
identifier read_f;
@@
struct file_operations fops = {
...
 .read = read_f,
...
};

@ has_write depends on fops0 @
identifier fops0.fops;
identifier write_f;
@@
struct file_operations fops = {
...
 .write = write_f,
...
};

@ has_open depends on fops0 @
identifier fops0.fops;
identifier open_f;
@@
struct file_operations fops = {
...
 .open = open_f,
...
};

// use no_llseek if we call nonseekable_open
////////////////////////////////////////////
@ nonseekable1 depends on !has_llseek && has_open @
identifier fops0.fops;
identifier nso ~= "nonseekable_open";
@@
struct file_operations fops = {
...  .open = nso, ...
+.llseek = no_llseek, /* nonseekable */
};

@ nonseekable2 depends on !has_llseek @
identifier fops0.fops;
identifier open.open_f;
@@
struct file_operations fops = {
...  .open = open_f, ...
+.llseek = no_llseek, /* open uses nonseekable */
};

// use seq_lseek for sequential files
/////////////////////////////////////
@ seq depends on !has_llseek @
identifier fops0.fops;
identifier sr ~= "seq_read";
@@
struct file_operations fops = {
...  .read = sr, ...
+.llseek = seq_lseek, /* we have seq_read */
};

// use default_llseek if there is a readdir
///////////////////////////////////////////
@ fops1 depends on !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier readdir_e;
@@
// any other fop is used that changes pos
struct file_operations fops = {
... .readdir = readdir_e, ...
+.llseek = default_llseek, /* readdir is present */
};

// use default_llseek if at least one of read/write touches f_pos
/////////////////////////////////////////////////////////////////
@ fops2 depends on !fops1 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier read.read_f;
@@
// read fops use offset
struct file_operations fops = {
... .read = read_f, ...
+.llseek = default_llseek, /* read accesses f_pos */
};

@ fops3 depends on !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier write.write_f;
@@
// write fops use offset
struct file_operations fops = {
... .write = write_f, ...
+	.llseek = default_llseek, /* write accesses f_pos */
};

// Use noop_llseek if neither read nor write accesses f_pos
///////////////////////////////////////////////////////////

@ fops4 depends on !fops1 && !fops2 && !fops3 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier read_no_fpos.read_f;
identifier write_no_fpos.write_f;
@@
// write fops use offset
struct file_operations fops = {
...
 .write = write_f,
 .read = read_f,
...
+.llseek = noop_llseek, /* read and write both use no f_pos */
};

@ depends on has_write && !has_read && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier write_no_fpos.write_f;
@@
struct file_operations fops = {
... .write = write_f, ...
+.llseek = noop_llseek, /* write uses no f_pos */
};

@ depends on has_read && !has_write && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
identifier read_no_fpos.read_f;
@@
struct file_operations fops = {
... .read = read_f, ...
+.llseek = noop_llseek, /* read uses no f_pos */
};

@ depends on !has_read && !has_write && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
identifier fops0.fops;
@@
struct file_operations fops = {
...
+.llseek = noop_llseek, /* no read or write fn */
};
===== End semantic patch =====

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Julia Lawall <julia@diku.dk>
Cc: Christoph Hellwig <hch@infradead.org>
2010-10-15 15:53:27 +02:00
..
cpufreq [IA64] Use set_cpus_allowed_ptr 2010-05-18 14:45:53 -07:00
.gitignore [IA64] Cleanup generated file not ignored by .gitignore 2008-08-04 11:06:16 -07:00
acpi-ext.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
acpi.c x86, acpi/irq: Introduce apci_isa_irq_to_gsi 2010-05-04 13:34:23 -07:00
asm-offsets.c ia64/pv_ops/xen: paravirtualize read/write ar.itc and ar.itm 2009-03-26 10:50:32 -07:00
audit.c [IA64] Remove COMPAT_IA32 support 2010-02-08 10:42:17 -08:00
brl_emu.c
crash_dump.c kdump: make elfcorehdr_addr independent of CONFIG_PROC_VMCORE 2008-10-20 08:52:39 -07:00
crash.c sysctl: Drop & in front of every proc_handler. 2009-11-18 08:37:40 -08:00
cyclone.c clocksource: pass clocksource to read() callback 2009-04-21 13:41:47 -07:00
dma-mapping.c [IA64] Fix warning in dma-mapping.c 2009-09-02 09:12:21 -07:00
efi_stub.S
efi.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
elfcore.c elf coredump: add extended numbering support 2010-03-06 11:26:46 -08:00
entry.h
entry.S [IA64] Add latest crop of syscalls 2010-08-13 20:55:51 -07:00
err_inject.c sysdev: Pass the attribute to the low level sysdev show/store function 2008-07-21 21:55:02 -07:00
esi_stub.S
esi.c tree-wide: fix assorted typos all over the place 2009-12-04 15:39:55 +01:00
fsys.S ia64/pv_ops: paravirtualize mov = ar.itc. 2009-03-26 10:50:22 -07:00
fsyscall_gtod_data.h [IA64] generalize attribute of fsyscall_gtod_data 2008-02-04 15:36:36 -08:00
ftrace.c ftrace, ia64: IA64 dynamic ftrace support 2009-01-14 12:11:31 +01:00
gate-data.S Rename .data.gate to .data..gate. 2010-03-03 11:25:59 +01:00
gate.lds.S Rename .data..patch.XXX to .data..patch.XXX. 2010-03-03 11:25:59 +01:00
gate.S Rename .data..patch.XXX to .data..patch.XXX. 2010-03-03 11:25:59 +01:00
head.S percpu: make percpu symbols in ia64 unique 2009-10-29 22:34:14 +09:00
ia64_ksyms.c percpu: remove per_cpu__ prefix. 2009-10-29 22:34:15 +09:00
init_task.c Rename .data.init_task to .data..init_task. 2010-03-03 11:25:58 +01:00
iosapic.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
irq_ia64.c [IA64] use __ratelimit 2010-05-18 14:45:54 -07:00
irq_lsapic.c [IA64] remove obsolete hw_interrupt_type 2009-06-15 14:35:10 -07:00
irq.c genirq: Convert irq_desc.lock to raw_spinlock 2009-12-14 23:55:33 +01:00
ivt.S Merge branch 'for-35' of git://repo.or.cz/linux-kbuild 2010-06-01 08:55:52 -07:00
jprobes.S [IA64] Move include/asm-ia64 to arch/ia64/include/asm 2008-08-01 10:21:21 -07:00
kprobes.c kprobes: Disable booster when CONFIG_PREEMPT=y 2010-02-04 09:36:18 +01:00
machine_kexec.c [IA64] kexec: Unregister MCA handler before kexec 2009-09-14 16:18:17 -07:00
machvec.c x86, ia64: convert to use generic dma_map_ops struct 2009-01-06 14:06:57 +01:00
Makefile elf coredump: replace ELF_CORE_EXTRA_* macros by functions 2010-03-06 11:26:45 -08:00
Makefile.gate Rename .data.gate to .data..gate. 2010-03-03 11:25:59 +01:00
mca_asm.S percpu: make percpu symbols in ia64 unique 2009-10-29 22:34:14 +09:00
mca_drv_asm.S [IA64] mca style cleanup 2008-02-04 15:42:06 -08:00
mca_drv.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
mca_drv.h [IA64] mca style cleanup 2008-02-04 15:42:06 -08:00
mca.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
minstate.h Rename .data..patch.XXX to .data..patch.XXX. 2010-03-03 11:25:59 +01:00
module.c [IA64] Convert ia64 to use int-ll64.h 2009-06-17 09:33:49 -07:00
msi_ia64.c PCI: MSI: Restore read_msi_msg_desc(); add get_cached_msi_msg_desc() 2010-07-30 09:41:39 -07:00
nr-irqs.c ia64/pv_ops/xen: define the nubmer of irqs which xen needs. 2008-10-17 10:06:59 -07:00
numa.c [IA64] Minimize per_cpu reservations. 2008-04-08 13:51:35 -07:00
pal.S
palinfo.c [IA64] Convert ia64 to use int-ll64.h 2009-06-17 09:33:49 -07:00
paravirt_inst.h ia64/pv_ops: paravirtualized instruction checker. 2008-10-17 10:12:54 -07:00
paravirt_patch.c ia64/pv_op/binarypatch: add helper functions to support binary patching for paravirt_ops. 2009-03-26 11:02:31 -07:00
paravirt_patchlist.c [IA64] Fix build error in paravirt_patchlist.c 2009-06-17 09:04:40 -07:00
paravirt_patchlist.h ia64/pv_ops: gate page paravirtualization. 2009-03-26 10:51:02 -07:00
paravirt.c ia64: remove some warnings. 2009-03-27 11:11:04 -07:00
paravirtentry.S Rename .data.read_mostly to .data..read_mostly. 2010-03-03 11:26:00 +01:00
patch.c ia64: remove some warnings. 2009-03-27 11:11:04 -07:00
pci-dma.c Bug Fix arch/ia64/kernel/pci-dma.c: fix recursive dma_supported() call in iommu_dma_supported() 2009-08-11 14:52:10 -07:00
pci-swiotlb.c ia64: remove unnecessary sync_single_range_* in swiotlb_dma_ops 2010-05-27 09:12:52 -07:00
perfmon_default_smpl.c [IA64] remove remaining __FUNCTION__ occurrences 2008-03-06 09:19:27 -08:00
perfmon_generic.h
perfmon_itanium.h
perfmon_mckinley.h
perfmon_montecito.h
perfmon.c ia64: perfmon: add d_dname method 2010-08-11 00:28:21 -04:00
process.c Make do_execve() take a const filename pointer 2010-08-17 18:07:43 -07:00
ptrace.c ia64: ptrace_attach_sync_user_rbs: avoid "task->signal != NULL" checks 2010-05-27 09:12:46 -07:00
relocate_kernel.S percpu: make percpu symbols in ia64 unique 2009-10-29 22:34:14 +09:00
sal.c [IA64] Update check_sal_cache_flush to use platform_send_ipi() 2008-06-11 16:40:33 -07:00
salinfo.c llseek: automatically add .llseek fop 2010-10-15 15:53:27 +02:00
setup.c dma-mapping: unify dma_get_cache_alignment implementations 2010-08-11 08:59:21 -07:00
sigframe.h
signal.c [IA64] Remove COMPAT_IA32 support 2010-02-08 10:42:17 -08:00
smp.c ia64: convert last user of smp_call_function_mask 2009-09-24 09:34:40 +09:30
smpboot.c x86, ia64, smp: use workqueues unconditionally during do_boot_cpu() 2010-08-09 20:45:06 -07:00
sys_ia64.c Get rid of open-coding in ia64_brk() 2009-12-11 06:44:58 -05:00
time.c timkeeping: Fix update_vsyscall to provide wall_to_monotonic offset 2010-07-27 12:40:54 +02:00
topology.c [IA64] Use set_cpus_allowed_ptr 2010-05-18 14:45:53 -07:00
traps.c [IA64] Remove COMPAT_IA32 support 2010-02-08 10:42:17 -08:00
unaligned.c [IA64] use __ratelimit 2010-05-18 14:45:54 -07:00
uncached.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
unwind_decoder.c
unwind_i.h
unwind.c [IA64] Do not go beyond ARRAY_SIZE of unw.hash 2009-02-25 11:48:04 -08:00
vmlinux.lds.S [IA64] beautify vmlinux.lds.h 2010-06-21 15:08:44 -07:00