Blame view

fs/udf/file.c 6.17 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * file.c
   *
   * PURPOSE
   *  File handling routines for the OSTA-UDF(tm) filesystem.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   * COPYRIGHT
   *  This file is distributed under the terms of the GNU General Public
   *  License (GPL). Copies of the GPL can be obtained from:
   *    ftp://prep.ai.mit.edu/pub/gnu/GPL
   *  Each contributing author retains all rights to their own work.
   *
   *  (C) 1998-1999 Dave Boynton
   *  (C) 1998-2004 Ben Fennema
   *  (C) 1999-2000 Stelias Computing Inc
   *
   * HISTORY
   *
   *  10/02/98 dgb  Attempt to integrate into udf.o
   *  10/07/98      Switched to using generic_readpage, etc., like isofs
   *                And it works!
   *  12/06/98 blf  Added udf_file_read. uses generic_file_read for all cases but
   *                ICBTAG_FLAG_AD_IN_ICB.
   *  04/06/99      64 bit file handling on 32 bit systems taken from ext2 file.c
   *  05/12/99      Preliminary file write support
   */
  
  #include "udfdecl.h"
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  #include <asm/uaccess.h>
  #include <linux/kernel.h>
28de7948a   Cyrill Gorcunov   UDF: coding style...
32
  #include <linux/string.h> /* memset */
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
33
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <linux/errno.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include <linux/pagemap.h>
  #include <linux/buffer_head.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
37
  #include <linux/aio.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
  
  #include "udf_i.h"
  #include "udf_sb.h"
