Blame view

fs/exofs/inode.c 36.4 KB
e80627191   Boaz Harrosh   exofs: file and f...
1
2
  /*
   * Copyright (C) 2005, 2006
27d2e1491   Boaz Harrosh   exofs: Remove IBM...
3
   * Avishay Traeger (avishay@gmail.com)
e80627191   Boaz Harrosh   exofs: file and f...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
   * Copyright (C) 2008, 2009
   * Boaz Harrosh <bharrosh@panasas.com>
   *
   * Copyrights for code taken from ext2:
   *     Copyright (C) 1992, 1993, 1994, 1995
   *     Remy Card (card@masi.ibp.fr)
   *     Laboratoire MASI - Institut Blaise Pascal
   *     Universite Pierre et Marie Curie (Paris VI)
   *     from
   *     linux/fs/minix/inode.c
   *     Copyright (C) 1991, 1992  Linus Torvalds
   *
   * This file is part of exofs.
   *
   * exofs is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation.  Since it is based on ext2, and the only
   * valid version of GPL for the Linux kernel is version 2, the only valid
   * version of GPL for exofs is version 2.
   *
   * exofs is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with exofs; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
33
  #include <linux/slab.h>
e80627191   Boaz Harrosh   exofs: file and f...
34
35
  
  #include "exofs.h"
fe33cc1ee   Boaz Harrosh   exofs: dbg-print ...
36
  #define EXOFS_DBGMSG2(M...) do {} while (0)
5a51c0c7e   Boaz Harrosh   ore/exofs: Define...
37
  enum {MAX_PAGES_KMALLOC = PAGE_SIZE / sizeof(struct page *), };
06886a5a3   Boaz Harrosh   exofs: Move all o...
38

8ff660ab8   Boaz Harrosh   exofs: Rename rai...
39
  unsigned exofs_max_io_pages(struct ore_layout *layout,
66cd6cad4   bharrosh@panasas.com   exofs: Override r...
40
41
42
43
44
  			    unsigned expected_pages)
  {
  	unsigned pages = min_t(unsigned, expected_pages, MAX_PAGES_KMALLOC);
  
  	/* TODO: easily support bio chaining */
5a51c0c7e   Boaz Harrosh   ore/exofs: Define...
45
  	pages =  min_t(unsigned, pages, layout->max_io_length / PAGE_SIZE);
66cd6cad4   bharrosh@panasas.com   exofs: Override r...
46
47
  	return pages;
  }
beaec07ba   Boaz Harrosh   exofs: address_sp...
48
49
  struct page_collect {
  	struct exofs_sb_info *sbi;
beaec07ba   Boaz Harrosh   exofs: address_sp...
50
51
  	struct inode *inode;
  	unsigned expected_pages;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
52
  	struct ore_io_state *ios;
beaec07ba   Boaz Harrosh   exofs: address_sp...
53

86093aaff   Boaz Harrosh   exofs: convert io...
54
55
  	struct page **pages;
  	unsigned alloc_pages;
beaec07ba   Boaz Harrosh   exofs: address_sp...
56
57
58
  	unsigned nr_pages;
  	unsigned long length;
  	loff_t pg_first; /* keep 64bit also in 32-arches */
f17b1f9f1   Boaz Harrosh   exofs: Fix double...
59
60
61
  	bool read_4_write; /* This means two things: that the read is sync
  			    * And the pages should not be unlocked.
  			    */
dd2966199   Boaz Harrosh   exofs: Support fo...
62
  	struct page *that_locked_page;
beaec07ba   Boaz Harrosh   exofs: address_sp...
63
64
65
  };
  
  static void _pcol_init(struct page_collect *pcol, unsigned expected_pages,
06886a5a3   Boaz Harrosh   exofs: Move all o...
66
  		       struct inode *inode)
beaec07ba   Boaz Harrosh   exofs: address_sp...
67
68
  {
  	struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
beaec07ba   Boaz Harrosh   exofs: address_sp...
69
70
  
  	pcol->sbi = sbi;
beaec07ba   Boaz Harrosh   exofs: address_sp...
71
72
  	pcol->inode = inode;
  	pcol->expected_pages = expected_pages;
06886a5a3   Boaz Harrosh   exofs: Move all o...
73
  	pcol->ios = NULL;
86093aaff   Boaz Harrosh   exofs: convert io...
74
75
  	pcol->pages = NULL;
  	pcol->alloc_pages = 0;
beaec07ba   Boaz Harrosh   exofs: address_sp...
76
77
78
  	pcol->nr_pages = 0;
  	pcol->length = 0;
  	pcol->pg_first = -1;
f17b1f9f1   Boaz Harrosh   exofs: Fix double...
79
  	pcol->read_4_write = false;
dd2966199   Boaz Harrosh   exofs: Support fo...
80
  	pcol->that_locked_page = NULL;
beaec07ba   Boaz Harrosh   exofs: address_sp...
81
82
83
84
85
  }
  
  static void _pcol_reset(struct page_collect *pcol)
  {
  	pcol->expected_pages -= min(pcol->nr_pages, pcol->expected_pages);
86093aaff   Boaz Harrosh   exofs: convert io...
86
87
  	pcol->pages = NULL;
  	pcol->alloc_pages = 0;
beaec07ba   Boaz Harrosh   exofs: address_sp...
88
89
90
  	pcol->nr_pages = 0;
  	pcol->length = 0;
  	pcol->pg_first = -1;
06886a5a3   Boaz Harrosh   exofs: Move all o...
91
  	pcol->ios = NULL;
dd2966199   Boaz Harrosh   exofs: Support fo...
92
  	pcol->that_locked_page = NULL;
beaec07ba   Boaz Harrosh   exofs: address_sp...
93
94
95
96
97
  
  	/* this is probably the end of the loop but in writes
  	 * it might not end here. don't be left with nothing
  	 */
  	if (!pcol->expected_pages)
86093aaff   Boaz Harrosh   exofs: convert io...
98
  		pcol->expected_pages = MAX_PAGES_KMALLOC;
beaec07ba   Boaz Harrosh   exofs: address_sp...
99
100
101
102
  }
  
  static int pcol_try_alloc(struct page_collect *pcol)
  {
66cd6cad4   bharrosh@panasas.com   exofs: Override r...
103
  	unsigned pages;
06886a5a3   Boaz Harrosh   exofs: Move all o...
104

86093aaff   Boaz Harrosh   exofs: convert io...
105
  	/* TODO: easily support bio chaining */
66cd6cad4   bharrosh@panasas.com   exofs: Override r...
106
  	pages =  exofs_max_io_pages(&pcol->sbi->layout, pcol->expected_pages);
86093aaff   Boaz Harrosh   exofs: convert io...
107

beaec07ba   Boaz Harrosh   exofs: address_sp...
108
  	for (; pages; pages >>= 1) {
86093aaff   Boaz Harrosh   exofs: convert io...
109
110
111
112
  		pcol->pages = kmalloc(pages * sizeof(struct page *),
  				      GFP_KERNEL);
  		if (likely(pcol->pages)) {
  			pcol->alloc_pages = pages;
beaec07ba   Boaz Harrosh   exofs: address_sp...
113
  			return 0;
86093aaff   Boaz Harrosh   exofs: convert io...
114
  		}
beaec07ba   Boaz Harrosh   exofs: address_sp...
115
  	}
86093aaff   Boaz Harrosh   exofs: convert io...
116
117
  	EXOFS_ERR("Failed to kmalloc expected_pages=%u
  ",
beaec07ba   Boaz Harrosh   exofs: address_sp...
118
119
120
121
122
123
  		  pcol->expected_pages);
  	return -ENOMEM;
  }
  
  static void pcol_free(struct page_collect *pcol)
  {
86093aaff   Boaz Harrosh   exofs: convert io...
124
125
  	kfree(pcol->pages);
  	pcol->pages = NULL;
06886a5a3   Boaz Harrosh   exofs: Move all o...
126
127
  
  	if (pcol->ios) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
128
  		ore_put_io_state(pcol->ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
129
130
  		pcol->ios = NULL;
  	}
beaec07ba   Boaz Harrosh   exofs: address_sp...
131
132
133
134
135
  }
  
  static int pcol_add_page(struct page_collect *pcol, struct page *page,
  			 unsigned len)
  {
86093aaff   Boaz Harrosh   exofs: convert io...
136
  	if (unlikely(pcol->nr_pages >= pcol->alloc_pages))
beaec07ba   Boaz Harrosh   exofs: address_sp...
137
  		return -ENOMEM;
86093aaff   Boaz Harrosh   exofs: convert io...
138
  	pcol->pages[pcol->nr_pages++] = page;
beaec07ba   Boaz Harrosh   exofs: address_sp...
139
140
141
  	pcol->length += len;
  	return 0;
  }
154a9300c   Boaz Harrosh   exofs: Support fo...
142
  enum {PAGE_WAS_NOT_IN_IO = 17};