cb00ea352   Cyrill Gorcunov   UDF: coding style...
41
  static int udf_adinicb_readpage(struct file *file, struct page *page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  {
  	struct inode *inode = page->mapping->host;
  	char *kaddr;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
45
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

cd7619d6b   Matt Mackall   [PATCH] Extermina...
47
  	BUG_ON(!PageLocked(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  
  	kaddr = kmap(page);
  	memset(kaddr, 0, PAGE_CACHE_SIZE);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
51
  	memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  	flush_dcache_page(page);
  	SetPageUptodate(page);
  	kunmap(page);
  	unlock_page(page);
28de7948a   Cyrill Gorcunov   UDF: coding style...
56

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  	return 0;
  }
4b11111ab   Marcin Slusarz   udf: fix coding s...
59
60
  static int udf_adinicb_writepage(struct page *page,
  				 struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
  {
  	struct inode *inode = page->mapping->host;
  	char *kaddr;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
64
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65

cd7619d6b   Matt Mackall   [PATCH] Extermina...
66
  	BUG_ON(!PageLocked(page));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  
  	kaddr = kmap(page);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
69
  	memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
  	mark_inode_dirty(inode);
  	SetPageUptodate(page);
  	kunmap(page);
  	unlock_page(page);
28de7948a   Cyrill Gorcunov   UDF: coding style...
74

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  	return 0;
  }
be021ee41   Nick Piggin   udf: convert to n...
77
78
79
80
  static int udf_adinicb_write_end(struct file *file,
  			struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *page, void *fsdata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  {
be021ee41   Nick Piggin   udf: convert to n...
82
83
84
  	struct inode *inode = mapping->host;
  	unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
  	char *kaddr;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
85
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

be021ee41   Nick Piggin   udf: convert to n...
87
  	kaddr = kmap_atomic(page, KM_USER0);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
88
  	memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
be021ee41   Nick Piggin   udf: convert to n...
89
90
91
92
  		kaddr + offset, copied);
  	kunmap_atomic(kaddr, KM_USER0);
  
  	return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
94
  const struct address_space_operations udf_adinicb_aops = {
28de7948a   Cyrill Gorcunov   UDF: coding style...
95
96
  	.readpage	= udf_adinicb_readpage,
  	.writepage	= udf_adinicb_writepage,
be021ee41   Nick Piggin   udf: convert to n...
97
98
  	.write_begin = simple_write_begin,
  	.write_end = udf_adinicb_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
  };
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
100
  static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
101
  				  unsigned long nr_segs, loff_t ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  {
  	ssize_t retval;
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
104
  	struct file *file = iocb->ki_filp;
5096e933a   Josef Sipek   [PATCH] struct pa...
105
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  	int err, pos;
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
107
  	size_t count = iocb->ki_left;
48d6d8ff7   Marcin Slusarz   udf: cache struct...
108
  	struct udf_inode_info *iinfo = UDF_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109

8754a3f71   Jan Kara   udf: Protect udf_...
110
  	down_write(&iinfo->i_data_sem);
48d6d8ff7   Marcin Slusarz   udf: cache struct...
111
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
  		if (file->f_flags & O_APPEND)
  			pos = inode->i_size;
  		else
543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
115
  			pos = ppos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

4b11111ab   Marcin Slusarz   udf: fix coding s...
117
118
  		if (inode->i_sb->s_blocksize <
  				(udf_file_entry_alloc_offset(inode) +
28de7948a   Cyrill Gorcunov   UDF: coding style...
119
  						pos + count)) {
7e49b6f24   Jan Kara   udf: Convert UDF ...
120
121
  			err = udf_expand_file_adinicb(inode);
  			if (err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
  				udf_debug("udf_expand_adinicb: err=%d
  ", err);
  				return err;
  			}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
126
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  			if (pos + count > inode->i_size)
48d6d8ff7   Marcin Slusarz   udf: cache struct...
128
  				iinfo->i_lenAlloc = pos + count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  			else
48d6d8ff7   Marcin Slusarz   udf: cache struct...
130
  				iinfo->i_lenAlloc = inode->i_size;
d2eb8c359   Jan Kara   udf: Fix deadlock...
131
  			up_write(&iinfo->i_data_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  		}
d2eb8c359   Jan Kara   udf: Fix deadlock...
133
134
  	} else
  		up_write(&iinfo->i_data_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135

543ade1fc   Badari Pulavarty   [PATCH] Streamlin...
136
  	retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
  	if (retval > 0)
  		mark_inode_dirty(inode);
28de7948a   Cyrill Gorcunov   UDF: coding style...
139

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  	return retval;
  }
2f07a88b3   John Kacur   udf: BKL ioctl pu...
142
  long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  {
2f07a88b3   John Kacur   udf: BKL ioctl pu...
144
  	struct inode *inode = filp->f_dentry->d_inode;
28de7948a   Cyrill Gorcunov   UDF: coding style...
145
  	long old_block, new_block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	int result = -EINVAL;
6f2861097   Al Viro   switch udf_ioctl(...
147
  	if (inode_permission(inode, MAY_READ) != 0) {
2f07a88b3   John Kacur   udf: BKL ioctl pu...
148
149
150
151
  		udf_debug("no permission to access inode %lu
  ", inode->i_ino);
  		result = -EPERM;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
153
  	if (!arg) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
  		udf_debug("invalid argument to udf_ioctl
  ");
2f07a88b3   John Kacur   udf: BKL ioctl pu...
156
157
  		result = -EINVAL;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
159
160
  	switch (cmd) {
  	case UDF_GETVOLIDENT:
4b11111ab   Marcin Slusarz   udf: fix coding s...
161
162
  		if (copy_to_user((char __user *)arg,
  				 UDF_SB(inode->i_sb)->s_volume_ident, 32))
2f07a88b3   John Kacur   udf: BKL ioctl pu...
163
  			result = -EFAULT;
4b11111ab   Marcin Slusarz   udf: fix coding s...
164
  		else
2f07a88b3   John Kacur   udf: BKL ioctl pu...
165
166
  			result = 0;
  		goto out;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
167
  	case UDF_RELOCATE_BLOCKS:
2f07a88b3   John Kacur   udf: BKL ioctl pu...
168
169
170
171
172
173
174
175
  		if (!capable(CAP_SYS_ADMIN)) {
  			result = -EACCES;
  			goto out;
  		}
  		if (get_user(old_block, (long __user *)arg)) {
  			result = -EFAULT;
  			goto out;
  		}
4b11111ab   Marcin Slusarz   udf: fix coding s...
176
177
178
  		result = udf_relocate_blocks(inode->i_sb,
  						old_block, &new_block);
  		if (result == 0)
28de7948a   Cyrill Gorcunov   UDF: coding style...
179
  			result = put_user(new_block, (long __user *)arg);
2f07a88b3   John Kacur   udf: BKL ioctl pu...
180
  		goto out;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
181
  	case UDF_GETEASIZE:
c0b344385   Marcin Slusarz   udf: remove UDF_I...
182
  		result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
2f07a88b3   John Kacur   udf: BKL ioctl pu...
183
  		goto out;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
184
  	case UDF_GETEABLOCK:
c0b344385   Marcin Slusarz   udf: remove UDF_I...
185
186
187
  		result = copy_to_user((char __user *)arg,
  				      UDF_I(inode)->i_ext.i_data,
  				      UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
2f07a88b3   John Kacur   udf: BKL ioctl pu...
188
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  	}
2f07a88b3   John Kacur   udf: BKL ioctl pu...
190
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  	return result;
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
193
  static int udf_release_file(struct inode *inode, struct file *filp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
195
  	if (filp->f_mode & FMODE_WRITE) {
cbc8cc335   Jan Kara   udf: Fix possible...
196
  		mutex_lock(&inode->i_mutex);
4d0fb621d   Alessio Igor Bogani   udf: Replace bkl ...
197
  		down_write(&UDF_I(inode)->i_data_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  		udf_discard_prealloc(inode);
2c948b3f8   Jan Kara   udf: Avoid IO in ...
199
  		udf_truncate_tail_extent(inode);
4d0fb621d   Alessio Igor Bogani   udf: Replace bkl ...
200
  		up_write(&UDF_I(inode)->i_data_sem);
cbc8cc335   Jan Kara   udf: Fix possible...
201
  		mutex_unlock(&inode->i_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
  	}
  	return 0;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
205
  const struct file_operations udf_file_operations = {
28de7948a   Cyrill Gorcunov   UDF: coding style...
206
207
  	.read			= do_sync_read,
  	.aio_read		= generic_file_aio_read,
2f07a88b3   John Kacur   udf: BKL ioctl pu...
208
  	.unlocked_ioctl		= udf_ioctl,
363504628   Jan Kara   udf: Remove dead ...
209
  	.open			= generic_file_open,
28de7948a   Cyrill Gorcunov   UDF: coding style...
210
211
212
213
  	.mmap			= generic_file_mmap,
  	.write			= do_sync_write,
  	.aio_write		= udf_file_aio_write,
  	.release		= udf_release_file,
1b061d924   Christoph Hellwig   rename the generi...
214
  	.fsync			= generic_file_fsync,
28de7948a   Cyrill Gorcunov   UDF: coding style...
215
  	.splice_read		= generic_file_splice_read,
5c89468c1   Christoph Hellwig   udf: add llseek m...
216
  	.llseek			= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  };
d39aae9ec   Christoph Hellwig   add missing setat...
218
219
220
221
222
223
224
225
  static int udf_setattr(struct dentry *dentry, struct iattr *attr)
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
  
  	error = inode_change_ok(inode, attr);
  	if (error)
  		return error;
1025774ce   Christoph Hellwig   remove inode_setattr
226
227
228
  
  	if ((attr->ia_valid & ATTR_SIZE) &&
  	    attr->ia_size != i_size_read(inode)) {
7e49b6f24   Jan Kara   udf: Convert UDF ...
229
  		error = udf_setsize(inode, attr->ia_size);
1025774ce   Christoph Hellwig   remove inode_setattr
230
231
232
233
234
235
236
  		if (error)
  			return error;
  	}
  
  	setattr_copy(inode, attr);
  	mark_inode_dirty(inode);
  	return 0;
d39aae9ec   Christoph Hellwig   add missing setat...
237
  }
c5ef1c42c   Arjan van de Ven   [PATCH] mark stru...
238
  const struct inode_operations udf_file_inode_operations = {
d39aae9ec   Christoph Hellwig   add missing setat...
239
  	.setattr		= udf_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  };