beaec07ba   Boaz Harrosh   exofs: address_sp...
143
144
  static int update_read_page(struct page *page, int ret)
  {
154a9300c   Boaz Harrosh   exofs: Support fo...
145
146
  	switch (ret) {
  	case 0:
beaec07ba   Boaz Harrosh   exofs: address_sp...
147
148
149
150
  		/* Everything is OK */
  		SetPageUptodate(page);
  		if (PageError(page))
  			ClearPageError(page);
154a9300c   Boaz Harrosh   exofs: Support fo...
151
152
  		break;
  	case -EFAULT:
beaec07ba   Boaz Harrosh   exofs: address_sp...
153
154
155
156
157
158
159
160
161
162
  		/* In this case we were trying to read something that wasn't on
  		 * disk yet - return a page full of zeroes.  This should be OK,
  		 * because the object should be empty (if there was a write
  		 * before this read, the read would be waiting with the page
  		 * locked */
  		clear_highpage(page);
  
  		SetPageUptodate(page);
  		if (PageError(page))
  			ClearPageError(page);
beaec07ba   Boaz Harrosh   exofs: address_sp...
163
164
  		EXOFS_DBGMSG("recovered read error
  ");
154a9300c   Boaz Harrosh   exofs: Support fo...
165
166
167
168
169
  		/* fall through */
  	case PAGE_WAS_NOT_IN_IO:
  		ret = 0; /* recovered error */
  		break;
  	default:
beaec07ba   Boaz Harrosh   exofs: address_sp...
170
  		SetPageError(page);
154a9300c   Boaz Harrosh   exofs: Support fo...
171
  	}
beaec07ba   Boaz Harrosh   exofs: address_sp...
172
173
174
175
176
  	return ret;
  }
  
  static void update_write_page(struct page *page, int ret)
  {
154a9300c   Boaz Harrosh   exofs: Support fo...
177
178
  	if (unlikely(ret == PAGE_WAS_NOT_IN_IO))
  		return; /* don't pass start don't collect $200 */
beaec07ba   Boaz Harrosh   exofs: address_sp...
179
180
181
182
183
184
185
186
187
188
  	if (ret) {
  		mapping_set_error(page->mapping, ret);
  		SetPageError(page);
  	}
  	end_page_writeback(page);
  }
  
  /* Called at the end of reads, to optionally unlock pages and update their
   * status.
   */
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
189
  static int __readpages_done(struct page_collect *pcol)
beaec07ba   Boaz Harrosh   exofs: address_sp...
190
  {
beaec07ba   Boaz Harrosh   exofs: address_sp...
191
  	int i;
beaec07ba   Boaz Harrosh   exofs: address_sp...
192
193
  	u64 good_bytes;
  	u64 length = 0;
4b46c9f5c   Boaz Harrosh   ore/exofs: Change...
194
  	int ret = ore_check_io(pcol->ios, NULL);
beaec07ba   Boaz Harrosh   exofs: address_sp...
195

154a9300c   Boaz Harrosh   exofs: Support fo...
196
  	if (likely(!ret)) {
beaec07ba   Boaz Harrosh   exofs: address_sp...
197
  		good_bytes = pcol->length;
154a9300c   Boaz Harrosh   exofs: Support fo...
198
199
  		ret = PAGE_WAS_NOT_IN_IO;
  	} else {
4b46c9f5c   Boaz Harrosh   ore/exofs: Change...
200
  		good_bytes = 0;
154a9300c   Boaz Harrosh   exofs: Support fo...
201
  	}
beaec07ba   Boaz Harrosh   exofs: address_sp...
202

34ce4e7c2   Boaz Harrosh   exofs: debug prin...
203
  	EXOFS_DBGMSG2("readpages_done(0x%lx) good_bytes=0x%llx"
beaec07ba   Boaz Harrosh   exofs: address_sp...
204
205
206
207
  		     " length=0x%lx nr_pages=%u
  ",
  		     pcol->inode->i_ino, _LLU(good_bytes), pcol->length,
  		     pcol->nr_pages);
86093aaff   Boaz Harrosh   exofs: convert io...
208
209
  	for (i = 0; i < pcol->nr_pages; i++) {
  		struct page *page = pcol->pages[i];
beaec07ba   Boaz Harrosh   exofs: address_sp...
210
211
212
213
214
215
216
217
218
219
  		struct inode *inode = page->mapping->host;
  		int page_stat;
  
  		if (inode != pcol->inode)
  			continue; /* osd might add more pages at end */
  
  		if (likely(length < good_bytes))
  			page_stat = 0;
  		else
  			page_stat = ret;
fe33cc1ee   Boaz Harrosh   exofs: dbg-print ...
220
221
  		EXOFS_DBGMSG2("    readpages_done(0x%lx, 0x%lx) %s
  ",
beaec07ba   Boaz Harrosh   exofs: address_sp...
222
223
224
225
  			  inode->i_ino, page->index,
  			  page_stat ? "bad_bytes" : "good_bytes");
  
  		ret = update_read_page(page, page_stat);
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
226
  		if (!pcol->read_4_write)
beaec07ba   Boaz Harrosh   exofs: address_sp...
227
  			unlock_page(page);
86093aaff   Boaz Harrosh   exofs: convert io...
228
  		length += PAGE_SIZE;
beaec07ba   Boaz Harrosh   exofs: address_sp...
229
230
231
  	}
  
  	pcol_free(pcol);
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
232
233
  	EXOFS_DBGMSG2("readpages_done END
  ");
beaec07ba   Boaz Harrosh   exofs: address_sp...
234
235
236
237
  	return ret;
  }
  
  /* callback of async reads */
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
238
  static void readpages_done(struct ore_io_state *ios, void *p)
beaec07ba   Boaz Harrosh   exofs: address_sp...
239
240
  {
  	struct page_collect *pcol = p;
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
241
  	__readpages_done(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
242
  	atomic_dec(&pcol->sbi->s_curr_pending);
06886a5a3   Boaz Harrosh   exofs: Move all o...
243
  	kfree(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
244
245
246
247
  }
  
  static void _unlock_pcol_pages(struct page_collect *pcol, int ret, int rw)
  {
beaec07ba   Boaz Harrosh   exofs: address_sp...
248
  	int i;
86093aaff   Boaz Harrosh   exofs: convert io...
249
250
  	for (i = 0; i < pcol->nr_pages; i++) {
  		struct page *page = pcol->pages[i];
beaec07ba   Boaz Harrosh   exofs: address_sp...
251
252
253
254
255
256
257
258
  
  		if (rw == READ)
  			update_read_page(page, ret);
  		else
  			update_write_page(page, ret);
  
  		unlock_page(page);
  	}
beaec07ba   Boaz Harrosh   exofs: address_sp...
259
  }
b916c5cd4   Boaz Harrosh   ore: Only IO one ...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
  static int _maybe_not_all_in_one_io(struct ore_io_state *ios,
  	struct page_collect *pcol_src, struct page_collect *pcol)
  {
  	/* length was wrong or offset was not page aligned */
  	BUG_ON(pcol_src->nr_pages < ios->nr_pages);
  
  	if (pcol_src->nr_pages > ios->nr_pages) {
  		struct page **src_page;
  		unsigned pages_less = pcol_src->nr_pages - ios->nr_pages;
  		unsigned long len_less = pcol_src->length - ios->length;
  		unsigned i;
  		int ret;
  
  		/* This IO was trimmed */
  		pcol_src->nr_pages = ios->nr_pages;
  		pcol_src->length = ios->length;
  
  		/* Left over pages are passed to the next io */
  		pcol->expected_pages += pages_less;
  		pcol->nr_pages = pages_less;
  		pcol->length = len_less;
  		src_page = pcol_src->pages + pcol_src->nr_pages;
  		pcol->pg_first = (*src_page)->index;
  
  		ret = pcol_try_alloc(pcol);
  		if (unlikely(ret))
  			return ret;
  
  		for (i = 0; i < pages_less; ++i)
  			pcol->pages[i] = *src_page++;
  
  		EXOFS_DBGMSG("Length was adjusted nr_pages=0x%x "
  			"pages_less=0x%x expected_pages=0x%x "
  			"next_offset=0x%llx next_len=0x%lx
  ",
  			pcol_src->nr_pages, pages_less, pcol->expected_pages,
  			pcol->pg_first * PAGE_SIZE, pcol->length);
  	}
  	return 0;
  }
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
300
  static int read_exec(struct page_collect *pcol)
beaec07ba   Boaz Harrosh   exofs: address_sp...
301
302
  {
  	struct exofs_i_info *oi = exofs_i(pcol->inode);
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
303
  	struct ore_io_state *ios;
beaec07ba   Boaz Harrosh   exofs: address_sp...
304
  	struct page_collect *pcol_copy = NULL;
beaec07ba   Boaz Harrosh   exofs: address_sp...
305
  	int ret;
86093aaff   Boaz Harrosh   exofs: convert io...
306
  	if (!pcol->pages)
beaec07ba   Boaz Harrosh   exofs: address_sp...
307
  		return 0;
e1042ba09   Boaz Harrosh   exofs: Add offset...
308
  	if (!pcol->ios) {
5bf696dad   Boaz Harrosh   exofs: Rename str...
309
  		int ret = ore_get_rw_state(&pcol->sbi->layout, &oi->oc, true,
e1042ba09   Boaz Harrosh   exofs: Add offset...
310
311
312
313
314
315
316
317
  					     pcol->pg_first << PAGE_CACHE_SHIFT,
  					     pcol->length, &pcol->ios);
  
  		if (ret)
  			return ret;
  	}
  
  	ios = pcol->ios;
86093aaff   Boaz Harrosh   exofs: convert io...
318
  	ios->pages = pcol->pages;
beaec07ba   Boaz Harrosh   exofs: address_sp...
319

7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
320
  	if (pcol->read_4_write) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
321
  		ore_read(pcol->ios);
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
322
  		return __readpages_done(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
323
324
325
326
327
328
329
330
331
  	}
  
  	pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
  	if (!pcol_copy) {
  		ret = -ENOMEM;
  		goto err;
  	}
  
  	*pcol_copy = *pcol;
06886a5a3   Boaz Harrosh   exofs: Move all o...
332
333
  	ios->done = readpages_done;
  	ios->private = pcol_copy;
b916c5cd4   Boaz Harrosh   ore: Only IO one ...
334
335
336
337
338
339
340
341
342
343
344
  
  	/* pages ownership was passed to pcol_copy */
  	_pcol_reset(pcol);
  
  	ret = _maybe_not_all_in_one_io(ios, pcol_copy, pcol);
  	if (unlikely(ret))
  		goto err;
  
  	EXOFS_DBGMSG2("read_exec(0x%lx) offset=0x%llx length=0x%llx
  ",
  		pcol->inode->i_ino, _LLU(ios->offset), _LLU(ios->length));
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
345
  	ret = ore_read(ios);
beaec07ba   Boaz Harrosh   exofs: address_sp...
346
347
348
349
  	if (unlikely(ret))
  		goto err;
  
  	atomic_inc(&pcol->sbi->s_curr_pending);
beaec07ba   Boaz Harrosh   exofs: address_sp...
350
351
352
  	return 0;
  
  err:
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
353
  	if (!pcol->read_4_write)
beaec07ba   Boaz Harrosh   exofs: address_sp...
354
  		_unlock_pcol_pages(pcol, ret, READ);
06886a5a3   Boaz Harrosh   exofs: Move all o...
355
356
  
  	pcol_free(pcol);
b76a3f93d   Boaz Harrosh   exofs: Fix bio le...
357

beaec07ba   Boaz Harrosh   exofs: address_sp...
358
  	kfree(pcol_copy);
beaec07ba   Boaz Harrosh   exofs: address_sp...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	return ret;
  }
  
  /* readpage_strip is called either directly from readpage() or by the VFS from
   * within read_cache_pages(), to add one more page to be read. It will try to
   * collect as many contiguous pages as posible. If a discontinuity is
   * encountered, or it runs out of resources, it will submit the previous segment
   * and will start a new collection. Eventually caller must submit the last
   * segment if present.
   */
  static int readpage_strip(void *data, struct page *page)
  {
  	struct page_collect *pcol = data;
  	struct inode *inode = pcol->inode;
  	struct exofs_i_info *oi = exofs_i(inode);
  	loff_t i_size = i_size_read(inode);
  	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
  	size_t len;
  	int ret;
  
  	/* FIXME: Just for debugging, will be removed */
  	if (PageUptodate(page))
  		EXOFS_ERR("PageUptodate(0x%lx, 0x%lx)
  ", pcol->inode->i_ino,
  			  page->index);
dd2966199   Boaz Harrosh   exofs: Support fo...
384
  	pcol->that_locked_page = page;
beaec07ba   Boaz Harrosh   exofs: address_sp...
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  	if (page->index < end_index)
  		len = PAGE_CACHE_SIZE;
  	else if (page->index == end_index)
  		len = i_size & ~PAGE_CACHE_MASK;
  	else
  		len = 0;
  
  	if (!len || !obj_created(oi)) {
  		/* this will be out of bounds, or doesn't exist yet.
  		 * Current page is cleared and the request is split
  		 */
  		clear_highpage(page);
  
  		SetPageUptodate(page);
  		if (PageError(page))
  			ClearPageError(page);
f17b1f9f1   Boaz Harrosh   exofs: Fix double...
401
402
  		if (!pcol->read_4_write)
  			unlock_page(page);
a8f1418f9   Boaz Harrosh   exofs: Optimize r...
403
404
405
406
407
  		EXOFS_DBGMSG("readpage_strip(0x%lx) empty page len=%zx "
  			     "read_4_write=%d index=0x%lx end_index=0x%lx "
  			     "splitting
  ", inode->i_ino, len,
  			     pcol->read_4_write, page->index, end_index);
beaec07ba   Boaz Harrosh   exofs: address_sp...
408

7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
409
  		return read_exec(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
410
411
412
413
414
415
416
417
418
  	}
  
  try_again:
  
  	if (unlikely(pcol->pg_first == -1)) {
  		pcol->pg_first = page->index;
  	} else if (unlikely((pcol->pg_first + pcol->nr_pages) !=
  		   page->index)) {
  		/* Discontinuity detected, split the request */
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
419
  		ret = read_exec(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
420
421
422
423
  		if (unlikely(ret))
  			goto fail;
  		goto try_again;
  	}
86093aaff   Boaz Harrosh   exofs: convert io...
424
  	if (!pcol->pages) {
beaec07ba   Boaz Harrosh   exofs: address_sp...
425
426
427
428
429
430
431
  		ret = pcol_try_alloc(pcol);
  		if (unlikely(ret))
  			goto fail;
  	}
  
  	if (len != PAGE_CACHE_SIZE)
  		zero_user(page, len, PAGE_CACHE_SIZE - len);
fe33cc1ee   Boaz Harrosh   exofs: dbg-print ...
432
433
  	EXOFS_DBGMSG2("    readpage_strip(0x%lx, 0x%lx) len=0x%zx
  ",
beaec07ba   Boaz Harrosh   exofs: address_sp...
434
435
436
437
  		     inode->i_ino, page->index, len);
  
  	ret = pcol_add_page(pcol, page, len);
  	if (ret) {
fe33cc1ee   Boaz Harrosh   exofs: dbg-print ...
438
  		EXOFS_DBGMSG2("Failed pcol_add_page pages[i]=%p "
beaec07ba   Boaz Harrosh   exofs: address_sp...
439
440
441
442
443
  			  "this_len=0x%zx nr_pages=%u length=0x%lx
  ",
  			  page, len, pcol->nr_pages, pcol->length);
  
  		/* split the request, and start again with current page */
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
444
  		ret = read_exec(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  		if (unlikely(ret))
  			goto fail;
  
  		goto try_again;
  	}
  
  	return 0;
  
  fail:
  	/* SetPageError(page); ??? */
  	unlock_page(page);
  	return ret;
  }
  
  static int exofs_readpages(struct file *file, struct address_space *mapping,
  			   struct list_head *pages, unsigned nr_pages)
  {
  	struct page_collect pcol;
  	int ret;
  
  	_pcol_init(&pcol, nr_pages, mapping->host);
  
  	ret = read_cache_pages(mapping, pages, readpage_strip, &pcol);
  	if (ret) {
  		EXOFS_ERR("read_cache_pages => %d
  ", ret);
  		return ret;
  	}
b916c5cd4   Boaz Harrosh   ore: Only IO one ...
473
474
475
  	ret = read_exec(&pcol);
  	if (unlikely(ret))
  		return ret;
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
476
  	return read_exec(&pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
477
  }
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
478
  static int _readpage(struct page *page, bool read_4_write)
beaec07ba   Boaz Harrosh   exofs: address_sp...
479
480
481
482
483
  {
  	struct page_collect pcol;
  	int ret;
  
  	_pcol_init(&pcol, 1, page->mapping->host);
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
484
  	pcol.read_4_write = read_4_write;
beaec07ba   Boaz Harrosh   exofs: address_sp...
485
486
487
488
489
490
  	ret = readpage_strip(&pcol, page);
  	if (ret) {
  		EXOFS_ERR("_readpage => %d
  ", ret);
  		return ret;
  	}
7aebf4106   Boaz Harrosh   exofs: Cleaup rea...
491
  	return read_exec(&pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
492
493
494
495
496
497
498
499
500
  }
  
  /*
   * We don't need the file
   */
  static int exofs_readpage(struct file *file, struct page *page)
  {
  	return _readpage(page, false);
  }
06886a5a3   Boaz Harrosh   exofs: Move all o...
501
  /* Callback for osd_write. All writes are asynchronous */
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
502
  static void writepages_done(struct ore_io_state *ios, void *p)
beaec07ba   Boaz Harrosh   exofs: address_sp...
503
504
  {
  	struct page_collect *pcol = p;
beaec07ba   Boaz Harrosh   exofs: address_sp...
505
  	int i;
beaec07ba   Boaz Harrosh   exofs: address_sp...
506
507
  	u64  good_bytes;
  	u64  length = 0;
4b46c9f5c   Boaz Harrosh   ore/exofs: Change...
508
  	int ret = ore_check_io(ios, NULL);
beaec07ba   Boaz Harrosh   exofs: address_sp...
509

beaec07ba   Boaz Harrosh   exofs: address_sp...
510
  	atomic_dec(&pcol->sbi->s_curr_pending);
154a9300c   Boaz Harrosh   exofs: Support fo...
511
  	if (likely(!ret)) {
beaec07ba   Boaz Harrosh   exofs: address_sp...
512
  		good_bytes = pcol->length;
154a9300c   Boaz Harrosh   exofs: Support fo...
513
514
  		ret = PAGE_WAS_NOT_IN_IO;
  	} else {
4b46c9f5c   Boaz Harrosh   ore/exofs: Change...
515
  		good_bytes = 0;
154a9300c   Boaz Harrosh   exofs: Support fo...
516
  	}
beaec07ba   Boaz Harrosh   exofs: address_sp...
517

34ce4e7c2   Boaz Harrosh   exofs: debug prin...
518
  	EXOFS_DBGMSG2("writepages_done(0x%lx) good_bytes=0x%llx"
beaec07ba   Boaz Harrosh   exofs: address_sp...
519
520
521
522
  		     " length=0x%lx nr_pages=%u
  ",
  		     pcol->inode->i_ino, _LLU(good_bytes), pcol->length,
  		     pcol->nr_pages);
86093aaff   Boaz Harrosh   exofs: convert io...
523
524
  	for (i = 0; i < pcol->nr_pages; i++) {
  		struct page *page = pcol->pages[i];
beaec07ba   Boaz Harrosh   exofs: address_sp...
525
526
527
528
529
530
531
532
533
534
535
536
537
  		struct inode *inode = page->mapping->host;
  		int page_stat;
  
  		if (inode != pcol->inode)
  			continue; /* osd might add more pages to a bio */
  
  		if (likely(length < good_bytes))
  			page_stat = 0;
  		else
  			page_stat = ret;
  
  		update_write_page(page, page_stat);
  		unlock_page(page);
fe33cc1ee   Boaz Harrosh   exofs: dbg-print ...
538
539
  		EXOFS_DBGMSG2("    writepages_done(0x%lx, 0x%lx) status=%d
  ",
beaec07ba   Boaz Harrosh   exofs: address_sp...
540
  			     inode->i_ino, page->index, page_stat);
86093aaff   Boaz Harrosh   exofs: convert io...
541
  		length += PAGE_SIZE;
beaec07ba   Boaz Harrosh   exofs: address_sp...
542
543
544
545
  	}
  
  	pcol_free(pcol);
  	kfree(pcol);
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
546
547
  	EXOFS_DBGMSG2("writepages_done END
  ");
beaec07ba   Boaz Harrosh   exofs: address_sp...
548
  }
dd2966199   Boaz Harrosh   exofs: Support fo...
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
  {
  	struct page_collect *pcol = priv;
  	pgoff_t index = offset / PAGE_SIZE;
  
  	if (!pcol->that_locked_page ||
  	    (pcol->that_locked_page->index != index)) {
  		struct page *page = find_get_page(pcol->inode->i_mapping, index);
  
  		if (!page) {
  			page = find_or_create_page(pcol->inode->i_mapping,
  						   index, GFP_NOFS);
  			if (unlikely(!page)) {
  				EXOFS_DBGMSG("grab_cache_page Failed "
  					"index=0x%llx
  ", _LLU(index));
  				return NULL;
  			}
  			unlock_page(page);
  		}
  		if (PageDirty(page) || PageWriteback(page))
  			*uptodate = true;
  		else
  			*uptodate = PageUptodate(page);
  		EXOFS_DBGMSG("index=0x%lx uptodate=%d
  ", index, *uptodate);
  		return page;
  	} else {
  		EXOFS_DBGMSG("YES that_locked_page index=0x%lx
  ",
  			     pcol->that_locked_page->index);
  		*uptodate = true;
  		return pcol->that_locked_page;
  	}
  }
  
  static void __r4w_put_page(void *priv, struct page *page)
  {
  	struct page_collect *pcol = priv;
  
  	if (pcol->that_locked_page != page) {
  		EXOFS_DBGMSG("index=0x%lx
  ", page->index);
  		page_cache_release(page);
  		return;
  	}
  	EXOFS_DBGMSG("that_locked_page index=0x%lx
  ", page->index);
  }
  
  static const struct _ore_r4w_op _r4w_op = {
  	.get_page = &__r4w_get_page,
  	.put_page = &__r4w_put_page,
  };
beaec07ba   Boaz Harrosh   exofs: address_sp...
603
604
605
  static int write_exec(struct page_collect *pcol)
  {
  	struct exofs_i_info *oi = exofs_i(pcol->inode);
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
606
  	struct ore_io_state *ios;
beaec07ba   Boaz Harrosh   exofs: address_sp...
607
  	struct page_collect *pcol_copy = NULL;
beaec07ba   Boaz Harrosh   exofs: address_sp...
608
  	int ret;
86093aaff   Boaz Harrosh   exofs: convert io...
609
  	if (!pcol->pages)
beaec07ba   Boaz Harrosh   exofs: address_sp...
610
  		return 0;
e1042ba09   Boaz Harrosh   exofs: Add offset...
611
  	BUG_ON(pcol->ios);
5bf696dad   Boaz Harrosh   exofs: Rename str...
612
  	ret = ore_get_rw_state(&pcol->sbi->layout, &oi->oc, false,
e1042ba09   Boaz Harrosh   exofs: Add offset...
613
614
  				 pcol->pg_first << PAGE_CACHE_SHIFT,
  				 pcol->length, &pcol->ios);
e1042ba09   Boaz Harrosh   exofs: Add offset...
615
616
  	if (unlikely(ret))
  		goto err;
beaec07ba   Boaz Harrosh   exofs: address_sp...
617
618
  	pcol_copy = kmalloc(sizeof(*pcol_copy), GFP_KERNEL);
  	if (!pcol_copy) {
571f7f46b   Joe Perches   fs/exofs: typo fi...
619
620
  		EXOFS_ERR("write_exec: Failed to kmalloc(pcol)
  ");
beaec07ba   Boaz Harrosh   exofs: address_sp...
621
622
623
624
625
  		ret = -ENOMEM;
  		goto err;
  	}
  
  	*pcol_copy = *pcol;
e1042ba09   Boaz Harrosh   exofs: Add offset...
626
  	ios = pcol->ios;
86093aaff   Boaz Harrosh   exofs: convert io...
627
  	ios->pages = pcol_copy->pages;
06886a5a3   Boaz Harrosh   exofs: Move all o...
628
  	ios->done = writepages_done;
dd2966199   Boaz Harrosh   exofs: Support fo...
629
  	ios->r4w = &_r4w_op;
06886a5a3   Boaz Harrosh   exofs: Move all o...
630
  	ios->private = pcol_copy;
b916c5cd4   Boaz Harrosh   ore: Only IO one ...
631
632
633
634
635
636
637
638
639
640
  	/* pages ownership was passed to pcol_copy */
  	_pcol_reset(pcol);
  
  	ret = _maybe_not_all_in_one_io(ios, pcol_copy, pcol);
  	if (unlikely(ret))
  		goto err;
  
  	EXOFS_DBGMSG2("write_exec(0x%lx) offset=0x%llx length=0x%llx
  ",
  		pcol->inode->i_ino, _LLU(ios->offset), _LLU(ios->length));
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
641
  	ret = ore_write(ios);
beaec07ba   Boaz Harrosh   exofs: address_sp...
642
  	if (unlikely(ret)) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
643
644
  		EXOFS_ERR("write_exec: ore_write() Failed
  ");
beaec07ba   Boaz Harrosh   exofs: address_sp...
645
646
647
648
  		goto err;
  	}
  
  	atomic_inc(&pcol->sbi->s_curr_pending);
beaec07ba   Boaz Harrosh   exofs: address_sp...
649
650
651
652
  	return 0;
  
  err:
  	_unlock_pcol_pages(pcol, ret, WRITE);
06886a5a3   Boaz Harrosh   exofs: Move all o...
653
  	pcol_free(pcol);
beaec07ba   Boaz Harrosh   exofs: address_sp...
654
  	kfree(pcol_copy);
06886a5a3   Boaz Harrosh   exofs: Move all o...
655

beaec07ba   Boaz Harrosh   exofs: address_sp...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  	return ret;
  }
  
  /* writepage_strip is called either directly from writepage() or by the VFS from
   * within write_cache_pages(), to add one more page to be written to storage.
   * It will try to collect as many contiguous pages as possible. If a
   * discontinuity is encountered or it runs out of resources it will submit the
   * previous segment and will start a new collection.
   * Eventually caller must submit the last segment if present.
   */
  static int writepage_strip(struct page *page,
  			   struct writeback_control *wbc_unused, void *data)
  {
  	struct page_collect *pcol = data;
  	struct inode *inode = pcol->inode;
  	struct exofs_i_info *oi = exofs_i(inode);
  	loff_t i_size = i_size_read(inode);
  	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
  	size_t len;
  	int ret;
  
  	BUG_ON(!PageLocked(page));
  
  	ret = wait_obj_created(oi);
  	if (unlikely(ret))
  		goto fail;
  
  	if (page->index < end_index)
  		/* in this case, the page is within the limits of the file */
  		len = PAGE_CACHE_SIZE;
  	else {
  		len = i_size & ~PAGE_CACHE_MASK;
  
  		if (page->index > end_index || !len) {
  			/* in this case, the page is outside the limits
  			 * (truncate in progress)
  			 */
  			ret = write_exec(pcol);
  			if (unlikely(ret))
  				goto fail;
  			if (PageError(page))
  				ClearPageError(page);
  			unlock_page(page);
06886a5a3   Boaz Harrosh   exofs: Move all o...
699
700
701
702
  			EXOFS_DBGMSG("writepage_strip(0x%lx, 0x%lx) "
  				     "outside the limits
  ",
  				     inode->i_ino, page->index);
beaec07ba   Boaz Harrosh   exofs: address_sp...
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  			return 0;
  		}
  	}
  
  try_again:
  
  	if (unlikely(pcol->pg_first == -1)) {
  		pcol->pg_first = page->index;
  	} else if (unlikely((pcol->pg_first + pcol->nr_pages) !=
  		   page->index)) {
  		/* Discontinuity detected, split the request */
  		ret = write_exec(pcol);
  		if (unlikely(ret))
  			goto fail;
06886a5a3   Boaz Harrosh   exofs: Move all o...
717
718
719
720
  
  		EXOFS_DBGMSG("writepage_strip(0x%lx, 0x%lx) Discontinuity
  ",
  			     inode->i_ino, page->index);
beaec07ba   Boaz Harrosh   exofs: address_sp...
721
722
  		goto try_again;
  	}
86093aaff   Boaz Harrosh   exofs: convert io...
723
  	if (!pcol->pages) {
beaec07ba   Boaz Harrosh   exofs: address_sp...
724
725
726
727
  		ret = pcol_try_alloc(pcol);
  		if (unlikely(ret))
  			goto fail;
  	}
fe33cc1ee   Boaz Harrosh   exofs: dbg-print ...
728
729
  	EXOFS_DBGMSG2("    writepage_strip(0x%lx, 0x%lx) len=0x%zx
  ",
beaec07ba   Boaz Harrosh   exofs: address_sp...
730
731
732
733
  		     inode->i_ino, page->index, len);
  
  	ret = pcol_add_page(pcol, page, len);
  	if (unlikely(ret)) {
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
734
  		EXOFS_DBGMSG2("Failed pcol_add_page "
beaec07ba   Boaz Harrosh   exofs: address_sp...
735
736
737
738
739
740
741
  			     "nr_pages=%u total_length=0x%lx
  ",
  			     pcol->nr_pages, pcol->length);
  
  		/* split the request, next loop will start again */
  		ret = write_exec(pcol);
  		if (unlikely(ret)) {
571f7f46b   Joe Perches   fs/exofs: typo fi...
742
  			EXOFS_DBGMSG("write_exec failed => %d", ret);
beaec07ba   Boaz Harrosh   exofs: address_sp...
743
744
745
746
747
748
749
750
751
752
753
754
  			goto fail;
  		}
  
  		goto try_again;
  	}
  
  	BUG_ON(PageWriteback(page));
  	set_page_writeback(page);
  
  	return 0;
  
  fail:
06886a5a3   Boaz Harrosh   exofs: Move all o...
755
756
757
  	EXOFS_DBGMSG("Error: writepage_strip(0x%lx, 0x%lx)=>%d
  ",
  		     inode->i_ino, page->index, ret);
beaec07ba   Boaz Harrosh   exofs: address_sp...
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
  	set_bit(AS_EIO, &page->mapping->flags);
  	unlock_page(page);
  	return ret;
  }
  
  static int exofs_writepages(struct address_space *mapping,
  		       struct writeback_control *wbc)
  {
  	struct page_collect pcol;
  	long start, end, expected_pages;
  	int ret;
  
  	start = wbc->range_start >> PAGE_CACHE_SHIFT;
  	end = (wbc->range_end == LLONG_MAX) ?
  			start + mapping->nrpages :
  			wbc->range_end >> PAGE_CACHE_SHIFT;
  
  	if (start || end)
06886a5a3   Boaz Harrosh   exofs: Move all o...
776
  		expected_pages = end - start + 1;
beaec07ba   Boaz Harrosh   exofs: address_sp...
777
778
  	else
  		expected_pages = mapping->nrpages;
06886a5a3   Boaz Harrosh   exofs: Move all o...
779
780
  	if (expected_pages < 32L)
  		expected_pages = 32L;
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
781
  	EXOFS_DBGMSG2("inode(0x%lx) wbc->start=0x%llx wbc->end=0x%llx "
06886a5a3   Boaz Harrosh   exofs: Move all o...
782
783
  		     "nrpages=%lu start=0x%lx end=0x%lx expected_pages=%ld
  ",
beaec07ba   Boaz Harrosh   exofs: address_sp...
784
  		     mapping->host->i_ino, wbc->range_start, wbc->range_end,
06886a5a3   Boaz Harrosh   exofs: Move all o...
785
  		     mapping->nrpages, start, end, expected_pages);
beaec07ba   Boaz Harrosh   exofs: address_sp...
786
787
788
789
  
  	_pcol_init(&pcol, expected_pages, mapping->host);
  
  	ret = write_cache_pages(mapping, wbc, writepage_strip, &pcol);
b916c5cd4   Boaz Harrosh   ore: Only IO one ...
790
  	if (unlikely(ret)) {
beaec07ba   Boaz Harrosh   exofs: address_sp...
791
792
793
794
  		EXOFS_ERR("write_cache_pages => %d
  ", ret);
  		return ret;
  	}
b916c5cd4   Boaz Harrosh   ore: Only IO one ...
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  	ret = write_exec(&pcol);
  	if (unlikely(ret))
  		return ret;
  
  	if (wbc->sync_mode == WB_SYNC_ALL) {
  		return write_exec(&pcol); /* pump the last reminder */
  	} else if (pcol.nr_pages) {
  		/* not SYNC let the reminder join the next writeout */
  		unsigned i;
  
  		for (i = 0; i < pcol.nr_pages; i++) {
  			struct page *page = pcol.pages[i];
  
  			end_page_writeback(page);
  			set_page_dirty(page);
  			unlock_page(page);
  		}
  	}
  	return 0;
beaec07ba   Boaz Harrosh   exofs: address_sp...
814
  }
dd2966199   Boaz Harrosh   exofs: Support fo...
815
  /*
beaec07ba   Boaz Harrosh   exofs: address_sp...
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
  static int exofs_writepage(struct page *page, struct writeback_control *wbc)
  {
  	struct page_collect pcol;
  	int ret;
  
  	_pcol_init(&pcol, 1, page->mapping->host);
  
  	ret = writepage_strip(page, NULL, &pcol);
  	if (ret) {
  		EXOFS_ERR("exofs_writepage => %d
  ", ret);
  		return ret;
  	}
  
  	return write_exec(&pcol);
  }
dd2966199   Boaz Harrosh   exofs: Support fo...
832
  */
2f246fd0f   Boaz Harrosh   exofs: New trunca...
833
834
835
836
837
838
  /* i_mutex held using inode->i_size directly */
  static void _write_failed(struct inode *inode, loff_t to)
  {
  	if (to > inode->i_size)
  		truncate_pagecache(inode, to, inode->i_size);
  }
beaec07ba   Boaz Harrosh   exofs: address_sp...
839
840
841
842
843
844
845
846
847
848
849
850
  int exofs_write_begin(struct file *file, struct address_space *mapping,
  		loff_t pos, unsigned len, unsigned flags,
  		struct page **pagep, void **fsdata)
  {
  	int ret = 0;
  	struct page *page;
  
  	page = *pagep;
  	if (page == NULL) {
  		ret = simple_write_begin(file, mapping, pos, len, flags, pagep,
  					 fsdata);
  		if (ret) {
571f7f46b   Joe Perches   fs/exofs: typo fi...
851
852
  			EXOFS_DBGMSG("simple_write_begin failed
  ");
2f246fd0f   Boaz Harrosh   exofs: New trunca...
853
  			goto out;
beaec07ba   Boaz Harrosh   exofs: address_sp...
854
855
856
857
858
859
860
  		}
  
  		page = *pagep;
  	}
  
  	 /* read modify write */
  	if (!PageUptodate(page) && (len != PAGE_CACHE_SIZE)) {
a8f1418f9   Boaz Harrosh   exofs: Optimize r...
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
  		loff_t i_size = i_size_read(mapping->host);
  		pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
  		size_t rlen;
  
  		if (page->index < end_index)
  			rlen = PAGE_CACHE_SIZE;
  		else if (page->index == end_index)
  			rlen = i_size & ~PAGE_CACHE_MASK;
  		else
  			rlen = 0;
  
  		if (!rlen) {
  			clear_highpage(page);
  			SetPageUptodate(page);
  			goto out;
  		}
beaec07ba   Boaz Harrosh   exofs: address_sp...
877
878
879
880
  		ret = _readpage(page, true);
  		if (ret) {
  			/*SetPageError was done by _readpage. Is it ok?*/
  			unlock_page(page);
a8f1418f9   Boaz Harrosh   exofs: Optimize r...
881
882
  			EXOFS_DBGMSG("__readpage failed
  ");
beaec07ba   Boaz Harrosh   exofs: address_sp...
883
884
  		}
  	}
2f246fd0f   Boaz Harrosh   exofs: New trunca...
885
886
887
  out:
  	if (unlikely(ret))
  		_write_failed(mapping->host, pos + len);
beaec07ba   Boaz Harrosh   exofs: address_sp...
888
889
890
891
892
893
894
895
896
897
898
899
900
901
  
  	return ret;
  }
  
  static int exofs_write_begin_export(struct file *file,
  		struct address_space *mapping,
  		loff_t pos, unsigned len, unsigned flags,
  		struct page **pagep, void **fsdata)
  {
  	*pagep = NULL;
  
  	return exofs_write_begin(file, mapping, pos, len, flags, pagep,
  					fsdata);
  }
efd124b99   Boaz Harrosh   exofs: simple_wri...
902
903
904
905
906
907
908
909
910
911
  static int exofs_write_end(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned copied,
  			struct page *page, void *fsdata)
  {
  	struct inode *inode = mapping->host;
  	/* According to comment in simple_write_end i_mutex is held */
  	loff_t i_size = inode->i_size;
  	int ret;
  
  	ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata);
2f246fd0f   Boaz Harrosh   exofs: New trunca...
912
913
914
915
  	if (unlikely(ret))
  		_write_failed(inode, pos + len);
  
  	/* TODO: once simple_write_end marks inode dirty remove */
efd124b99   Boaz Harrosh   exofs: simple_wri...
916
917
918
919
  	if (i_size != inode->i_size)
  		mark_inode_dirty(inode);
  	return ret;
  }
200b07004   Boaz Harrosh   exofs: Add defaul...
920
921
922
923
924
  static int exofs_releasepage(struct page *page, gfp_t gfp)
  {
  	EXOFS_DBGMSG("page 0x%lx
  ", page->index);
  	WARN_ON(1);
85dc7878c   Boaz Harrosh   exofs: Remove sup...
925
  	return 0;
200b07004   Boaz Harrosh   exofs: Add defaul...
926
927
928
929
  }
  
  static void exofs_invalidatepage(struct page *page, unsigned long offset)
  {
85dc7878c   Boaz Harrosh   exofs: Remove sup...
930
931
  	EXOFS_DBGMSG("page 0x%lx offset 0x%lx
  ", page->index, offset);
200b07004   Boaz Harrosh   exofs: Add defaul...
932
  	WARN_ON(1);
200b07004   Boaz Harrosh   exofs: Add defaul...
933
  }
beaec07ba   Boaz Harrosh   exofs: address_sp...
934
935
936
  const struct address_space_operations exofs_aops = {
  	.readpage	= exofs_readpage,
  	.readpages	= exofs_readpages,
dd2966199   Boaz Harrosh   exofs: Support fo...
937
  	.writepage	= NULL,
beaec07ba   Boaz Harrosh   exofs: address_sp...
938
939
  	.writepages	= exofs_writepages,
  	.write_begin	= exofs_write_begin_export,
efd124b99   Boaz Harrosh   exofs: simple_wri...
940
  	.write_end	= exofs_write_end,
200b07004   Boaz Harrosh   exofs: Add defaul...
941
942
943
944
945
946
947
948
949
  	.releasepage	= exofs_releasepage,
  	.set_page_dirty	= __set_page_dirty_nobuffers,
  	.invalidatepage = exofs_invalidatepage,
  
  	/* Not implemented Yet */
  	.bmap		= NULL, /* TODO: use osd's OSD_ACT_READ_MAP */
  	.direct_IO	= NULL, /* TODO: Should be trivial to do */
  
  	/* With these NULL has special meaning or default is not exported */
200b07004   Boaz Harrosh   exofs: Add defaul...
950
951
952
953
954
  	.get_xip_mem	= NULL,
  	.migratepage	= NULL,
  	.launder_page	= NULL,
  	.is_partially_uptodate = NULL,
  	.error_remove_page = NULL,
beaec07ba   Boaz Harrosh   exofs: address_sp...
955
  };
e80627191   Boaz Harrosh   exofs: file and f...
956
957
958
959
960
961
962
963
964
965
966
967
968
  /******************************************************************************
   * INODE OPERATIONS
   *****************************************************************************/
  
  /*
   * Test whether an inode is a fast symlink.
   */
  static inline int exofs_inode_is_fast_symlink(struct inode *inode)
  {
  	struct exofs_i_info *oi = exofs_i(inode);
  
  	return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0);
  }
2f246fd0f   Boaz Harrosh   exofs: New trunca...
969
  static int _do_truncate(struct inode *inode, loff_t newsize)
06886a5a3   Boaz Harrosh   exofs: Move all o...
970
971
  {
  	struct exofs_i_info *oi = exofs_i(inode);
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
972
  	struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
06886a5a3   Boaz Harrosh   exofs: Move all o...
973
974
975
  	int ret;
  
  	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
5bf696dad   Boaz Harrosh   exofs: Rename str...
976
  	ret = ore_truncate(&sbi->layout, &oi->oc, (u64)newsize);
2f246fd0f   Boaz Harrosh   exofs: New trunca...
977
978
  	if (likely(!ret))
  		truncate_setsize(inode, newsize);
06886a5a3   Boaz Harrosh   exofs: Move all o...
979

2f246fd0f   Boaz Harrosh   exofs: New trunca...
980
981
982
  	EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d
  ",
  		     inode->i_ino, newsize, ret);
06886a5a3   Boaz Harrosh   exofs: Move all o...
983
984
  	return ret;
  }
e80627191   Boaz Harrosh   exofs: file and f...
985
  /*
2f246fd0f   Boaz Harrosh   exofs: New trunca...
986
987
   * Set inode attributes - update size attribute on OSD if needed,
   *                        otherwise just call generic functions.
e80627191   Boaz Harrosh   exofs: file and f...
988
989
990
991
992
   */
  int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
  {
  	struct inode *inode = dentry->d_inode;
  	int error;
2f246fd0f   Boaz Harrosh   exofs: New trunca...
993
994
995
996
997
998
  	/* if we are about to modify an object, and it hasn't been
  	 * created yet, wait
  	 */
  	error = wait_obj_created(exofs_i(inode));
  	if (unlikely(error))
  		return error;
e80627191   Boaz Harrosh   exofs: file and f...
999
  	error = inode_change_ok(inode, iattr);
2f246fd0f   Boaz Harrosh   exofs: New trunca...
1000
  	if (unlikely(error))
e80627191   Boaz Harrosh   exofs: file and f...
1001
  		return error;
1025774ce   Christoph Hellwig   remove inode_setattr
1002
1003
  	if ((iattr->ia_valid & ATTR_SIZE) &&
  	    iattr->ia_size != i_size_read(inode)) {
2f246fd0f   Boaz Harrosh   exofs: New trunca...
1004
1005
  		error = _do_truncate(inode, iattr->ia_size);
  		if (unlikely(error))
1025774ce   Christoph Hellwig   remove inode_setattr
1006
1007
1008
1009
1010
1011
  			return error;
  	}
  
  	setattr_copy(inode, iattr);
  	mark_inode_dirty(inode);
  	return 0;
e80627191   Boaz Harrosh   exofs: file and f...
1012
  }
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1013

d9c740d22   Boaz Harrosh   exofs: Define on-...
1014
1015
1016
1017
1018
1019
1020
1021
  static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF(
  	EXOFS_APAGE_FS_DATA,
  	EXOFS_ATTR_INODE_FILE_LAYOUT,
  	0);
  static const struct osd_attr g_attr_inode_dir_layout = ATTR_DEF(
  	EXOFS_APAGE_FS_DATA,
  	EXOFS_ATTR_INODE_DIR_LAYOUT,
  	0);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1022
  /*
5d952b839   Boaz Harrosh   exofs: RAID0 support
1023
1024
   * Read the Linux inode info from the OSD, and return it as is. In exofs the
   * inode info is in an application specific page/attribute of the osd-object.
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1025
1026
   */
  static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
5d952b839   Boaz Harrosh   exofs: RAID0 support
1027
  		    struct exofs_fcb *inode)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1028
1029
  {
  	struct exofs_sb_info *sbi = sb->s_fs_info;
d9c740d22   Boaz Harrosh   exofs: Define on-...
1030
1031
1032
1033
  	struct osd_attr attrs[] = {
  		[0] = g_attr_inode_data,
  		[1] = g_attr_inode_file_layout,
  		[2] = g_attr_inode_dir_layout,
d9c740d22   Boaz Harrosh   exofs: Define on-...
1034
  	};
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1035
  	struct ore_io_state *ios;
d9c740d22   Boaz Harrosh   exofs: Define on-...
1036
  	struct exofs_on_disk_inode_layout *layout;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1037
  	int ret;
5bf696dad   Boaz Harrosh   exofs: Rename str...
1038
  	ret = ore_get_io_state(&sbi->layout, &oi->oc, &ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1039
  	if (unlikely(ret)) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1040
1041
  		EXOFS_ERR("%s: ore_get_io_state failed.
  ", __func__);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1042
  		return ret;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1043
  	}
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1044

5bf696dad   Boaz Harrosh   exofs: Rename str...
1045
1046
  	attrs[1].len = exofs_on_disk_inode_layout_size(sbi->oc.numdevs);
  	attrs[2].len = exofs_on_disk_inode_layout_size(sbi->oc.numdevs);
d9c740d22   Boaz Harrosh   exofs: Define on-...
1047

06886a5a3   Boaz Harrosh   exofs: Move all o...
1048
1049
  	ios->in_attr = attrs;
  	ios->in_attr_len = ARRAY_SIZE(attrs);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1050

8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1051
  	ret = ore_read(ios);
96391e2ba   Boaz Harrosh   exofs: Error reco...
1052
1053
1054
  	if (unlikely(ret)) {
  		EXOFS_ERR("object(0x%llx) corrupted, return empty file=>%d
  ",
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1055
  			  _LLU(oi->one_comp.obj.id), ret);
96391e2ba   Boaz Harrosh   exofs: Error reco...
1056
1057
1058
1059
1060
1061
1062
  		memset(inode, 0, sizeof(*inode));
  		inode->i_mode = 0040000 | (0777 & ~022);
  		/* If object is lost on target we might as well enable it's
  		 * delete.
  		 */
  		if ((ret == -ENOENT) || (ret == -EINVAL))
  			ret = 0;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1063
  		goto out;
96391e2ba   Boaz Harrosh   exofs: Error reco...
1064
  	}
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1065

06886a5a3   Boaz Harrosh   exofs: Move all o...
1066
  	ret = extract_attr_from_ios(ios, &attrs[0]);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1067
  	if (ret) {
06886a5a3   Boaz Harrosh   exofs: Move all o...
1068
1069
  		EXOFS_ERR("%s: extract_attr of inode_data failed
  ", __func__);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1070
1071
  		goto out;
  	}
06886a5a3   Boaz Harrosh   exofs: Move all o...
1072
1073
  	WARN_ON(attrs[0].len != EXOFS_INO_ATTR_SIZE);
  	memcpy(inode, attrs[0].val_ptr, EXOFS_INO_ATTR_SIZE);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1074

06886a5a3   Boaz Harrosh   exofs: Move all o...
1075
  	ret = extract_attr_from_ios(ios, &attrs[1]);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1076
  	if (ret) {
d9c740d22   Boaz Harrosh   exofs: Define on-...
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
  		EXOFS_ERR("%s: extract_attr of inode_data failed
  ", __func__);
  		goto out;
  	}
  	if (attrs[1].len) {
  		layout = attrs[1].val_ptr;
  		if (layout->gen_func != cpu_to_le16(LAYOUT_MOVING_WINDOW)) {
  			EXOFS_ERR("%s: unsupported files layout %d
  ",
  				__func__, layout->gen_func);
  			ret = -ENOTSUPP;
  			goto out;
  		}
  	}
  
  	ret = extract_attr_from_ios(ios, &attrs[2]);
  	if (ret) {
  		EXOFS_ERR("%s: extract_attr of inode_data failed
  ", __func__);
  		goto out;
  	}
  	if (attrs[2].len) {
  		layout = attrs[2].val_ptr;
  		if (layout->gen_func != cpu_to_le16(LAYOUT_MOVING_WINDOW)) {
  			EXOFS_ERR("%s: unsupported meta-data layout %d
  ",
  				__func__, layout->gen_func);
  			ret = -ENOTSUPP;
  			goto out;
  		}
  	}
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1108
  out:
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1109
  	ore_put_io_state(ios);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1110
1111
  	return ret;
  }
9cfdc7aa9   Boaz Harrosh   exofs: refactor e...
1112
1113
1114
1115
1116
  static void __oi_init(struct exofs_i_info *oi)
  {
  	init_waitqueue_head(&oi->i_wq);
  	oi->i_flags = 0;
  }
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1117
1118
1119
1120
1121
1122
1123
1124
  /*
   * Fill in an inode read from the OSD and set it up for use
   */
  struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
  {
  	struct exofs_i_info *oi;
  	struct exofs_fcb fcb;
  	struct inode *inode;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1125
1126
1127
1128
1129
1130
1131
1132
  	int ret;
  
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
  	oi = exofs_i(inode);
9cfdc7aa9   Boaz Harrosh   exofs: refactor e...
1133
  	__oi_init(oi);
5bf696dad   Boaz Harrosh   exofs: Rename str...
1134
  	exofs_init_comps(&oi->oc, &oi->one_comp, sb->s_fs_info,
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1135
  			 exofs_oi_objno(oi));
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1136
1137
  
  	/* read the inode from the osd */
5d952b839   Boaz Harrosh   exofs: RAID0 support
1138
  	ret = exofs_get_inode(sb, oi, &fcb);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1139
1140
  	if (ret)
  		goto bad_inode;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1141
1142
1143
1144
1145
1146
  	set_obj_created(oi);
  
  	/* copy stuff from on-disk struct to in-memory struct */
  	inode->i_mode = le16_to_cpu(fcb.i_mode);
  	inode->i_uid = le32_to_cpu(fcb.i_uid);
  	inode->i_gid = le32_to_cpu(fcb.i_gid);
bfe868486   Miklos Szeredi   filesystems: add ...
1147
  	set_nlink(inode, le16_to_cpu(fcb.i_links_count));
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1148
1149
1150
1151
1152
1153
1154
1155
1156
  	inode->i_ctime.tv_sec = (signed)le32_to_cpu(fcb.i_ctime);
  	inode->i_atime.tv_sec = (signed)le32_to_cpu(fcb.i_atime);
  	inode->i_mtime.tv_sec = (signed)le32_to_cpu(fcb.i_mtime);
  	inode->i_ctime.tv_nsec =
  		inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = 0;
  	oi->i_commit_size = le64_to_cpu(fcb.i_size);
  	i_size_write(inode, oi->i_commit_size);
  	inode->i_blkbits = EXOFS_BLKSHIFT;
  	inode->i_generation = le32_to_cpu(fcb.i_generation);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
  	oi->i_dir_start_lookup = 0;
  
  	if ((inode->i_nlink == 0) && (inode->i_mode == 0)) {
  		ret = -ESTALE;
  		goto bad_inode;
  	}
  
  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
  		if (fcb.i_data[0])
  			inode->i_rdev =
  				old_decode_dev(le32_to_cpu(fcb.i_data[0]));
  		else
  			inode->i_rdev =
  				new_decode_dev(le32_to_cpu(fcb.i_data[1]));
  	} else {
  		memcpy(oi->i_data, fcb.i_data, sizeof(fcb.i_data));
  	}
66cd6cad4   bharrosh@panasas.com   exofs: Override r...
1174
  	inode->i_mapping->backing_dev_info = sb->s_bdi;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
  	if (S_ISREG(inode->i_mode)) {
  		inode->i_op = &exofs_file_inode_operations;
  		inode->i_fop = &exofs_file_operations;
  		inode->i_mapping->a_ops = &exofs_aops;
  	} else if (S_ISDIR(inode->i_mode)) {
  		inode->i_op = &exofs_dir_inode_operations;
  		inode->i_fop = &exofs_dir_operations;
  		inode->i_mapping->a_ops = &exofs_aops;
  	} else if (S_ISLNK(inode->i_mode)) {
  		if (exofs_inode_is_fast_symlink(inode))
  			inode->i_op = &exofs_fast_symlink_inode_operations;
  		else {
  			inode->i_op = &exofs_symlink_inode_operations;
  			inode->i_mapping->a_ops = &exofs_aops;
  		}
  	} else {
  		inode->i_op = &exofs_special_inode_operations;
  		if (fcb.i_data[0])
  			init_special_inode(inode, inode->i_mode,
  			   old_decode_dev(le32_to_cpu(fcb.i_data[0])));
  		else
  			init_special_inode(inode, inode->i_mode,
  			   new_decode_dev(le32_to_cpu(fcb.i_data[1])));
  	}
  
  	unlock_new_inode(inode);
  	return inode;
  
  bad_inode:
  	iget_failed(inode);
  	return ERR_PTR(ret);
  }
  
  int __exofs_wait_obj_created(struct exofs_i_info *oi)
  {
  	if (!obj_created(oi)) {
fe2fd9ed5   Boaz Harrosh   exofs: Remove ino...
1211
1212
  		EXOFS_DBGMSG("!obj_created
  ");
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1213
1214
  		BUG_ON(!obj_2bcreated(oi));
  		wait_event(oi->i_wq, obj_created(oi));
fe2fd9ed5   Boaz Harrosh   exofs: Remove ino...
1215
1216
  		EXOFS_DBGMSG("wait_event done
  ");
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1217
1218
1219
  	}
  	return unlikely(is_bad_inode(&oi->vfs_inode)) ? -EIO : 0;
  }
1cea312ad   Boaz Harrosh   exofs: Write sbi-...
1220

e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1221
1222
1223
1224
1225
  /*
   * Callback function from exofs_new_inode().  The important thing is that we
   * set the obj_created flag so that other methods know that the object exists on
   * the OSD.
   */
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1226
  static void create_done(struct ore_io_state *ios, void *p)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1227
1228
1229
1230
1231
  {
  	struct inode *inode = p;
  	struct exofs_i_info *oi = exofs_i(inode);
  	struct exofs_sb_info *sbi = inode->i_sb->s_fs_info;
  	int ret;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1232
1233
  	ret = ore_check_io(ios, NULL);
  	ore_put_io_state(ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1234

e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1235
1236
1237
  	atomic_dec(&sbi->s_curr_pending);
  
  	if (unlikely(ret)) {
571f7f46b   Joe Perches   fs/exofs: typo fi...
1238
  		EXOFS_ERR("object=0x%llx creation failed in pid=0x%llx",
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1239
1240
  			  _LLU(exofs_oi_objno(oi)),
  			  _LLU(oi->one_comp.obj.partition));
06886a5a3   Boaz Harrosh   exofs: Move all o...
1241
1242
1243
1244
1245
1246
1247
1248
1249
  		/*TODO: When FS is corrupted creation can fail, object already
  		 * exist. Get rid of this asynchronous creation, if exist
  		 * increment the obj counter and try the next object. Until we
  		 * succeed. All these dangling objects will be made into lost
  		 * files by chkfs.exofs
  		 */
  	}
  
  	set_obj_created(oi);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1250

e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1251
1252
1253
1254
1255
1256
  	wake_up(&oi->i_wq);
  }
  
  /*
   * Set up a new inode and create an object for it on the OSD
   */
bef41c267   Al Viro   exofs: propagate ...
1257
  struct inode *exofs_new_inode(struct inode *dir, umode_t mode)
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1258
  {
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1259
1260
  	struct super_block *sb = dir->i_sb;
  	struct exofs_sb_info *sbi = sb->s_fs_info;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1261
1262
  	struct inode *inode;
  	struct exofs_i_info *oi;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1263
  	struct ore_io_state *ios;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1264
  	int ret;
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1265
1266
1267
1268
1269
  	inode = new_inode(sb);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  
  	oi = exofs_i(inode);
9cfdc7aa9   Boaz Harrosh   exofs: refactor e...
1270
  	__oi_init(oi);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1271

e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1272
  	set_obj_2bcreated(oi);
66cd6cad4   bharrosh@panasas.com   exofs: Override r...
1273
  	inode->i_mapping->backing_dev_info = sb->s_bdi;
e00117f14   Dmitry Monakhov   exofs: replace in...
1274
  	inode_init_owner(inode, dir, mode);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1275
1276
1277
1278
1279
1280
1281
1282
  	inode->i_ino = sbi->s_nextid++;
  	inode->i_blkbits = EXOFS_BLKSHIFT;
  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  	oi->i_commit_size = inode->i_size = 0;
  	spin_lock(&sbi->s_next_gen_lock);
  	inode->i_generation = sbi->s_next_generation++;
  	spin_unlock(&sbi->s_next_gen_lock);
  	insert_inode_hash(inode);
5bf696dad   Boaz Harrosh   exofs: Rename str...
1283
  	exofs_init_comps(&oi->oc, &oi->one_comp, sb->s_fs_info,
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1284
  			 exofs_oi_objno(oi));
1cea312ad   Boaz Harrosh   exofs: Write sbi-...
1285
  	exofs_sbi_write_stats(sbi); /* Make sure new sbi->s_nextid is on disk */
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1286
  	mark_inode_dirty(inode);
5bf696dad   Boaz Harrosh   exofs: Rename str...
1287
  	ret = ore_get_io_state(&sbi->layout, &oi->oc, &ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1288
  	if (unlikely(ret)) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1289
1290
  		EXOFS_ERR("exofs_new_inode: ore_get_io_state failed
  ");
06886a5a3   Boaz Harrosh   exofs: Move all o...
1291
  		return ERR_PTR(ret);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1292
  	}
06886a5a3   Boaz Harrosh   exofs: Move all o...
1293
1294
  	ios->done = create_done;
  	ios->private = inode;
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1295

8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1296
  	ret = ore_create(ios);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1297
  	if (ret) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1298
  		ore_put_io_state(ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1299
  		return ERR_PTR(ret);
e6af00f1d   Boaz Harrosh   exofs: dir_inode ...
1300
1301
1302
1303
1304
  	}
  	atomic_inc(&sbi->s_curr_pending);
  
  	return inode;
  }
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
  
  /*
   * struct to pass two arguments to update_inode's callback
   */
  struct updatei_args {
  	struct exofs_sb_info	*sbi;
  	struct exofs_fcb	fcb;
  };
  
  /*
   * Callback function from exofs_update_inode().
   */
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1317
  static void updatei_done(struct ore_io_state *ios, void *p)
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1318
1319
  {
  	struct updatei_args *args = p;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1320
  	ore_put_io_state(ios);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  
  	atomic_dec(&args->sbi->s_curr_pending);
  
  	kfree(args);
  }
  
  /*
   * Write the inode to the OSD.  Just fill up the struct, and set the attribute
   * synchronously or asynchronously depending on the do_sync flag.
   */
  static int exofs_update_inode(struct inode *inode, int do_sync)
  {
  	struct exofs_i_info *oi = exofs_i(inode);
  	struct super_block *sb = inode->i_sb;
  	struct exofs_sb_info *sbi = sb->s_fs_info;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1336
  	struct ore_io_state *ios;
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1337
1338
1339
1340
1341
1342
  	struct osd_attr attr;
  	struct exofs_fcb *fcb;
  	struct updatei_args *args;
  	int ret;
  
  	args = kzalloc(sizeof(*args), GFP_KERNEL);
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
1343
  	if (!args) {
571f7f46b   Joe Perches   fs/exofs: typo fi...
1344
1345
  		EXOFS_DBGMSG("Failed kzalloc of args
  ");
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1346
  		return -ENOMEM;
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
1347
  	}
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
  
  	fcb = &args->fcb;
  
  	fcb->i_mode = cpu_to_le16(inode->i_mode);
  	fcb->i_uid = cpu_to_le32(inode->i_uid);
  	fcb->i_gid = cpu_to_le32(inode->i_gid);
  	fcb->i_links_count = cpu_to_le16(inode->i_nlink);
  	fcb->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
  	fcb->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
  	fcb->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
  	oi->i_commit_size = i_size_read(inode);
  	fcb->i_size = cpu_to_le64(oi->i_commit_size);
  	fcb->i_generation = cpu_to_le32(inode->i_generation);
  
  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
  		if (old_valid_dev(inode->i_rdev)) {
  			fcb->i_data[0] =
  				cpu_to_le32(old_encode_dev(inode->i_rdev));
  			fcb->i_data[1] = 0;
  		} else {
  			fcb->i_data[0] = 0;
  			fcb->i_data[1] =
  				cpu_to_le32(new_encode_dev(inode->i_rdev));
  			fcb->i_data[2] = 0;
  		}
  	} else
  		memcpy(fcb->i_data, oi->i_data, sizeof(fcb->i_data));
5bf696dad   Boaz Harrosh   exofs: Rename str...
1375
  	ret = ore_get_io_state(&sbi->layout, &oi->oc, &ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1376
  	if (unlikely(ret)) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1377
1378
  		EXOFS_ERR("%s: ore_get_io_state failed.
  ", __func__);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1379
1380
  		goto free_args;
  	}
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1381
1382
  	attr = g_attr_inode_data;
  	attr.val_ptr = fcb;
06886a5a3   Boaz Harrosh   exofs: Move all o...
1383
1384
  	ios->out_attr_len = 1;
  	ios->out_attr = &attr;
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1385

fe2fd9ed5   Boaz Harrosh   exofs: Remove ino...
1386
  	wait_obj_created(oi);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1387

06886a5a3   Boaz Harrosh   exofs: Move all o...
1388
  	if (!do_sync) {
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1389
  		args->sbi = sbi;
06886a5a3   Boaz Harrosh   exofs: Move all o...
1390
1391
1392
  		ios->done = updatei_done;
  		ios->private = args;
  	}
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1393

8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1394
  	ret = ore_write(ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1395
  	if (!do_sync && !ret) {
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1396
1397
1398
  		atomic_inc(&sbi->s_curr_pending);
  		goto out; /* deallocation in updatei_done */
  	}
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1399
  	ore_put_io_state(ios);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1400
1401
1402
  free_args:
  	kfree(args);
  out:
34ce4e7c2   Boaz Harrosh   exofs: debug prin...
1403
1404
1405
  	EXOFS_DBGMSG("(0x%lx) do_sync=%d ret=>%d
  ",
  		     inode->i_ino, do_sync, ret);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1406
1407
  	return ret;
  }
a9185b41a   Christoph Hellwig   pass writeback_co...
1408
  int exofs_write_inode(struct inode *inode, struct writeback_control *wbc)
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1409
  {
97178b7b6   Nick Piggin   exofs: simple fsy...
1410
1411
  	/* FIXME: fix fsync and use wbc->sync_mode == WB_SYNC_ALL */
  	return exofs_update_inode(inode, 1);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1412
1413
1414
1415
1416
1417
  }
  
  /*
   * Callback function from exofs_delete_inode() - don't have much cleaning up to
   * do.
   */
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1418
  static void delete_done(struct ore_io_state *ios, void *p)
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1419
  {
06886a5a3   Boaz Harrosh   exofs: Move all o...
1420
  	struct exofs_sb_info *sbi = p;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1421
  	ore_put_io_state(ios);
06886a5a3   Boaz Harrosh   exofs: Move all o...
1422

ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1423
1424
1425
1426
1427
1428
1429
1430
  	atomic_dec(&sbi->s_curr_pending);
  }
  
  /*
   * Called when the refcount of an inode reaches zero.  We remove the object
   * from the OSD here.  We make sure the object was created before we try and
   * delete it.
   */
4ec70c9b4   Al Viro   convert exofs to ...
1431
  void exofs_evict_inode(struct inode *inode)
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1432
1433
1434
1435
  {
  	struct exofs_i_info *oi = exofs_i(inode);
  	struct super_block *sb = inode->i_sb;
  	struct exofs_sb_info *sbi = sb->s_fs_info;
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1436
  	struct ore_io_state *ios;
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1437
1438
1439
  	int ret;
  
  	truncate_inode_pages(&inode->i_data, 0);
2f246fd0f   Boaz Harrosh   exofs: New trunca...
1440
  	/* TODO: should do better here */
4ec70c9b4   Al Viro   convert exofs to ...
1441
  	if (inode->i_nlink || is_bad_inode(inode))
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1442
  		goto no_delete;
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1443
  	inode->i_size = 0;
4ec70c9b4   Al Viro   convert exofs to ...
1444
  	end_writeback(inode);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1445

fe2fd9ed5   Boaz Harrosh   exofs: Remove ino...
1446
1447
1448
1449
1450
1451
  	/* if we are deleting an obj that hasn't been created yet, wait.
  	 * This also makes sure that create_done cannot be called with an
  	 * already evicted inode.
  	 */
  	wait_obj_created(oi);
  	/* ignore the error, attempt a remove anyway */
2f246fd0f   Boaz Harrosh   exofs: New trunca...
1452
1453
  
  	/* Now Remove the OSD objects */
5bf696dad   Boaz Harrosh   exofs: Rename str...
1454
  	ret = ore_get_io_state(&sbi->layout, &oi->oc, &ios);
2f246fd0f   Boaz Harrosh   exofs: New trunca...
1455
  	if (unlikely(ret)) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1456
1457
  		EXOFS_ERR("%s: ore_get_io_state failed
  ", __func__);
2f246fd0f   Boaz Harrosh   exofs: New trunca...
1458
  		return;
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1459
  	}
06886a5a3   Boaz Harrosh   exofs: Move all o...
1460
1461
  	ios->done = delete_done;
  	ios->private = sbi;
9e9db4564   Boaz Harrosh   exofs: ios: Move ...
1462

8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1463
  	ret = ore_remove(ios);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1464
  	if (ret) {
8ff660ab8   Boaz Harrosh   exofs: Rename rai...
1465
1466
1467
  		EXOFS_ERR("%s: ore_remove failed
  ", __func__);
  		ore_put_io_state(ios);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1468
1469
1470
1471
1472
1473
1474
  		return;
  	}
  	atomic_inc(&sbi->s_curr_pending);
  
  	return;
  
  no_delete:
4ec70c9b4   Al Viro   convert exofs to ...
1475
  	end_writeback(inode);
ba9e5e98c   Boaz Harrosh   exofs: super_oper...
1476
  }