ReactOS  0.4.12-dev-934-g9a4676f
write.c
Go to the documentation of this file.
1 /* Copyright (c) Mark Harmstone 2016-17
2  *
3  * This file is part of WinBtrfs.
4  *
5  * WinBtrfs is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public Licence as published by
7  * the Free Software Foundation, either version 3 of the Licence, or
8  * (at your option) any later version.
9  *
10  * WinBtrfs is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public Licence for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public Licence
16  * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17 
18 #include "btrfs_drv.h"
19 
20 typedef struct {
26 } write_stripe;
27 
28 _Function_class_(IO_COMPLETION_ROUTINE)
29 #ifdef __REACTOS__
30 static NTSTATUS NTAPI write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr);
31 #else
32 static NTSTATUS write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr);
33 #endif
34 
36 
40 extern BOOL diskacc;
41 
43  LIST_ENTRY* le;
44  space* s;
45 
46  TRACE("(%p, %llx, %llx, %p)\n", Vcb, c->offset, length, address);
47 
48  if (length > c->chunk_item->size - c->used)
49  return FALSE;
50 
51  if (!c->cache_loaded) {
53 
54  if (!NT_SUCCESS(Status)) {
55  ERR("load_cache_chunk returned %08x\n", Status);
56  return FALSE;
57  }
58  }
59 
60  if (IsListEmpty(&c->space_size))
61  return FALSE;
62 
63  le = c->space_size.Flink;
64  while (le != &c->space_size) {
65  s = CONTAINING_RECORD(le, space, list_entry_size);
66 
67  if (s->size == length) {
68  *address = s->address;
69  return TRUE;
70  } else if (s->size < length) {
71  if (le == c->space_size.Flink)
72  return FALSE;
73 
74  s = CONTAINING_RECORD(le->Blink, space, list_entry_size);
75 
76  *address = s->address;
77  return TRUE;
78  }
79 
80  le = le->Flink;
81  }
82 
83  s = CONTAINING_RECORD(c->space_size.Blink, space, list_entry_size);
84 
85  if (s->size > length) {
86  *address = s->address;
87  return TRUE;
88  }
89 
90  return FALSE;
91 }
92 
94  LIST_ENTRY* le2;
95 
96  ExAcquireResourceSharedLite(&Vcb->chunk_lock, TRUE);
97 
98  le2 = Vcb->chunks.Flink;
99  while (le2 != &Vcb->chunks) {
101 
102  if (address >= c->offset && address < c->offset + c->chunk_item->size) {
103  ExReleaseResourceLite(&Vcb->chunk_lock);
104  return c;
105  }
106 
107  le2 = le2->Flink;
108  }
109 
110  ExReleaseResourceLite(&Vcb->chunk_lock);
111 
112  return NULL;
113 }
114 
115 typedef struct {
118 } stripe;
119 
121  UINT64 lastaddr;
122  LIST_ENTRY* le;
123 
124  lastaddr = 0xc00000;
125 
126  le = Vcb->chunks.Flink;
127  while (le != &Vcb->chunks) {
129 
130  if (c->offset >= lastaddr + size)
131  return lastaddr;
132 
133  lastaddr = c->offset + c->chunk_item->size;
134 
135  le = le->Flink;
136  }
137 
138  return lastaddr;
139 }
140 
141 static BOOL find_new_dup_stripes(device_extension* Vcb, stripe* stripes, UINT64 max_stripe_size, BOOL full_size) {
142  UINT64 devusage = 0xffffffffffffffff;
143  space *devdh1 = NULL, *devdh2 = NULL;
144  LIST_ENTRY* le;
145  device* dev2 = NULL;
146 
147  le = Vcb->devices.Flink;
148 
149  while (le != &Vcb->devices) {
151 
152  if (!dev->readonly && !dev->reloc && dev->devobj) {
153  UINT64 usage = (dev->devitem.bytes_used * 4096) / dev->devitem.num_bytes;
154 
155  // favour devices which have been used the least
156  if (usage < devusage) {
157  if (!IsListEmpty(&dev->space)) {
158  LIST_ENTRY* le2;
159  space *dh1 = NULL, *dh2 = NULL;
160 
161  le2 = dev->space.Flink;
162  while (le2 != &dev->space) {
164 
165  if (dh->size >= max_stripe_size && (!dh1 || !dh2 || dh->size < dh1->size)) {
166  dh2 = dh1;
167  dh1 = dh;
168  }
169 
170  le2 = le2->Flink;
171  }
172 
173  if (dh1 && (dh2 || dh1->size >= 2 * max_stripe_size)) {
174  dev2 = dev;
175  devusage = usage;
176  devdh1 = dh1;
177  devdh2 = dh2 ? dh2 : dh1;
178  }
179  }
180  }
181  }
182 
183  le = le->Flink;
184  }
185 
186  if (!devdh1) {
187  UINT64 size = 0;
188 
189  // Can't find hole of at least max_stripe_size; look for the largest one we can find
190 
191  if (full_size)
192  return FALSE;
193 
194  le = Vcb->devices.Flink;
195  while (le != &Vcb->devices) {
197 
198  if (!dev->readonly && !dev->reloc) {
199  if (!IsListEmpty(&dev->space)) {
200  LIST_ENTRY* le2;
201  space *dh1 = NULL, *dh2 = NULL;
202 
203  le2 = dev->space.Flink;
204  while (le2 != &dev->space) {
206 
207  if (!dh1 || !dh2 || dh->size < dh1->size) {
208  dh2 = dh1;
209  dh1 = dh;
210  }
211 
212  le2 = le2->Flink;
213  }
214 
215  if (dh1) {
216  UINT64 devsize;
217 
218  if (dh2)
219  devsize = max(dh1->size / 2, min(dh1->size, dh2->size));
220  else
221  devsize = dh1->size / 2;
222 
223  if (devsize > size) {
224  dev2 = dev;
225  devdh1 = dh1;
226 
227  if (dh2 && min(dh1->size, dh2->size) > dh1->size / 2)
228  devdh2 = dh2;
229  else
230  devdh2 = dh1;
231 
232  size = devsize;
233  }
234  }
235  }
236  }
237 
238  le = le->Flink;
239  }
240 
241  if (!devdh1)
242  return FALSE;
243  }
244 
245  stripes[0].device = stripes[1].device = dev2;
246  stripes[0].dh = devdh1;
247  stripes[1].dh = devdh2;
248 
249  return TRUE;
250 }
251 
252 static BOOL find_new_stripe(device_extension* Vcb, stripe* stripes, UINT16 i, UINT64 max_stripe_size, BOOL allow_missing, BOOL full_size) {
253  UINT64 k, devusage = 0xffffffffffffffff;
254  space* devdh = NULL;
255  LIST_ENTRY* le;
256  device* dev2 = NULL;
257 
258  le = Vcb->devices.Flink;
259  while (le != &Vcb->devices) {
261  UINT64 usage;
262  BOOL skip = FALSE;
263 
264  if (dev->readonly || dev->reloc || (!dev->devobj && !allow_missing)) {
265  le = le->Flink;
266  continue;
267  }
268 
269  // skip this device if it already has a stripe
270  if (i > 0) {
271  for (k = 0; k < i; k++) {
272  if (stripes[k].device == dev) {
273  skip = TRUE;
274  break;
275  }
276  }
277  }
278 
279  if (!skip) {
280  usage = (dev->devitem.bytes_used * 4096) / dev->devitem.num_bytes;
281 
282  // favour devices which have been used the least
283  if (usage < devusage) {
284  if (!IsListEmpty(&dev->space)) {
285  LIST_ENTRY* le2;
286 
287  le2 = dev->space.Flink;
288  while (le2 != &dev->space) {
290 
291  if ((dev2 != dev && dh->size >= max_stripe_size) ||
292  (dev2 == dev && dh->size >= max_stripe_size && dh->size < devdh->size)
293  ) {
294  devdh = dh;
295  dev2 = dev;
296  devusage = usage;
297  }
298 
299  le2 = le2->Flink;
300  }
301  }
302  }
303  }
304 
305  le = le->Flink;
306  }
307 
308  if (!devdh) {
309  // Can't find hole of at least max_stripe_size; look for the largest one we can find
310 
311  if (full_size)
312  return FALSE;
313 
314  le = Vcb->devices.Flink;
315  while (le != &Vcb->devices) {
317  BOOL skip = FALSE;
318 
319  if (dev->readonly || dev->reloc || (!dev->devobj && !allow_missing)) {
320  le = le->Flink;
321  continue;
322  }
323 
324  // skip this device if it already has a stripe
325  if (i > 0) {
326  for (k = 0; k < i; k++) {
327  if (stripes[k].device == dev) {
328  skip = TRUE;
329  break;
330  }
331  }
332  }
333 
334  if (!skip) {
335  if (!IsListEmpty(&dev->space)) {
336  LIST_ENTRY* le2;
337 
338  le2 = dev->space.Flink;
339  while (le2 != &dev->space) {
341 
342  if (!devdh || devdh->size < dh->size) {
343  devdh = dh;
344  dev2 = dev;
345  }
346 
347  le2 = le2->Flink;
348  }
349  }
350  }
351 
352  le = le->Flink;
353  }
354 
355  if (!devdh)
356  return FALSE;
357  }
358 
359  stripes[i].dh = devdh;
360  stripes[i].device = dev2;
361 
362  return TRUE;
363 }
364 
367  UINT64 max_stripe_size, max_chunk_size, stripe_size, stripe_length, factor;
368  UINT64 total_size = 0, logaddr;
369  UINT16 i, type, num_stripes, sub_stripes, max_stripes, min_stripes, allowed_missing;
370  stripe* stripes = NULL;
371  UINT16 cisize;
372  CHUNK_ITEM_STRIPE* cis;
373  chunk* c = NULL;
374  space* s = NULL;
375  LIST_ENTRY* le;
376 
377  le = Vcb->devices.Flink;
378  while (le != &Vcb->devices) {
380  total_size += dev->devitem.num_bytes;
381 
382  le = le->Flink;
383  }
384 
385  TRACE("total_size = %llx\n", total_size);
386 
387  // We purposely check for DATA first - mixed blocks have the same size
388  // as DATA ones.
389  if (flags & BLOCK_FLAG_DATA) {
390  max_stripe_size = 0x40000000; // 1 GB
391  max_chunk_size = 10 * max_stripe_size;
392  } else if (flags & BLOCK_FLAG_METADATA) {
393  if (total_size > 0xC80000000) // 50 GB
394  max_stripe_size = 0x40000000; // 1 GB
395  else
396  max_stripe_size = 0x10000000; // 256 MB
397 
398  max_chunk_size = max_stripe_size;
399  } else if (flags & BLOCK_FLAG_SYSTEM) {
400  max_stripe_size = 0x2000000; // 32 MB
401  max_chunk_size = 2 * max_stripe_size;
402  } else {
403  ERR("unknown chunk type\n");
404  return STATUS_INTERNAL_ERROR;
405  }
406 
407  if (flags & BLOCK_FLAG_DUPLICATE) {
408  min_stripes = 2;
409  max_stripes = 2;
410  sub_stripes = 0;
412  allowed_missing = 0;
413  } else if (flags & BLOCK_FLAG_RAID0) {
414  min_stripes = 2;
415  max_stripes = (UINT16)min(0xffff, Vcb->superblock.num_devices);
416  sub_stripes = 0;
418  allowed_missing = 0;
419  } else if (flags & BLOCK_FLAG_RAID1) {
420  min_stripes = 2;
421  max_stripes = 2;
422  sub_stripes = 1;
424  allowed_missing = 1;
425  } else if (flags & BLOCK_FLAG_RAID10) {
426  min_stripes = 4;
427  max_stripes = (UINT16)min(0xffff, Vcb->superblock.num_devices);
428  sub_stripes = 2;
430  allowed_missing = 1;
431  } else if (flags & BLOCK_FLAG_RAID5) {
432  min_stripes = 3;
433  max_stripes = (UINT16)min(0xffff, Vcb->superblock.num_devices);
434  sub_stripes = 1;
436  allowed_missing = 1;
437  } else if (flags & BLOCK_FLAG_RAID6) {
438  min_stripes = 4;
439  max_stripes = 257;
440  sub_stripes = 1;
442  allowed_missing = 2;
443  } else { // SINGLE
444  min_stripes = 1;
445  max_stripes = 1;
446  sub_stripes = 1;
447  type = 0;
448  allowed_missing = 0;
449  }
450 
451  if (max_chunk_size > total_size / 10) { // cap at 10%
452  max_chunk_size = total_size / 10;
453  max_stripe_size = max_chunk_size / min_stripes;
454  }
455 
456  TRACE("would allocate a new chunk of %llx bytes and stripe %llx\n", max_chunk_size, max_stripe_size);
457 
458  stripes = ExAllocatePoolWithTag(PagedPool, sizeof(stripe) * max_stripes, ALLOC_TAG);
459  if (!stripes) {
460  ERR("out of memory\n");
462  goto end;
463  }
464 
465  num_stripes = 0;
466 
467  if (type == BLOCK_FLAG_DUPLICATE) {
468  if (!find_new_dup_stripes(Vcb, stripes, max_stripe_size, full_size)) {
470  goto end;
471  }
472  else
473  num_stripes = max_stripes;
474  } else {
475  for (i = 0; i < max_stripes; i++) {
476  if (!find_new_stripe(Vcb, stripes, i, max_stripe_size, FALSE, full_size))
477  break;
478  else
479  num_stripes++;
480  }
481  }
482 
483  if (num_stripes < min_stripes && Vcb->options.allow_degraded && allowed_missing > 0) {
484  UINT16 added_missing = 0;
485 
486  for (i = num_stripes; i < max_stripes; i++) {
487  if (!find_new_stripe(Vcb, stripes, i, max_stripe_size, TRUE, full_size))
488  break;
489  else {
490  added_missing++;
491  if (added_missing >= allowed_missing)
492  break;
493  }
494  }
495 
496  num_stripes += added_missing;
497  }
498 
499  // for RAID10, round down to an even number of stripes
500  if (type == BLOCK_FLAG_RAID10 && (num_stripes % sub_stripes) != 0) {
501  num_stripes -= num_stripes % sub_stripes;
502  }
503 
504  if (num_stripes < min_stripes) {
505  WARN("found %u stripes, needed at least %u\n", num_stripes, min_stripes);
507  goto end;
508  }
509 
511  if (!c) {
512  ERR("out of memory\n");
514  goto end;
515  }
516 
517  c->devices = NULL;
518 
519  cisize = sizeof(CHUNK_ITEM) + (num_stripes * sizeof(CHUNK_ITEM_STRIPE));
520  c->chunk_item = ExAllocatePoolWithTag(NonPagedPool, cisize, ALLOC_TAG);
521  if (!c->chunk_item) {
522  ERR("out of memory\n");
524  goto end;
525  }
526 
527  stripe_length = 0x10000; // FIXME? BTRFS_STRIPE_LEN in kernel
528 
529  if (type == BLOCK_FLAG_DUPLICATE && stripes[1].dh == stripes[0].dh)
530  stripe_size = min(stripes[0].dh->size / 2, max_stripe_size);
531  else {
532  stripe_size = max_stripe_size;
533  for (i = 0; i < num_stripes; i++) {
534  if (stripes[i].dh->size < stripe_size)
535  stripe_size = stripes[i].dh->size;
536  }
537  }
538 
539  if (type == 0 || type == BLOCK_FLAG_DUPLICATE || type == BLOCK_FLAG_RAID1)
540  factor = 1;
541  else if (type == BLOCK_FLAG_RAID0)
542  factor = num_stripes;
543  else if (type == BLOCK_FLAG_RAID10)
544  factor = num_stripes / sub_stripes;
545  else if (type == BLOCK_FLAG_RAID5)
546  factor = num_stripes - 1;
547  else if (type == BLOCK_FLAG_RAID6)
548  factor = num_stripes - 2;
549 
550  if (stripe_size * factor > max_chunk_size)
551  stripe_size = max_chunk_size / factor;
552 
553  if (stripe_size % stripe_length > 0)
554  stripe_size -= stripe_size % stripe_length;
555 
556  if (stripe_size == 0) {
557  ERR("not enough free space found (stripe_size == 0)\n");
559  goto end;
560  }
561 
562  c->chunk_item->size = stripe_size * factor;
563  c->chunk_item->root_id = Vcb->extent_root->id;
564  c->chunk_item->stripe_length = stripe_length;
565  c->chunk_item->type = flags;
566  c->chunk_item->opt_io_alignment = (UINT32)c->chunk_item->stripe_length;
567  c->chunk_item->opt_io_width = (UINT32)c->chunk_item->stripe_length;
568  c->chunk_item->sector_size = stripes[0].device->devitem.minimal_io_size;
569  c->chunk_item->num_stripes = num_stripes;
570  c->chunk_item->sub_stripes = sub_stripes;
571 
572  c->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * num_stripes, ALLOC_TAG);
573  if (!c->devices) {
574  ERR("out of memory\n");
576  goto end;
577  }
578 
579  cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
580  for (i = 0; i < num_stripes; i++) {
581  cis[i].dev_id = stripes[i].device->devitem.dev_id;
582 
583  if (type == BLOCK_FLAG_DUPLICATE && i == 1 && stripes[i].dh == stripes[0].dh)
584  cis[i].offset = stripes[0].dh->address + stripe_size;
585  else
586  cis[i].offset = stripes[i].dh->address;
587 
588  cis[i].dev_uuid = stripes[i].device->devitem.device_uuid;
589 
590  c->devices[i] = stripes[i].device;
591  }
592 
593  logaddr = find_new_chunk_address(Vcb, c->chunk_item->size);
594 
595  Vcb->superblock.chunk_root_generation = Vcb->superblock.generation;
596 
597  c->size = cisize;
598  c->offset = logaddr;
599  c->used = c->oldused = 0;
600  c->cache = c->old_cache = NULL;
601  c->readonly = FALSE;
602  c->reloc = FALSE;
603  c->last_alloc_set = FALSE;
604  c->last_stripe = 0;
605  c->cache_loaded = TRUE;
606  c->changed = FALSE;
607  c->space_changed = FALSE;
608  c->balance_num = 0;
609 
610  InitializeListHead(&c->space);
611  InitializeListHead(&c->space_size);
612  InitializeListHead(&c->deleting);
613  InitializeListHead(&c->changed_extents);
614 
615  InitializeListHead(&c->range_locks);
616  ExInitializeResourceLite(&c->range_locks_lock);
617  KeInitializeEvent(&c->range_locks_event, NotificationEvent, FALSE);
618 
619  InitializeListHead(&c->partial_stripes);
620  ExInitializeResourceLite(&c->partial_stripes_lock);
621 
622  ExInitializeResourceLite(&c->lock);
623  ExInitializeResourceLite(&c->changed_extents_lock);
624 
626  if (!s) {
627  ERR("out of memory\n");
629  goto end;
630  }
631 
632  s->address = c->offset;
633  s->size = c->chunk_item->size;
634  InsertTailList(&c->space, &s->list_entry);
635  InsertTailList(&c->space_size, &s->list_entry_size);
636 
638 
639  for (i = 0; i < num_stripes; i++) {
640  stripes[i].device->devitem.bytes_used += stripe_size;
641 
642  space_list_subtract2(&stripes[i].device->space, NULL, cis[i].offset, stripe_size, NULL, NULL);
643  }
644 
646 
648  Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_RAID56;
649 
650 end:
651  if (stripes)
652  ExFreePool(stripes);
653 
654  if (!NT_SUCCESS(Status)) {
655  if (c) {
656  if (c->devices)
657  ExFreePool(c->devices);
658 
659  if (c->chunk_item)
660  ExFreePool(c->chunk_item);
661 
662  ExFreePool(c);
663  }
664 
665  if (s) ExFreePool(s);
666  } else {
667  BOOL done = FALSE;
668 
669  le = Vcb->chunks.Flink;
670  while (le != &Vcb->chunks) {
672 
673  if (c2->offset > c->offset) {
674  InsertHeadList(le->Blink, &c->list_entry);
675  done = TRUE;
676  break;
677  }
678 
679  le = le->Flink;
680  }
681 
682  if (!done)
683  InsertTailList(&Vcb->chunks, &c->list_entry);
684 
685  c->created = TRUE;
686  c->changed = TRUE;
687  c->space_changed = TRUE;
688  c->list_entry_balance.Flink = NULL;
689 
690  *pc = c;
691  }
692 
693  return Status;
694 }
695 
696 static NTSTATUS prepare_raid0_write(_Pre_satisfies_(_Curr_->chunk_item->num_stripes>0) _In_ chunk* c, _In_ UINT64 address, _In_reads_bytes_(length) void* data,
698  UINT64 startoff, endoff;
699  UINT16 startoffstripe, endoffstripe, stripenum;
700  UINT64 pos, *stripeoff;
701  UINT32 i;
702  BOOL file_write = Irp && Irp->MdlAddress && (Irp->MdlAddress->ByteOffset == 0);
703  PMDL master_mdl;
704  PFN_NUMBER* pfns;
705 
706  stripeoff = ExAllocatePoolWithTag(PagedPool, sizeof(UINT64) * c->chunk_item->num_stripes, ALLOC_TAG);
707  if (!stripeoff) {
708  ERR("out of memory\n");
710  }
711 
712  get_raid0_offset(address - c->offset, c->chunk_item->stripe_length, c->chunk_item->num_stripes, &startoff, &startoffstripe);
713  get_raid0_offset(address + length - c->offset - 1, c->chunk_item->stripe_length, c->chunk_item->num_stripes, &endoff, &endoffstripe);
714 
715  if (file_write) {
716  master_mdl = Irp->MdlAddress;
717 
718  pfns = (PFN_NUMBER*)(Irp->MdlAddress + 1);
719  pfns = &pfns[irp_offset >> PAGE_SHIFT];
720  } else if (((ULONG_PTR)data % PAGE_SIZE) != 0) {
722  if (!wtc->scratch) {
723  ERR("out of memory\n");
725  }
726 
727  RtlCopyMemory(wtc->scratch, data, length);
728 
729  master_mdl = IoAllocateMdl(wtc->scratch, length, FALSE, FALSE, NULL);
730  if (!master_mdl) {
731  ERR("out of memory\n");
733  }
734 
735  MmBuildMdlForNonPagedPool(master_mdl);
736 
737  wtc->mdl = master_mdl;
738 
739  pfns = (PFN_NUMBER*)(master_mdl + 1);
740  } else {
742 
743  master_mdl = IoAllocateMdl(data, length, FALSE, FALSE, NULL);
744  if (!master_mdl) {
745  ERR("out of memory\n");
747  }
748 
749  _SEH2_TRY {
753  } _SEH2_END;
754 
755  if (!NT_SUCCESS(Status)) {
756  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
757  IoFreeMdl(master_mdl);
758  return Status;
759  }
760 
761  wtc->mdl = master_mdl;
762 
763  pfns = (PFN_NUMBER*)(master_mdl + 1);
764  }
765 
766  for (i = 0; i < c->chunk_item->num_stripes; i++) {
767  if (startoffstripe > i)
768  stripes[i].start = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
769  else if (startoffstripe == i)
770  stripes[i].start = startoff;
771  else
772  stripes[i].start = startoff - (startoff % c->chunk_item->stripe_length);
773 
774  if (endoffstripe > i)
775  stripes[i].end = endoff - (endoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
776  else if (endoffstripe == i)
777  stripes[i].end = endoff + 1;
778  else
779  stripes[i].end = endoff - (endoff % c->chunk_item->stripe_length);
780 
781  if (stripes[i].start != stripes[i].end) {
782  stripes[i].mdl = IoAllocateMdl(NULL, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
783  if (!stripes[i].mdl) {
784  ERR("IoAllocateMdl failed\n");
785  ExFreePool(stripeoff);
787  }
788  }
789  }
790 
791  pos = 0;
792  RtlZeroMemory(stripeoff, sizeof(UINT64) * c->chunk_item->num_stripes);
793 
794  stripenum = startoffstripe;
795 
796  while (pos < length) {
797  PFN_NUMBER* stripe_pfns = (PFN_NUMBER*)(stripes[stripenum].mdl + 1);
798 
799  if (pos == 0) {
800  UINT32 writelen = (UINT32)min(stripes[stripenum].end - stripes[stripenum].start,
801  c->chunk_item->stripe_length - (stripes[stripenum].start % c->chunk_item->stripe_length));
802 
803  RtlCopyMemory(stripe_pfns, pfns, writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
804 
805  stripeoff[stripenum] += writelen;
806  pos += writelen;
807  } else if (length - pos < c->chunk_item->stripe_length) {
808  RtlCopyMemory(&stripe_pfns[stripeoff[stripenum] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)((length - pos) * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
809  break;
810  } else {
811  RtlCopyMemory(&stripe_pfns[stripeoff[stripenum] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
812 
813  stripeoff[stripenum] += c->chunk_item->stripe_length;
814  pos += c->chunk_item->stripe_length;
815  }
816 
817  stripenum = (stripenum + 1) % c->chunk_item->num_stripes;
818  }
819 
820  ExFreePool(stripeoff);
821 
822  return STATUS_SUCCESS;
823 }
824 
825 static NTSTATUS prepare_raid10_write(_Pre_satisfies_(_Curr_->chunk_item->sub_stripes>0&&_Curr_->chunk_item->num_stripes>=_Curr_->chunk_item->sub_stripes) _In_ chunk* c,
828  UINT64 startoff, endoff;
829  UINT16 startoffstripe, endoffstripe, stripenum;
830  UINT64 pos, *stripeoff;
831  UINT32 i;
832  BOOL file_write = Irp && Irp->MdlAddress && (Irp->MdlAddress->ByteOffset == 0);
833  PMDL master_mdl;
834  PFN_NUMBER* pfns;
835 
836  get_raid0_offset(address - c->offset, c->chunk_item->stripe_length, c->chunk_item->num_stripes / c->chunk_item->sub_stripes, &startoff, &startoffstripe);
837  get_raid0_offset(address + length - c->offset - 1, c->chunk_item->stripe_length, c->chunk_item->num_stripes / c->chunk_item->sub_stripes, &endoff, &endoffstripe);
838 
839  stripenum = startoffstripe;
840  startoffstripe *= c->chunk_item->sub_stripes;
841  endoffstripe *= c->chunk_item->sub_stripes;
842 
843  if (file_write) {
844  master_mdl = Irp->MdlAddress;
845 
846  pfns = (PFN_NUMBER*)(Irp->MdlAddress + 1);
847  pfns = &pfns[irp_offset >> PAGE_SHIFT];
848  } else if (((ULONG_PTR)data % PAGE_SIZE) != 0) {
850  if (!wtc->scratch) {
851  ERR("out of memory\n");
853  }
854 
855  RtlCopyMemory(wtc->scratch, data, length);
856 
857  master_mdl = IoAllocateMdl(wtc->scratch, length, FALSE, FALSE, NULL);
858  if (!master_mdl) {
859  ERR("out of memory\n");
861  }
862 
863  MmBuildMdlForNonPagedPool(master_mdl);
864 
865  wtc->mdl = master_mdl;
866 
867  pfns = (PFN_NUMBER*)(master_mdl + 1);
868  } else {
870 
871  master_mdl = IoAllocateMdl(data, length, FALSE, FALSE, NULL);
872  if (!master_mdl) {
873  ERR("out of memory\n");
875  }
876 
877  _SEH2_TRY {
881  } _SEH2_END;
882 
883  if (!NT_SUCCESS(Status)) {
884  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
885  IoFreeMdl(master_mdl);
886  return Status;
887  }
888 
889  wtc->mdl = master_mdl;
890 
891  pfns = (PFN_NUMBER*)(master_mdl + 1);
892  }
893 
894  for (i = 0; i < c->chunk_item->num_stripes; i += c->chunk_item->sub_stripes) {
895  UINT16 j;
896 
897  if (startoffstripe > i)
898  stripes[i].start = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
899  else if (startoffstripe == i)
900  stripes[i].start = startoff;
901  else
902  stripes[i].start = startoff - (startoff % c->chunk_item->stripe_length);
903 
904  if (endoffstripe > i)
905  stripes[i].end = endoff - (endoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
906  else if (endoffstripe == i)
907  stripes[i].end = endoff + 1;
908  else
909  stripes[i].end = endoff - (endoff % c->chunk_item->stripe_length);
910 
911  stripes[i].mdl = IoAllocateMdl(NULL, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
912  if (!stripes[i].mdl) {
913  ERR("IoAllocateMdl failed\n");
915  }
916 
917  for (j = 1; j < c->chunk_item->sub_stripes; j++) {
918  stripes[i+j].start = stripes[i].start;
919  stripes[i+j].end = stripes[i].end;
920  stripes[i+j].data = stripes[i].data;
921  stripes[i+j].mdl = stripes[i].mdl;
922  }
923  }
924 
925  pos = 0;
926 
927  stripeoff = ExAllocatePoolWithTag(PagedPool, sizeof(UINT64) * c->chunk_item->num_stripes / c->chunk_item->sub_stripes, ALLOC_TAG);
928  if (!stripeoff) {
929  ERR("out of memory\n");
931  }
932 
933  RtlZeroMemory(stripeoff, sizeof(UINT64) * c->chunk_item->num_stripes / c->chunk_item->sub_stripes);
934 
935  while (pos < length) {
936  PFN_NUMBER* stripe_pfns = (PFN_NUMBER*)(stripes[stripenum * c->chunk_item->sub_stripes].mdl + 1);
937 
938  if (pos == 0) {
939  UINT32 writelen = (UINT32)min(stripes[stripenum * c->chunk_item->sub_stripes].end - stripes[stripenum * c->chunk_item->sub_stripes].start,
940  c->chunk_item->stripe_length - (stripes[stripenum * c->chunk_item->sub_stripes].start % c->chunk_item->stripe_length));
941 
942  RtlCopyMemory(stripe_pfns, pfns, writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
943 
944  stripeoff[stripenum] += writelen;
945  pos += writelen;
946  } else if (length - pos < c->chunk_item->stripe_length) {
947  RtlCopyMemory(&stripe_pfns[stripeoff[stripenum] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)((length - pos) * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
948  break;
949  } else {
950  RtlCopyMemory(&stripe_pfns[stripeoff[stripenum] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
951 
952  stripeoff[stripenum] += c->chunk_item->stripe_length;
953  pos += c->chunk_item->stripe_length;
954  }
955 
956  stripenum = (stripenum + 1) % (c->chunk_item->num_stripes / c->chunk_item->sub_stripes);
957  }
958 
959  ExFreePool(stripeoff);
960 
961  return STATUS_SUCCESS;
962 }
963 
966  LIST_ENTRY* le;
967  partial_stripe* ps;
968  UINT64 stripe_addr;
969  UINT16 num_data_stripes;
970  ULONG bmplen;
971 
972  num_data_stripes = c->chunk_item->num_stripes - (c->chunk_item->type & BLOCK_FLAG_RAID5 ? 1 : 2);
973  stripe_addr = address - ((address - c->offset) % (num_data_stripes * c->chunk_item->stripe_length));
974 
975  ExAcquireResourceExclusiveLite(&c->partial_stripes_lock, TRUE);
976 
977  le = c->partial_stripes.Flink;
978  while (le != &c->partial_stripes) {
980 
981  if (ps->address == stripe_addr) {
982  // update existing entry
983 
984  RtlCopyMemory(ps->data + address - stripe_addr, data, length);
985  RtlClearBits(&ps->bmp, (ULONG)((address - stripe_addr) / Vcb->superblock.sector_size), length / Vcb->superblock.sector_size);
986 
987  // if now filled, flush
988  if (RtlAreBitsClear(&ps->bmp, 0, (ULONG)((num_data_stripes * c->chunk_item->stripe_length) / Vcb->superblock.sector_size))) {
990  if (!NT_SUCCESS(Status)) {
991  ERR("flush_partial_stripe returned %08x\n", Status);
992  goto end;
993  }
994 
996 
997  if (ps->bmparr)
998  ExFreePool(ps->bmparr);
999 
1000  ExFreePool(ps);
1001  }
1002 
1004  goto end;
1005  } else if (ps->address > stripe_addr)
1006  break;
1007 
1008  le = le->Flink;
1009  }
1010 
1011  // add new entry
1012 
1013  ps = ExAllocatePoolWithTag(NonPagedPool, offsetof(partial_stripe, data[0]) + (ULONG)(num_data_stripes * c->chunk_item->stripe_length), ALLOC_TAG);
1014  if (!ps) {
1015  ERR("out of memory\n");
1017  goto end;
1018  }
1019 
1020  bmplen = (ULONG)sector_align(((num_data_stripes * c->chunk_item->stripe_length) / (8 * Vcb->superblock.sector_size) + 1), sizeof(ULONG));
1021 
1022  ps->address = stripe_addr;
1024  if (!ps->bmparr) {
1025  ERR("out of memory\n");
1026  ExFreePool(ps);
1028  goto end;
1029  }
1030 
1031  RtlInitializeBitMap(&ps->bmp, ps->bmparr, (ULONG)((num_data_stripes * c->chunk_item->stripe_length) / Vcb->superblock.sector_size));
1032  RtlSetAllBits(&ps->bmp);
1033 
1034  RtlCopyMemory(ps->data + address - stripe_addr, data, length);
1035  RtlClearBits(&ps->bmp, (ULONG)((address - stripe_addr) / Vcb->superblock.sector_size), length / Vcb->superblock.sector_size);
1036 
1037  InsertHeadList(le->Blink, &ps->list_entry);
1038 
1040 
1041 end:
1042  ExReleaseResourceLite(&c->partial_stripes_lock);
1043 
1044  return Status;
1045 }
1046 
1047 typedef struct {
1050 } log_stripe;
1051 
1054  UINT64 startoff, endoff, parity_start, parity_end;
1055  UINT16 startoffstripe, endoffstripe, parity, num_data_stripes = c->chunk_item->num_stripes - 1;
1056  UINT64 pos, parity_pos, *stripeoff = NULL;
1057  UINT32 i;
1058  BOOL file_write = Irp && Irp->MdlAddress && (Irp->MdlAddress->ByteOffset == 0);
1059  PMDL master_mdl;
1060  NTSTATUS Status;
1061  PFN_NUMBER *pfns, *parity_pfns;
1062  log_stripe* log_stripes = NULL;
1063 
1064  if ((address + length - c->offset) % (num_data_stripes * c->chunk_item->stripe_length) > 0) {
1065  UINT64 delta = (address + length - c->offset) % (num_data_stripes * c->chunk_item->stripe_length);
1066 
1067  delta = min(irp_offset + length, delta);
1068  Status = add_partial_stripe(Vcb, c, address + length - delta, (UINT32)delta, (UINT8*)data + irp_offset + length - delta);
1069  if (!NT_SUCCESS(Status)) {
1070  ERR("add_partial_stripe returned %08x\n", Status);
1071  goto exit;
1072  }
1073 
1074  length -= (UINT32)delta;
1075  }
1076 
1077  if (length > 0 && (address - c->offset) % (num_data_stripes * c->chunk_item->stripe_length) > 0) {
1078  UINT64 delta = (num_data_stripes * c->chunk_item->stripe_length) - ((address - c->offset) % (num_data_stripes * c->chunk_item->stripe_length));
1079 
1081  if (!NT_SUCCESS(Status)) {
1082  ERR("add_partial_stripe returned %08x\n", Status);
1083  goto exit;
1084  }
1085 
1086  address += delta;
1087  length -= (UINT32)delta;
1088  irp_offset += delta;
1089  }
1090 
1091  if (length == 0) {
1093  goto exit;
1094  }
1095 
1096  get_raid0_offset(address - c->offset, c->chunk_item->stripe_length, num_data_stripes, &startoff, &startoffstripe);
1097  get_raid0_offset(address + length - c->offset - 1, c->chunk_item->stripe_length, num_data_stripes, &endoff, &endoffstripe);
1098 
1099  pos = 0;
1100  while (pos < length) {
1101  parity = (((address - c->offset + pos) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1102 
1103  if (pos == 0) {
1104  UINT16 stripe = (parity + startoffstripe + 1) % c->chunk_item->num_stripes;
1105  ULONG skip, writelen;
1106 
1107  i = startoffstripe;
1108  while (stripe != parity) {
1109  if (i == startoffstripe) {
1110  writelen = (ULONG)min(length, c->chunk_item->stripe_length - (startoff % c->chunk_item->stripe_length));
1111 
1112  stripes[stripe].start = startoff;
1113  stripes[stripe].end = startoff + writelen;
1114 
1115  pos += writelen;
1116 
1117  if (pos == length)
1118  break;
1119  } else {
1120  writelen = (ULONG)min(length - pos, c->chunk_item->stripe_length);
1121 
1122  stripes[stripe].start = startoff - (startoff % c->chunk_item->stripe_length);
1123  stripes[stripe].end = stripes[stripe].start + writelen;
1124 
1125  pos += writelen;
1126 
1127  if (pos == length)
1128  break;
1129  }
1130 
1131  i++;
1132  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1133  }
1134 
1135  if (pos == length)
1136  break;
1137 
1138  for (i = 0; i < startoffstripe; i++) {
1139  stripe = (parity + i + 1) % c->chunk_item->num_stripes;
1140 
1141  stripes[stripe].start = stripes[stripe].end = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
1142  }
1143 
1144  stripes[parity].start = stripes[parity].end = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
1145 
1146  if (length - pos > c->chunk_item->num_stripes * num_data_stripes * c->chunk_item->stripe_length) {
1147  skip = (ULONG)(((length - pos) / (c->chunk_item->num_stripes * num_data_stripes * c->chunk_item->stripe_length)) - 1);
1148 
1149  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1150  stripes[i].end += skip * c->chunk_item->num_stripes * c->chunk_item->stripe_length;
1151  }
1152 
1153  pos += skip * num_data_stripes * c->chunk_item->num_stripes * c->chunk_item->stripe_length;
1154  }
1155  } else if (length - pos >= c->chunk_item->stripe_length * num_data_stripes) {
1156  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1157  stripes[i].end += c->chunk_item->stripe_length;
1158  }
1159 
1160  pos += c->chunk_item->stripe_length * num_data_stripes;
1161  } else {
1162  UINT16 stripe = (parity + 1) % c->chunk_item->num_stripes;
1163 
1164  i = 0;
1165  while (stripe != parity) {
1166  if (endoffstripe == i) {
1167  stripes[stripe].end = endoff + 1;
1168  break;
1169  } else if (endoffstripe > i)
1170  stripes[stripe].end = endoff - (endoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
1171 
1172  i++;
1173  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1174  }
1175 
1176  break;
1177  }
1178  }
1179 
1180  parity_start = 0xffffffffffffffff;
1181  parity_end = 0;
1182 
1183  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1184  if (stripes[i].start != 0 || stripes[i].end != 0) {
1185  parity_start = min(stripes[i].start, parity_start);
1186  parity_end = max(stripes[i].end, parity_end);
1187  }
1188  }
1189 
1190  if (parity_end == parity_start) {
1192  goto exit;
1193  }
1194 
1195  parity = (((address - c->offset) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1196  stripes[parity].start = parity_start;
1197 
1198  parity = (((address - c->offset + length - 1) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1199  stripes[parity].end = parity_end;
1200 
1201  log_stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(log_stripe) * num_data_stripes, ALLOC_TAG);
1202  if (!log_stripes) {
1203  ERR("out of memory\n");
1205  goto exit;
1206  }
1207 
1208  RtlZeroMemory(log_stripes, sizeof(log_stripe) * num_data_stripes);
1209 
1210  for (i = 0; i < num_data_stripes; i++) {
1211  log_stripes[i].mdl = IoAllocateMdl(NULL, (ULONG)(parity_end - parity_start), FALSE, FALSE, NULL);
1212  if (!log_stripes[i].mdl) {
1213  ERR("out of memory\n");
1215  goto exit;
1216  }
1217 
1218  log_stripes[i].mdl->MdlFlags |= MDL_PARTIAL;
1219  log_stripes[i].pfns = (PFN_NUMBER*)(log_stripes[i].mdl + 1);
1220  }
1221 
1222  wtc->parity1 = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(parity_end - parity_start), ALLOC_TAG);
1223  if (!wtc->parity1) {
1224  ERR("out of memory\n");
1226  goto exit;
1227  }
1228 
1229  wtc->parity1_mdl = IoAllocateMdl(wtc->parity1, (ULONG)(parity_end - parity_start), FALSE, FALSE, NULL);
1230  if (!wtc->parity1_mdl) {
1231  ERR("out of memory\n");
1233  goto exit;
1234  }
1235 
1237 
1238  if (file_write)
1239  master_mdl = Irp->MdlAddress;
1240  else if (((ULONG_PTR)data % PAGE_SIZE) != 0) {
1242  if (!wtc->scratch) {
1243  ERR("out of memory\n");
1245  goto exit;
1246  }
1247 
1249 
1250  master_mdl = IoAllocateMdl(wtc->scratch, length, FALSE, FALSE, NULL);
1251  if (!master_mdl) {
1252  ERR("out of memory\n");
1254  goto exit;
1255  }
1256 
1257  MmBuildMdlForNonPagedPool(master_mdl);
1258 
1259  wtc->mdl = master_mdl;
1260  } else {
1261  master_mdl = IoAllocateMdl((UINT8*)data + irp_offset, length, FALSE, FALSE, NULL);
1262  if (!master_mdl) {
1263  ERR("out of memory\n");
1265  goto exit;
1266  }
1267 
1269 
1270  _SEH2_TRY {
1274  } _SEH2_END;
1275 
1276  if (!NT_SUCCESS(Status)) {
1277  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
1278  IoFreeMdl(master_mdl);
1279  return Status;
1280  }
1281 
1282  wtc->mdl = master_mdl;
1283  }
1284 
1285  pfns = (PFN_NUMBER*)(master_mdl + 1);
1286  parity_pfns = (PFN_NUMBER*)(wtc->parity1_mdl + 1);
1287 
1288  if (file_write)
1289  pfns = &pfns[irp_offset >> PAGE_SHIFT];
1290 
1291  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1292  if (stripes[i].start != stripes[i].end) {
1293  stripes[i].mdl = IoAllocateMdl((UINT8*)MmGetMdlVirtualAddress(master_mdl) + irp_offset, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
1294  if (!stripes[i].mdl) {
1295  ERR("IoAllocateMdl failed\n");
1297  goto exit;
1298  }
1299  }
1300  }
1301 
1302  stripeoff = ExAllocatePoolWithTag(PagedPool, sizeof(UINT64) * c->chunk_item->num_stripes, ALLOC_TAG);
1303  if (!stripeoff) {
1304  ERR("out of memory\n");
1306  goto exit;
1307  }
1308 
1309  RtlZeroMemory(stripeoff, sizeof(UINT64) * c->chunk_item->num_stripes);
1310 
1311  pos = 0;
1312  parity_pos = 0;
1313 
1314  while (pos < length) {
1315  PFN_NUMBER* stripe_pfns;
1316 
1317  parity = (((address - c->offset + pos) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1318 
1319  if (pos == 0) {
1320  UINT16 stripe = (parity + startoffstripe + 1) % c->chunk_item->num_stripes;
1321  UINT32 writelen = (UINT32)min(length - pos, min(stripes[stripe].end - stripes[stripe].start,
1322  c->chunk_item->stripe_length - (stripes[stripe].start % c->chunk_item->stripe_length)));
1323  UINT32 maxwritelen = writelen;
1324 
1325  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1326 
1327  RtlCopyMemory(stripe_pfns, pfns, writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1328 
1329  RtlCopyMemory(log_stripes[startoffstripe].pfns, pfns, writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1330  log_stripes[startoffstripe].pfns += writelen >> PAGE_SHIFT;
1331 
1332  stripeoff[stripe] = writelen;
1333  pos += writelen;
1334 
1335  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1336  i = startoffstripe + 1;
1337 
1338  while (stripe != parity) {
1339  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1340  writelen = (UINT32)min(length - pos, min(stripes[stripe].end - stripes[stripe].start, c->chunk_item->stripe_length));
1341 
1342  if (writelen == 0)
1343  break;
1344 
1345  if (writelen > maxwritelen)
1346  maxwritelen = writelen;
1347 
1348  RtlCopyMemory(stripe_pfns, &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1349 
1350  RtlCopyMemory(log_stripes[i].pfns, &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1351  log_stripes[i].pfns += writelen >> PAGE_SHIFT;
1352 
1353  stripeoff[stripe] = writelen;
1354  pos += writelen;
1355 
1356  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1357  i++;
1358  }
1359 
1360  stripe_pfns = (PFN_NUMBER*)(stripes[parity].mdl + 1);
1361 
1362  RtlCopyMemory(stripe_pfns, parity_pfns, maxwritelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1363  stripeoff[parity] = maxwritelen;
1364  parity_pos = maxwritelen;
1365  } else if (length - pos >= c->chunk_item->stripe_length * num_data_stripes) {
1366  UINT16 stripe = (parity + 1) % c->chunk_item->num_stripes;
1367 
1368  i = 0;
1369  while (stripe != parity) {
1370  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1371 
1372  RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1373 
1374  RtlCopyMemory(log_stripes[i].pfns, &pfns[pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1375  log_stripes[i].pfns += c->chunk_item->stripe_length >> PAGE_SHIFT;
1376 
1377  stripeoff[stripe] += c->chunk_item->stripe_length;
1378  pos += c->chunk_item->stripe_length;
1379 
1380  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1381  i++;
1382  }
1383 
1384  stripe_pfns = (PFN_NUMBER*)(stripes[parity].mdl + 1);
1385 
1386  RtlCopyMemory(&stripe_pfns[stripeoff[parity] >> PAGE_SHIFT], &parity_pfns[parity_pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1387  stripeoff[parity] += c->chunk_item->stripe_length;
1388  parity_pos += c->chunk_item->stripe_length;
1389  } else {
1390  UINT16 stripe = (parity + 1) % c->chunk_item->num_stripes;
1391  UINT32 writelen, maxwritelen = 0;
1392 
1393  i = 0;
1394  while (pos < length) {
1395  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1396  writelen = (UINT32)min(length - pos, min(stripes[stripe].end - stripes[stripe].start, c->chunk_item->stripe_length));
1397 
1398  if (writelen == 0)
1399  break;
1400 
1401  if (writelen > maxwritelen)
1402  maxwritelen = writelen;
1403 
1404  RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1405 
1406  RtlCopyMemory(log_stripes[i].pfns, &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1407  log_stripes[i].pfns += writelen >> PAGE_SHIFT;
1408 
1409  stripeoff[stripe] += writelen;
1410  pos += writelen;
1411 
1412  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1413  i++;
1414  }
1415 
1416  stripe_pfns = (PFN_NUMBER*)(stripes[parity].mdl + 1);
1417 
1418  RtlCopyMemory(&stripe_pfns[stripeoff[parity] >> PAGE_SHIFT], &parity_pfns[parity_pos >> PAGE_SHIFT], maxwritelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1419  }
1420  }
1421 
1422  for (i = 0; i < num_data_stripes; i++) {
1423  UINT8* ss = MmGetSystemAddressForMdlSafe(log_stripes[i].mdl, priority);
1424 
1425  if (i == 0)
1426  RtlCopyMemory(wtc->parity1, ss, (UINT32)(parity_end - parity_start));
1427  else
1428  do_xor(wtc->parity1, ss, (UINT32)(parity_end - parity_start));
1429  }
1430 
1432 
1433 exit:
1434  if (log_stripes) {
1435  for (i = 0; i < num_data_stripes; i++) {
1436  if (log_stripes[i].mdl)
1437  IoFreeMdl(log_stripes[i].mdl);
1438  }
1439 
1440  ExFreePool(log_stripes);
1441  }
1442 
1443  if (stripeoff)
1444  ExFreePool(stripeoff);
1445 
1446  return Status;
1447 }
1448 
1451  UINT64 startoff, endoff, parity_start, parity_end;
1452  UINT16 startoffstripe, endoffstripe, parity1, num_data_stripes = c->chunk_item->num_stripes - 2;
1453  UINT64 pos, parity_pos, *stripeoff = NULL;
1454  UINT32 i;
1455  BOOL file_write = Irp && Irp->MdlAddress && (Irp->MdlAddress->ByteOffset == 0);
1456  PMDL master_mdl;
1457  NTSTATUS Status;
1458  PFN_NUMBER *pfns, *parity1_pfns, *parity2_pfns;
1459  log_stripe* log_stripes = NULL;
1460 
1461  if ((address + length - c->offset) % (num_data_stripes * c->chunk_item->stripe_length) > 0) {
1462  UINT64 delta = (address + length - c->offset) % (num_data_stripes * c->chunk_item->stripe_length);
1463 
1464  delta = min(irp_offset + length, delta);
1465  Status = add_partial_stripe(Vcb, c, address + length - delta, (UINT32)delta, (UINT8*)data + irp_offset + length - delta);
1466  if (!NT_SUCCESS(Status)) {
1467  ERR("add_partial_stripe returned %08x\n", Status);
1468  goto exit;
1469  }
1470 
1471  length -= (UINT32)delta;
1472  }
1473 
1474  if (length > 0 && (address - c->offset) % (num_data_stripes * c->chunk_item->stripe_length) > 0) {
1475  UINT64 delta = (num_data_stripes * c->chunk_item->stripe_length) - ((address - c->offset) % (num_data_stripes * c->chunk_item->stripe_length));
1476 
1478  if (!NT_SUCCESS(Status)) {
1479  ERR("add_partial_stripe returned %08x\n", Status);
1480  goto exit;
1481  }
1482 
1483  address += delta;
1484  length -= (UINT32)delta;
1485  irp_offset += delta;
1486  }
1487 
1488  if (length == 0) {
1490  goto exit;
1491  }
1492 
1493  get_raid0_offset(address - c->offset, c->chunk_item->stripe_length, num_data_stripes, &startoff, &startoffstripe);
1494  get_raid0_offset(address + length - c->offset - 1, c->chunk_item->stripe_length, num_data_stripes, &endoff, &endoffstripe);
1495 
1496  pos = 0;
1497  while (pos < length) {
1498  parity1 = (((address - c->offset + pos) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1499 
1500  if (pos == 0) {
1501  UINT16 stripe = (parity1 + startoffstripe + 2) % c->chunk_item->num_stripes;
1502  UINT16 parity2 = (parity1 + 1) % c->chunk_item->num_stripes;
1503  ULONG skip, writelen;
1504 
1505  i = startoffstripe;
1506  while (stripe != parity1) {
1507  if (i == startoffstripe) {
1508  writelen = (ULONG)min(length, c->chunk_item->stripe_length - (startoff % c->chunk_item->stripe_length));
1509 
1510  stripes[stripe].start = startoff;
1511  stripes[stripe].end = startoff + writelen;
1512 
1513  pos += writelen;
1514 
1515  if (pos == length)
1516  break;
1517  } else {
1518  writelen = (ULONG)min(length - pos, c->chunk_item->stripe_length);
1519 
1520  stripes[stripe].start = startoff - (startoff % c->chunk_item->stripe_length);
1521  stripes[stripe].end = stripes[stripe].start + writelen;
1522 
1523  pos += writelen;
1524 
1525  if (pos == length)
1526  break;
1527  }
1528 
1529  i++;
1530  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1531  }
1532 
1533  if (pos == length)
1534  break;
1535 
1536  for (i = 0; i < startoffstripe; i++) {
1537  stripe = (parity1 + i + 2) % c->chunk_item->num_stripes;
1538 
1539  stripes[stripe].start = stripes[stripe].end = startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
1540  }
1541 
1542  stripes[parity1].start = stripes[parity1].end = stripes[parity2].start = stripes[parity2].end =
1543  startoff - (startoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
1544 
1545  if (length - pos > c->chunk_item->num_stripes * num_data_stripes * c->chunk_item->stripe_length) {
1546  skip = (ULONG)(((length - pos) / (c->chunk_item->num_stripes * num_data_stripes * c->chunk_item->stripe_length)) - 1);
1547 
1548  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1549  stripes[i].end += skip * c->chunk_item->num_stripes * c->chunk_item->stripe_length;
1550  }
1551 
1552  pos += skip * num_data_stripes * c->chunk_item->num_stripes * c->chunk_item->stripe_length;
1553  }
1554  } else if (length - pos >= c->chunk_item->stripe_length * num_data_stripes) {
1555  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1556  stripes[i].end += c->chunk_item->stripe_length;
1557  }
1558 
1559  pos += c->chunk_item->stripe_length * num_data_stripes;
1560  } else {
1561  UINT16 stripe = (parity1 + 2) % c->chunk_item->num_stripes;
1562 
1563  i = 0;
1564  while (stripe != parity1) {
1565  if (endoffstripe == i) {
1566  stripes[stripe].end = endoff + 1;
1567  break;
1568  } else if (endoffstripe > i)
1569  stripes[stripe].end = endoff - (endoff % c->chunk_item->stripe_length) + c->chunk_item->stripe_length;
1570 
1571  i++;
1572  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1573  }
1574 
1575  break;
1576  }
1577  }
1578 
1579  parity_start = 0xffffffffffffffff;
1580  parity_end = 0;
1581 
1582  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1583  if (stripes[i].start != 0 || stripes[i].end != 0) {
1584  parity_start = min(stripes[i].start, parity_start);
1585  parity_end = max(stripes[i].end, parity_end);
1586  }
1587  }
1588 
1589  if (parity_end == parity_start) {
1591  goto exit;
1592  }
1593 
1594  parity1 = (((address - c->offset) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1595  stripes[parity1].start = stripes[(parity1 + 1) % c->chunk_item->num_stripes].start = parity_start;
1596 
1597  parity1 = (((address - c->offset + length - 1) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1598  stripes[parity1].end = stripes[(parity1 + 1) % c->chunk_item->num_stripes].end = parity_end;
1599 
1600  log_stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(log_stripe) * num_data_stripes, ALLOC_TAG);
1601  if (!log_stripes) {
1602  ERR("out of memory\n");
1604  goto exit;
1605  }
1606 
1607  RtlZeroMemory(log_stripes, sizeof(log_stripe) * num_data_stripes);
1608 
1609  for (i = 0; i < num_data_stripes; i++) {
1610  log_stripes[i].mdl = IoAllocateMdl(NULL, (ULONG)(parity_end - parity_start), FALSE, FALSE, NULL);
1611  if (!log_stripes[i].mdl) {
1612  ERR("out of memory\n");
1614  goto exit;
1615  }
1616 
1617  log_stripes[i].mdl->MdlFlags |= MDL_PARTIAL;
1618  log_stripes[i].pfns = (PFN_NUMBER*)(log_stripes[i].mdl + 1);
1619  }
1620 
1621  wtc->parity1 = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(parity_end - parity_start), ALLOC_TAG);
1622  if (!wtc->parity1) {
1623  ERR("out of memory\n");
1625  goto exit;
1626  }
1627 
1628  wtc->parity2 = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(parity_end - parity_start), ALLOC_TAG);
1629  if (!wtc->parity2) {
1630  ERR("out of memory\n");
1632  goto exit;
1633  }
1634 
1635  wtc->parity1_mdl = IoAllocateMdl(wtc->parity1, (ULONG)(parity_end - parity_start), FALSE, FALSE, NULL);
1636  if (!wtc->parity1_mdl) {
1637  ERR("out of memory\n");
1639  goto exit;
1640  }
1641 
1643 
1644  wtc->parity2_mdl = IoAllocateMdl(wtc->parity2, (ULONG)(parity_end - parity_start), FALSE, FALSE, NULL);
1645  if (!wtc->parity2_mdl) {
1646  ERR("out of memory\n");
1648  goto exit;
1649  }
1650 
1652 
1653  if (file_write)
1654  master_mdl = Irp->MdlAddress;
1655  else if (((ULONG_PTR)data % PAGE_SIZE) != 0) {
1657  if (!wtc->scratch) {
1658  ERR("out of memory\n");
1660  goto exit;
1661  }
1662 
1664 
1665  master_mdl = IoAllocateMdl(wtc->scratch, length, FALSE, FALSE, NULL);
1666  if (!master_mdl) {
1667  ERR("out of memory\n");
1669  goto exit;
1670  }
1671 
1672  MmBuildMdlForNonPagedPool(master_mdl);
1673 
1674  wtc->mdl = master_mdl;
1675  } else {
1676  master_mdl = IoAllocateMdl((UINT8*)data + irp_offset, length, FALSE, FALSE, NULL);
1677  if (!master_mdl) {
1678  ERR("out of memory\n");
1680  goto exit;
1681  }
1682 
1684 
1685  _SEH2_TRY {
1689  } _SEH2_END;
1690 
1691  if (!NT_SUCCESS(Status)) {
1692  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
1693  IoFreeMdl(master_mdl);
1694  goto exit;
1695  }
1696 
1697  wtc->mdl = master_mdl;
1698  }
1699 
1700  pfns = (PFN_NUMBER*)(master_mdl + 1);
1701  parity1_pfns = (PFN_NUMBER*)(wtc->parity1_mdl + 1);
1702  parity2_pfns = (PFN_NUMBER*)(wtc->parity2_mdl + 1);
1703 
1704  if (file_write)
1705  pfns = &pfns[irp_offset >> PAGE_SHIFT];
1706 
1707  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1708  if (stripes[i].start != stripes[i].end) {
1709  stripes[i].mdl = IoAllocateMdl((UINT8*)MmGetMdlVirtualAddress(master_mdl) + irp_offset, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
1710  if (!stripes[i].mdl) {
1711  ERR("IoAllocateMdl failed\n");
1713  goto exit;
1714  }
1715  }
1716  }
1717 
1718  stripeoff = ExAllocatePoolWithTag(PagedPool, sizeof(UINT64) * c->chunk_item->num_stripes, ALLOC_TAG);
1719  if (!stripeoff) {
1720  ERR("out of memory\n");
1722  goto exit;
1723  }
1724 
1725  RtlZeroMemory(stripeoff, sizeof(UINT64) * c->chunk_item->num_stripes);
1726 
1727  pos = 0;
1728  parity_pos = 0;
1729 
1730  while (pos < length) {
1731  PFN_NUMBER* stripe_pfns;
1732 
1733  parity1 = (((address - c->offset + pos) / (num_data_stripes * c->chunk_item->stripe_length)) + num_data_stripes) % c->chunk_item->num_stripes;
1734 
1735  if (pos == 0) {
1736  UINT16 stripe = (parity1 + startoffstripe + 2) % c->chunk_item->num_stripes, parity2;
1737  UINT32 writelen = (UINT32)min(length - pos, min(stripes[stripe].end - stripes[stripe].start,
1738  c->chunk_item->stripe_length - (stripes[stripe].start % c->chunk_item->stripe_length)));
1739  UINT32 maxwritelen = writelen;
1740 
1741  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1742 
1743  RtlCopyMemory(stripe_pfns, pfns, writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1744 
1745  RtlCopyMemory(log_stripes[startoffstripe].pfns, pfns, writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1746  log_stripes[startoffstripe].pfns += writelen >> PAGE_SHIFT;
1747 
1748  stripeoff[stripe] = writelen;
1749  pos += writelen;
1750 
1751  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1752  i = startoffstripe + 1;
1753 
1754  while (stripe != parity1) {
1755  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1756  writelen = (UINT32)min(length - pos, min(stripes[stripe].end - stripes[stripe].start, c->chunk_item->stripe_length));
1757 
1758  if (writelen == 0)
1759  break;
1760 
1761  if (writelen > maxwritelen)
1762  maxwritelen = writelen;
1763 
1764  RtlCopyMemory(stripe_pfns, &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1765 
1766  RtlCopyMemory(log_stripes[i].pfns, &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1767  log_stripes[i].pfns += writelen >> PAGE_SHIFT;
1768 
1769  stripeoff[stripe] = writelen;
1770  pos += writelen;
1771 
1772  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1773  i++;
1774  }
1775 
1776  stripe_pfns = (PFN_NUMBER*)(stripes[parity1].mdl + 1);
1777  RtlCopyMemory(stripe_pfns, parity1_pfns, maxwritelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1778  stripeoff[parity1] = maxwritelen;
1779 
1780  parity2 = (parity1 + 1) % c->chunk_item->num_stripes;
1781 
1782  stripe_pfns = (PFN_NUMBER*)(stripes[parity2].mdl + 1);
1783  RtlCopyMemory(stripe_pfns, parity2_pfns, maxwritelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1784  stripeoff[parity2] = maxwritelen;
1785 
1786  parity_pos = maxwritelen;
1787  } else if (length - pos >= c->chunk_item->stripe_length * num_data_stripes) {
1788  UINT16 stripe = (parity1 + 2) % c->chunk_item->num_stripes, parity2;
1789 
1790  i = 0;
1791  while (stripe != parity1) {
1792  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1793 
1794  RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1795 
1796  RtlCopyMemory(log_stripes[i].pfns, &pfns[pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1797  log_stripes[i].pfns += c->chunk_item->stripe_length >> PAGE_SHIFT;
1798 
1799  stripeoff[stripe] += c->chunk_item->stripe_length;
1800  pos += c->chunk_item->stripe_length;
1801 
1802  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1803  i++;
1804  }
1805 
1806  stripe_pfns = (PFN_NUMBER*)(stripes[parity1].mdl + 1);
1807  RtlCopyMemory(&stripe_pfns[stripeoff[parity1] >> PAGE_SHIFT], &parity1_pfns[parity_pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1808  stripeoff[parity1] += c->chunk_item->stripe_length;
1809 
1810  parity2 = (parity1 + 1) % c->chunk_item->num_stripes;
1811 
1812  stripe_pfns = (PFN_NUMBER*)(stripes[parity2].mdl + 1);
1813  RtlCopyMemory(&stripe_pfns[stripeoff[parity2] >> PAGE_SHIFT], &parity2_pfns[parity_pos >> PAGE_SHIFT], (ULONG)(c->chunk_item->stripe_length * sizeof(PFN_NUMBER) >> PAGE_SHIFT));
1814  stripeoff[parity2] += c->chunk_item->stripe_length;
1815 
1816  parity_pos += c->chunk_item->stripe_length;
1817  } else {
1818  UINT16 stripe = (parity1 + 2) % c->chunk_item->num_stripes, parity2;
1819  UINT32 writelen, maxwritelen = 0;
1820 
1821  i = 0;
1822  while (pos < length) {
1823  stripe_pfns = (PFN_NUMBER*)(stripes[stripe].mdl + 1);
1824  writelen = (UINT32)min(length - pos, min(stripes[stripe].end - stripes[stripe].start, c->chunk_item->stripe_length));
1825 
1826  if (writelen == 0)
1827  break;
1828 
1829  if (writelen > maxwritelen)
1830  maxwritelen = writelen;
1831 
1832  RtlCopyMemory(&stripe_pfns[stripeoff[stripe] >> PAGE_SHIFT], &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1833 
1834  RtlCopyMemory(log_stripes[i].pfns, &pfns[pos >> PAGE_SHIFT], writelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1835  log_stripes[i].pfns += writelen >> PAGE_SHIFT;
1836 
1837  stripeoff[stripe] += writelen;
1838  pos += writelen;
1839 
1840  stripe = (stripe + 1) % c->chunk_item->num_stripes;
1841  i++;
1842  }
1843 
1844  stripe_pfns = (PFN_NUMBER*)(stripes[parity1].mdl + 1);
1845  RtlCopyMemory(&stripe_pfns[stripeoff[parity1] >> PAGE_SHIFT], &parity1_pfns[parity_pos >> PAGE_SHIFT], maxwritelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1846 
1847  parity2 = (parity1 + 1) % c->chunk_item->num_stripes;
1848 
1849  stripe_pfns = (PFN_NUMBER*)(stripes[parity2].mdl + 1);
1850  RtlCopyMemory(&stripe_pfns[stripeoff[parity2] >> PAGE_SHIFT], &parity2_pfns[parity_pos >> PAGE_SHIFT], maxwritelen * sizeof(PFN_NUMBER) >> PAGE_SHIFT);
1851  }
1852  }
1853 
1854  for (i = 0; i < num_data_stripes; i++) {
1855  UINT8* ss = MmGetSystemAddressForMdlSafe(log_stripes[c->chunk_item->num_stripes - 3 - i].mdl, priority);
1856 
1857  if (i == 0) {
1858  RtlCopyMemory(wtc->parity1, ss, (ULONG)(parity_end - parity_start));
1859  RtlCopyMemory(wtc->parity2, ss, (ULONG)(parity_end - parity_start));
1860  } else {
1861  do_xor(wtc->parity1, ss, (UINT32)(parity_end - parity_start));
1862 
1863  galois_double(wtc->parity2, (UINT32)(parity_end - parity_start));
1864  do_xor(wtc->parity2, ss, (UINT32)(parity_end - parity_start));
1865  }
1866  }
1867 
1869 
1870 exit:
1871  if (log_stripes) {
1872  for (i = 0; i < num_data_stripes; i++) {
1873  if (log_stripes[i].mdl)
1874  IoFreeMdl(log_stripes[i].mdl);
1875  }
1876 
1877  ExFreePool(log_stripes);
1878  }
1879 
1880  if (stripeoff)
1881  ExFreePool(stripeoff);
1882 
1883  return Status;
1884 }
1885 
1888  NTSTATUS Status;
1889  UINT32 i;
1890  CHUNK_ITEM_STRIPE* cis;
1891  write_stripe* stripes = NULL;
1892  UINT64 total_writing = 0;
1893  ULONG allowed_missing, missing;
1894 
1895  TRACE("(%p, %llx, %p, %x)\n", Vcb, address, data, length);
1896 
1897  if (!c) {
1899  if (!c) {
1900  ERR("could not get chunk for address %llx\n", address);
1901  return STATUS_INTERNAL_ERROR;
1902  }
1903  }
1904 
1905  stripes = ExAllocatePoolWithTag(PagedPool, sizeof(write_stripe) * c->chunk_item->num_stripes, ALLOC_TAG);
1906  if (!stripes) {
1907  ERR("out of memory\n");
1909  }
1910 
1911  RtlZeroMemory(stripes, sizeof(write_stripe) * c->chunk_item->num_stripes);
1912 
1913  cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1];
1914 
1915  if (c->chunk_item->type & BLOCK_FLAG_RAID0) {
1917  if (!NT_SUCCESS(Status)) {
1918  ERR("prepare_raid0_write returned %08x\n", Status);
1919  goto prepare_failed;
1920  }
1921 
1922  allowed_missing = 0;
1923  } else if (c->chunk_item->type & BLOCK_FLAG_RAID10) {
1925  if (!NT_SUCCESS(Status)) {
1926  ERR("prepare_raid10_write returned %08x\n", Status);
1927  goto prepare_failed;
1928  }
1929 
1930  allowed_missing = 1;
1931  } else if (c->chunk_item->type & BLOCK_FLAG_RAID5) {
1933  if (!NT_SUCCESS(Status)) {
1934  ERR("prepare_raid5_write returned %08x\n", Status);
1935  goto prepare_failed;
1936  }
1937 
1938  allowed_missing = 1;
1939  } else if (c->chunk_item->type & BLOCK_FLAG_RAID6) {
1941  if (!NT_SUCCESS(Status)) {
1942  ERR("prepare_raid6_write returned %08x\n", Status);
1943  goto prepare_failed;
1944  }
1945 
1946  allowed_missing = 2;
1947  } else { // write same data to every location - SINGLE, DUP, RAID1
1948  for (i = 0; i < c->chunk_item->num_stripes; i++) {
1949  stripes[i].start = address - c->offset;
1950  stripes[i].end = stripes[i].start + length;
1951  stripes[i].data = data;
1952  stripes[i].irp_offset = irp_offset;
1953 
1954  if (c->devices[i]->devobj) {
1955  if (file_write) {
1956  UINT8* va;
1957  ULONG writelen = (ULONG)(stripes[i].end - stripes[i].start);
1958 
1959  va = (UINT8*)MmGetMdlVirtualAddress(Irp->MdlAddress) + stripes[i].irp_offset;
1960 
1961  stripes[i].mdl = IoAllocateMdl(va, writelen, FALSE, FALSE, NULL);
1962  if (!stripes[i].mdl) {
1963  ERR("IoAllocateMdl failed\n");
1965  goto prepare_failed;
1966  }
1967 
1968  IoBuildPartialMdl(Irp->MdlAddress, stripes[i].mdl, va, writelen);
1969  } else {
1970  stripes[i].mdl = IoAllocateMdl(stripes[i].data, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
1971  if (!stripes[i].mdl) {
1972  ERR("IoAllocateMdl failed\n");
1974  goto prepare_failed;
1975  }
1976 
1978 
1979  _SEH2_TRY {
1980  MmProbeAndLockPages(stripes[i].mdl, KernelMode, IoReadAccess);
1983  } _SEH2_END;
1984 
1985  if (!NT_SUCCESS(Status)) {
1986  ERR("MmProbeAndLockPages threw exception %08x\n", Status);
1987  IoFreeMdl(stripes[i].mdl);
1988  stripes[i].mdl = NULL;
1989  goto prepare_failed;
1990  }
1991  }
1992  }
1993  }
1994 
1995  allowed_missing = c->chunk_item->num_stripes - 1;
1996  }
1997 
1998  missing = 0;
1999  for (i = 0; i < c->chunk_item->num_stripes; i++) {
2000  if (!c->devices[i]->devobj)
2001  missing++;
2002  }
2003 
2004  if (missing > allowed_missing) {
2005  ERR("cannot write as %u missing devices (maximum %u)\n", missing, allowed_missing);
2007  goto prepare_failed;
2008  }
2009 
2010  for (i = 0; i < c->chunk_item->num_stripes; i++) {
2013 
2015  if (!stripe) {
2016  ERR("out of memory\n");
2018  goto end;
2019  }
2020 
2021  if (stripes[i].start == stripes[i].end || !c->devices[i]->devobj) {
2022  stripe->status = WriteDataStatus_Ignore;
2023  stripe->Irp = NULL;
2024  stripe->buf = stripes[i].data;
2025  stripe->mdl = NULL;
2026  } else {
2027  stripe->context = (struct _write_data_context*)wtc;
2028  stripe->buf = stripes[i].data;
2029  stripe->device = c->devices[i];
2030  RtlZeroMemory(&stripe->iosb, sizeof(IO_STATUS_BLOCK));
2031  stripe->status = WriteDataStatus_Pending;
2032  stripe->mdl = stripes[i].mdl;
2033 
2034  if (!Irp) {
2036 
2037  if (!stripe->Irp) {
2038  ERR("IoAllocateIrp failed\n");
2039  ExFreePool(stripe);
2041  goto end;
2042  }
2043  } else {
2045 
2046  if (!stripe->Irp) {
2047  ERR("IoMakeAssociatedIrp failed\n");
2048  ExFreePool(stripe);
2050  goto end;
2051  }
2052  }
2053 
2056 
2058  stripe->Irp->AssociatedIrp.SystemBuffer = MmGetSystemAddressForMdlSafe(stripes[i].mdl, priority);
2059 
2060  stripe->Irp->Flags = IRP_BUFFERED_IO;
2061  } else if (stripe->device->devobj->Flags & DO_DIRECT_IO)
2062  stripe->Irp->MdlAddress = stripe->mdl;
2063  else
2064  stripe->Irp->UserBuffer = MmGetSystemAddressForMdlSafe(stripes[i].mdl, priority);
2065 
2066 #ifdef DEBUG_PARANOID
2067  if (stripes[i].end < stripes[i].start) {
2068  ERR("trying to write stripe with negative length (%llx < %llx)\n", stripes[i].end, stripes[i].start);
2069  int3;
2070  }
2071 #endif
2072 
2073  IrpSp->Parameters.Write.Length = (ULONG)(stripes[i].end - stripes[i].start);
2074  IrpSp->Parameters.Write.ByteOffset.QuadPart = stripes[i].start + cis[i].offset;
2075 
2076  total_writing += IrpSp->Parameters.Write.Length;
2077 
2078  stripe->Irp->UserIosb = &stripe->iosb;
2079  wtc->stripes_left++;
2080 
2081  IoSetCompletionRoutine(stripe->Irp, write_data_completion, stripe, TRUE, TRUE, TRUE);
2082  }
2083 
2084  InsertTailList(&wtc->stripes, &stripe->list_entry);
2085  }
2086 
2087  if (diskacc)
2088  fFsRtlUpdateDiskCounters(0, total_writing);
2089 
2091 
2092 end:
2093 
2094  if (stripes) ExFreePool(stripes);
2095 
2096  if (!NT_SUCCESS(Status))
2098 
2099  return Status;
2100 
2101 prepare_failed:
2102  for (i = 0; i < c->chunk_item->num_stripes; i++) {
2103  if (stripes[i].mdl && (i == 0 || stripes[i].mdl != stripes[i-1].mdl)) {
2104  if (stripes[i].mdl->MdlFlags & MDL_PAGES_LOCKED)
2106 
2107  IoFreeMdl(stripes[i].mdl);
2108  }
2109  }
2110 
2111  if (wtc->parity1_mdl) {
2112  if (wtc->parity1_mdl->MdlFlags & MDL_PAGES_LOCKED)
2113  MmUnlockPages(wtc->parity1_mdl);
2114 
2115  IoFreeMdl(wtc->parity1_mdl);
2116  wtc->parity1_mdl = NULL;
2117  }
2118 
2119  if (wtc->parity2_mdl) {
2120  if (wtc->parity2_mdl->MdlFlags & MDL_PAGES_LOCKED)
2121  MmUnlockPages(wtc->parity2_mdl);
2122 
2123  IoFreeMdl(wtc->parity2_mdl);
2124  wtc->parity2_mdl = NULL;
2125  }
2126 
2127  if (wtc->mdl) {
2128  if (wtc->mdl->MdlFlags & MDL_PAGES_LOCKED)
2129  MmUnlockPages(wtc->mdl);
2130 
2131  IoFreeMdl(wtc->mdl);
2132  wtc->mdl = NULL;
2133  }
2134 
2135  if (wtc->parity1) {
2136  ExFreePool(wtc->parity1);
2137  wtc->parity1 = NULL;
2138  }
2139 
2140  if (wtc->parity2) {
2141  ExFreePool(wtc->parity2);
2142  wtc->parity2 = NULL;
2143  }
2144 
2145  if (wtc->scratch) {
2146  ExFreePool(wtc->scratch);
2147  wtc->scratch = NULL;
2148  }
2149 
2151  return Status;
2152 }
2153 
2155  UINT64 startoff, endoff;
2156  UINT16 startoffstripe, endoffstripe, datastripes;
2157 
2158  datastripes = c->chunk_item->num_stripes - (c->chunk_item->type & BLOCK_FLAG_RAID5 ? 1 : 2);
2159 
2160  get_raid0_offset(address - c->offset, c->chunk_item->stripe_length, datastripes, &startoff, &startoffstripe);
2161  get_raid0_offset(address + length - c->offset - 1, c->chunk_item->stripe_length, datastripes, &endoff, &endoffstripe);
2162 
2163  startoff -= startoff % c->chunk_item->stripe_length;
2164  endoff = sector_align(endoff, c->chunk_item->stripe_length);
2165 
2166  *lockaddr = c->offset + (startoff * datastripes);
2167  *locklen = (endoff - startoff) * datastripes;
2168 }
2169 
2171  write_data_context wtc;
2172  NTSTATUS Status;
2173  UINT64 lockaddr, locklen;
2174 
2177  wtc.stripes_left = 0;
2178  wtc.parity1 = wtc.parity2 = wtc.scratch = NULL;
2179  wtc.mdl = wtc.parity1_mdl = wtc.parity2_mdl = NULL;
2180 
2181  if (!c) {
2183  if (!c) {
2184  ERR("could not get chunk for address %llx\n", address);
2185  return STATUS_INTERNAL_ERROR;
2186  }
2187  }
2188 
2189  if (c->chunk_item->type & BLOCK_FLAG_RAID5 || c->chunk_item->type & BLOCK_FLAG_RAID6) {
2190  get_raid56_lock_range(c, address, length, &lockaddr, &locklen);
2191  chunk_lock_range(Vcb, c, lockaddr, locklen);
2192  }
2193 
2194  _SEH2_TRY {
2198  } _SEH2_END;
2199 
2200  if (!NT_SUCCESS(Status)) {
2201  ERR("write_data returned %08x\n", Status);
2202 
2203  if (c->chunk_item->type & BLOCK_FLAG_RAID5 || c->chunk_item->type & BLOCK_FLAG_RAID6)
2204  chunk_unlock_range(Vcb, c, lockaddr, locklen);
2205 
2207  return Status;
2208  }
2209 
2210  if (wtc.stripes.Flink != &wtc.stripes) {
2211  // launch writes and wait
2212  LIST_ENTRY* le = wtc.stripes.Flink;
2213  BOOL no_wait = TRUE;
2214 
2215  while (le != &wtc.stripes) {
2217 
2218  if (stripe->status != WriteDataStatus_Ignore) {
2220  no_wait = FALSE;
2221  }
2222 
2223  le = le->Flink;
2224  }
2225 
2226  if (!no_wait)
2228 
2229  le = wtc.stripes.Flink;
2230  while (le != &wtc.stripes) {
2232 
2233  if (stripe->status != WriteDataStatus_Ignore && !NT_SUCCESS(stripe->iosb.Status)) {
2234  Status = stripe->iosb.Status;
2235 
2237  break;
2238  }
2239 
2240  le = le->Flink;
2241  }
2242 
2244  }
2245 
2246  if (c->chunk_item->type & BLOCK_FLAG_RAID5 || c->chunk_item->type & BLOCK_FLAG_RAID6)
2247  chunk_unlock_range(Vcb, c, lockaddr, locklen);
2248 
2249  return Status;
2250 }
2251 
2252 _Function_class_(IO_COMPLETION_ROUTINE)
2253 #ifdef __REACTOS__
2254 static NTSTATUS NTAPI write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
2255 #else
2256 static NTSTATUS write_data_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
2257 #endif
2258  write_data_stripe* stripe = conptr;
2260  LIST_ENTRY* le;
2261 
2263 
2264  // FIXME - we need a lock here
2265 
2266  if (stripe->status == WriteDataStatus_Cancelling) {
2268  goto end;
2269  }
2270 
2271  stripe->iosb = Irp->IoStatus;
2272 
2273  if (NT_SUCCESS(Irp->IoStatus.Status)) {
2274  stripe->status = WriteDataStatus_Success;
2275  } else {
2276  le = context->stripes.Flink;
2277 
2278  stripe->status = WriteDataStatus_Error;
2279 
2280  while (le != &context->stripes) {
2282 
2283  if (s2->status == WriteDataStatus_Pending) {
2284  s2->status = WriteDataStatus_Cancelling;
2285  IoCancelIrp(s2->Irp);
2286  }
2287 
2288  le = le->Flink;
2289  }
2290  }
2291 
2292 end:
2293  if (InterlockedDecrement(&context->stripes_left) == 0)
2294  KeSetEvent(&context->Event, 0, FALSE);
2295 
2297 }
2298 
2300  LIST_ENTRY* le;
2301  PMDL last_mdl = NULL;
2302 
2303  if (wtc->parity1_mdl) {
2304  if (wtc->parity1_mdl->MdlFlags & MDL_PAGES_LOCKED)
2305  MmUnlockPages(wtc->parity1_mdl);
2306 
2307  IoFreeMdl(wtc->parity1_mdl);
2308  }
2309 
2310  if (wtc->parity2_mdl) {
2311  if (wtc->parity2_mdl->MdlFlags & MDL_PAGES_LOCKED)
2312  MmUnlockPages(wtc->parity2_mdl);
2313 
2314  IoFreeMdl(wtc->parity2_mdl);
2315  }
2316 
2317  if (wtc->mdl) {
2318  if (wtc->mdl->MdlFlags & MDL_PAGES_LOCKED)
2319  MmUnlockPages(wtc->mdl);
2320 
2321  IoFreeMdl(wtc->mdl);
2322  }
2323 
2324  if (wtc->parity1)
2325  ExFreePool(wtc->parity1);
2326 
2327  if (wtc->parity2)
2328  ExFreePool(wtc->parity2);
2329 
2330  if (wtc->scratch)
2331  ExFreePool(wtc->scratch);
2332 
2333  le = wtc->stripes.Flink;
2334  while (le != &wtc->stripes) {
2336 
2337  if (stripe->mdl && stripe->mdl != last_mdl) {
2338  if (stripe->mdl->MdlFlags & MDL_PAGES_LOCKED)
2339  MmUnlockPages(stripe->mdl);
2340 
2341  IoFreeMdl(stripe->mdl);
2342  }
2343 
2344  last_mdl = stripe->mdl;
2345 
2346  if (stripe->Irp)
2347  IoFreeIrp(stripe->Irp);
2348 
2349  le = le->Flink;
2350  }
2351 
2352  while (!IsListEmpty(&wtc->stripes)) {
2354 
2355  ExFreePool(stripe);
2356  }
2357 }
2358 
2360  LIST_ENTRY* le = prevextle->Flink;
2361 
2362  while (le != &fcb->extents) {
2364 
2365  if (ext->offset >= newext->offset) {
2366  InsertHeadList(ext->list_entry.Blink, &newext->list_entry);
2367  return;
2368  }
2369 
2370  le = le->Flink;
2371  }
2372 
2373  InsertTailList(&fcb->extents, &newext->list_entry);
2374 }
2375 
2377  NTSTATUS Status;
2378  LIST_ENTRY* le;
2379 
2380  le = fcb->extents.Flink;
2381 
2382  while (le != &fcb->extents) {
2383  LIST_ENTRY* le2 = le->Flink;
2385  EXTENT_DATA* ed = &ext->extent_data;
2386  EXTENT_DATA2* ed2 = NULL;
2387  UINT64 len;
2388 
2389  if (!ext->ignore) {
2390  if (ed->type != EXTENT_TYPE_INLINE)
2391  ed2 = (EXTENT_DATA2*)ed->data;
2392 
2394 
2395  if (ext->offset < end_data && ext->offset + len > start_data) {
2396  if (ed->type == EXTENT_TYPE_INLINE) {
2397  if (start_data <= ext->offset && end_data >= ext->offset + len) { // remove all
2399 
2402  } else {
2403  ERR("trying to split inline extent\n");
2404 #ifdef DEBUG_PARANOID
2405  int3;
2406 #endif
2407  return STATUS_INTERNAL_ERROR;
2408  }
2409  } else if (ed->type != EXTENT_TYPE_INLINE) {
2410  if (start_data <= ext->offset && end_data >= ext->offset + len) { // remove all
2411  if (ed2->size != 0) {
2412  chunk* c;
2413 
2416 
2418 
2419  if (!c) {
2420  ERR("get_chunk_from_address(%llx) failed\n", ed2->address);
2421  } else {
2422  Status = update_changed_extent_ref(Vcb, c, ed2->address, ed2->size, fcb->subvol->id, fcb->inode, ext->offset - ed2->offset, -1,
2424  if (!NT_SUCCESS(Status)) {
2425  ERR("update_changed_extent_ref returned %08x\n", Status);
2426  goto end;
2427  }
2428  }
2429  }
2430 
2432  } else if (start_data <= ext->offset && end_data < ext->offset + len) { // remove beginning
2433  EXTENT_DATA2* ned2;
2434  extent* newext;
2435 
2436  if (ed2->size != 0) {
2437  fcb->inode_item.st_blocks -= end_data - ext->offset;
2439  }
2440 
2441  newext = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2), ALLOC_TAG);
2442  if (!newext) {
2443  ERR("out of memory\n");
2445  goto end;
2446  }
2447 
2448  ned2 = (EXTENT_DATA2*)newext->extent_data.data;
2449 
2450  newext->extent_data.generation = Vcb->superblock.generation;
2453  newext->extent_data.encryption = ed->encryption;
2454  newext->extent_data.encoding = ed->encoding;
2455  newext->extent_data.type = ed->type;
2456  ned2->address = ed2->address;
2457  ned2->size = ed2->size;
2458  ned2->offset = ed2->offset + (end_data - ext->offset);
2459  ned2->num_bytes = ed2->num_bytes - (end_data - ext->offset);
2460 
2461  newext->offset = end_data;
2462  newext->datalen = sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2);
2463  newext->unique = ext->unique;
2464  newext->ignore = FALSE;
2465  newext->inserted = TRUE;
2466 
2467  if (ext->csum) {
2469  newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ned2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2470  if (!newext->csum) {
2471  ERR("out of memory\n");
2473  ExFreePool(newext);
2474  goto end;
2475  }
2476 
2477  RtlCopyMemory(newext->csum, &ext->csum[(end_data - ext->offset) / Vcb->superblock.sector_size],
2478  (ULONG)(ned2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size));
2479  } else {
2480  newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2481  if (!newext->csum) {
2482  ERR("out of memory\n");
2484  ExFreePool(newext);
2485  goto end;
2486  }
2487 
2488  RtlCopyMemory(newext->csum, ext->csum, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size));
2489  }
2490  } else
2491  newext->csum = NULL;
2492 
2493  add_extent(fcb, &ext->list_entry, newext);
2494 
2496  } else if (start_data > ext->offset && end_data >= ext->offset + len) { // remove end
2497  EXTENT_DATA2* ned2;
2498  extent* newext;
2499 
2500  if (ed2->size != 0) {
2501  fcb->inode_item.st_blocks -= ext->offset + len - start_data;
2503  }
2504 
2505  newext = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2), ALLOC_TAG);
2506  if (!newext) {
2507  ERR("out of memory\n");
2509  goto end;
2510  }
2511 
2512  ned2 = (EXTENT_DATA2*)newext->extent_data.data;
2513 
2514  newext->extent_data.generation = Vcb->superblock.generation;
2517  newext->extent_data.encryption = ed->encryption;
2518  newext->extent_data.encoding = ed->encoding;
2519  newext->extent_data.type = ed->type;
2520  ned2->address = ed2->address;
2521  ned2->size = ed2->size;
2522  ned2->offset = ed2->offset;
2523  ned2->num_bytes = start_data - ext->offset;
2524 
2525  newext->offset = ext->offset;
2526  newext->datalen = sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2);
2527  newext->unique = ext->unique;
2528  newext->ignore = FALSE;
2529  newext->inserted = TRUE;
2530 
2531  if (ext->csum) {
2533  newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ned2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2534  if (!newext->csum) {
2535  ERR("out of memory\n");
2537  ExFreePool(newext);
2538  goto end;
2539  }
2540 
2541  RtlCopyMemory(newext->csum, ext->csum, (ULONG)(ned2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size));
2542  } else {
2543  newext->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2544  if (!newext->csum) {
2545  ERR("out of memory\n");
2547  ExFreePool(newext);
2548  goto end;
2549  }
2550 
2551  RtlCopyMemory(newext->csum, ext->csum, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size));
2552  }
2553  } else
2554  newext->csum = NULL;
2555 
2556  InsertHeadList(&ext->list_entry, &newext->list_entry);
2557 
2559  } else if (start_data > ext->offset && end_data < ext->offset + len) { // remove middle
2560  EXTENT_DATA2 *neda2, *nedb2;
2561  extent *newext1, *newext2;
2562 
2563  if (ed2->size != 0) {
2564  chunk* c;
2565 
2566  fcb->inode_item.st_blocks -= end_data - start_data;
2568 
2570 
2571  if (!c) {
2572  ERR("get_chunk_from_address(%llx) failed\n", ed2->address);
2573  } else {
2576  if (!NT_SUCCESS(Status)) {
2577  ERR("update_changed_extent_ref returned %08x\n", Status);
2578  goto end;
2579  }
2580  }
2581  }
2582 
2583  newext1 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2), ALLOC_TAG);
2584  if (!newext1) {
2585  ERR("out of memory\n");
2587  goto end;
2588  }
2589 
2590  newext2 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2), ALLOC_TAG);
2591  if (!newext2) {
2592  ERR("out of memory\n");
2594  ExFreePool(newext1);
2595  goto end;
2596  }
2597 
2598  neda2 = (EXTENT_DATA2*)newext1->extent_data.data;
2599 
2600  newext1->extent_data.generation = Vcb->superblock.generation;
2602  newext1->extent_data.compression = ed->compression;
2603  newext1->extent_data.encryption = ed->encryption;
2604  newext1->extent_data.encoding = ed->encoding;
2605  newext1->extent_data.type = ed->type;
2606  neda2->address = ed2->address;
2607  neda2->size = ed2->size;
2608  neda2->offset = ed2->offset;
2609  neda2->num_bytes = start_data - ext->offset;
2610 
2611  nedb2 = (EXTENT_DATA2*)newext2->extent_data.data;
2612 
2613  newext2->extent_data.generation = Vcb->superblock.generation;
2615  newext2->extent_data.compression = ed->compression;
2616  newext2->extent_data.encryption = ed->encryption;
2617  newext2->extent_data.encoding = ed->encoding;
2618  newext2->extent_data.type = ed->type;
2619  nedb2->address = ed2->address;
2620  nedb2->size = ed2->size;
2621  nedb2->offset = ed2->offset + (end_data - ext->offset);
2622  nedb2->num_bytes = ext->offset + len - end_data;
2623 
2624  newext1->offset = ext->offset;
2625  newext1->datalen = sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2);
2626  newext1->unique = ext->unique;
2627  newext1->ignore = FALSE;
2628  newext1->inserted = TRUE;
2629 
2630  newext2->offset = end_data;
2631  newext2->datalen = sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2);
2632  newext2->unique = ext->unique;
2633  newext2->ignore = FALSE;
2634  newext2->inserted = TRUE;
2635 
2636  if (ext->csum) {
2638  newext1->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(neda2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2639  if (!newext1->csum) {
2640  ERR("out of memory\n");
2642  ExFreePool(newext1);
2643  ExFreePool(newext2);
2644  goto end;
2645  }
2646 
2647  newext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(nedb2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2648  if (!newext2->csum) {
2649  ERR("out of memory\n");
2651  ExFreePool(newext1->csum);
2652  ExFreePool(newext1);
2653  ExFreePool(newext2);
2654  goto end;
2655  }
2656 
2657  RtlCopyMemory(newext1->csum, ext->csum, (ULONG)(neda2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size));
2658  RtlCopyMemory(newext2->csum, &ext->csum[(end_data - ext->offset) / Vcb->superblock.sector_size],
2659  (ULONG)(nedb2->num_bytes * sizeof(UINT32) / Vcb->superblock.sector_size));
2660  } else {
2661  newext1->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2662  if (!newext1->csum) {
2663  ERR("out of memory\n");
2665  ExFreePool(newext1);
2666  ExFreePool(newext2);
2667  goto end;
2668  }
2669 
2670  newext2->csum = ExAllocatePoolWithTag(PagedPool, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size), ALLOC_TAG);
2671  if (!newext2->csum) {
2672  ERR("out of memory\n");
2674  ExFreePool(newext1->csum);
2675  ExFreePool(newext1);
2676  ExFreePool(newext2);
2677  goto end;
2678  }
2679 
2680  RtlCopyMemory(newext1->csum, ext->csum, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size));
2681  RtlCopyMemory(newext2->csum, ext->csum, (ULONG)(ed2->size * sizeof(UINT32) / Vcb->superblock.sector_size));
2682  }
2683  } else {
2684  newext1->csum = NULL;
2685  newext2->csum = NULL;
2686  }
2687 
2688  InsertHeadList(&ext->list_entry, &newext1->list_entry);
2689  add_extent(fcb, &newext1->list_entry, newext2);
2690 
2692  }
2693  }
2694  }
2695  }
2696 
2697  le = le2;
2698  }
2699 
2701 
2702 end:
2705 
2706  return Status;
2707 }
2708 
2710  rollback_extent* re;
2711 
2713  if (!re) {
2714  ERR("out of memory\n");
2715  return;
2716  }
2717 
2718  re->fcb = fcb;
2719  re->ext = ext;
2720 
2722 }
2723 
2724 #ifdef _MSC_VER
2725 #pragma warning(push)
2726 #pragma warning(suppress: 28194)
2727 #endif
2730  extent* ext;
2731  LIST_ENTRY* le;
2732 
2734  if (!ext) {
2735  ERR("out of memory\n");
2737  }
2738 
2739  ext->offset = offset;
2740  ext->datalen = edsize;
2741  ext->unique = unique;
2742  ext->ignore = FALSE;
2743  ext->inserted = TRUE;
2744  ext->csum = csum;
2745 
2746  RtlCopyMemory(&ext->extent_data, ed, edsize);
2747 
2748  le = fcb->extents.Flink;
2749  while (le != &fcb->extents) {
2750  extent* oldext = CONTAINING_RECORD(le, extent, list_entry);
2751 
2752  if (oldext->offset >= offset) {
2753  InsertHeadList(le->Blink, &ext->list_entry);
2754  goto end;
2755  }
2756 
2757  le = le->Flink;
2758  }
2759 
2760  InsertTailList(&fcb->extents, &ext->list_entry);
2761 
2762 end:
2764 
2765  return STATUS_SUCCESS;
2766 }
2767 #ifdef _MSC_VER
2768 #pragma warning(pop)
2769 #endif
2770 
2772  if (!ext->ignore) {
2773  rollback_extent* re;
2774 
2775  ext->ignore = TRUE;
2776 
2778  if (!re) {
2779  ERR("out of memory\n");
2780  return;
2781  }
2782 
2783  re->fcb = fcb;
2784  re->ext = ext;
2785 
2787  }
2788 }
2789 
2792  NTSTATUS Status;
2793  calc_job* cj;
2794 
2795  // From experimenting, it seems that 40 sectors is roughly the crossover
2796  // point where offloading the crc32 calculation becomes worth it.
2797 
2798  if (sectors < 40 || KeQueryActiveProcessorCount(NULL) < 2) {
2799  ULONG j;
2800 
2801  for (j = 0; j < sectors; j++) {
2802  csum[j] = ~calc_crc32c(0xffffffff, data + (j * Vcb->superblock.sector_size), Vcb->superblock.sector_size);
2803  }
2804 
2805  return STATUS_SUCCESS;
2806  }
2807 
2809  if (!NT_SUCCESS(Status)) {
2810  ERR("add_calc_job returned %08x\n", Status);
2811  return Status;
2812  }
2813 
2815  free_calc_job(cj);
2816 
2817  return STATUS_SUCCESS;
2818 }
2819 
2820 _Requires_lock_held_(c->lock)
2824  UINT64 address;
2830 
2831  TRACE("(%p, (%llx, %llx), %llx, %llx, %llx, %u, %p, %p)\n", Vcb, fcb->subvol->id, fcb->inode, c->offset, start_data, length, prealloc, data, rollback);
2832 
2834  return FALSE;
2835 
2836  // add extent data to inode
2838  if (!ed) {
2839  ERR("out of memory\n");
2840  return FALSE;
2841  }
2842 
2843  ed->generation = Vcb->superblock.generation;
2849 
2850  ed2 = (EXTENT_DATA2*)ed->data;
2853  ed2->offset = 0;
2855 
2857  ULONG sl = (ULONG)(length / Vcb->superblock.sector_size);
2858 
2860  if (!csum) {
2861  ERR("out of memory\n");
2862  ExFreePool(ed);
2863  return FALSE;
2864  }
2865 
2866  Status = calc_csum(Vcb, data, sl, csum);
2867  if (!NT_SUCCESS(Status)) {
2868  ERR("calc_csum returned %08x\n", Status);
2869  ExFreePool(csum);
2870  ExFreePool(ed);
2871  return FALSE;
2872  }
2873  }
2874 
2877  ERR("add_extent_to_fcb returned %08x\n", Status);
2878  if (csum) ExFreePool(csum);
2879  ExFreePool(ed);
2880  return FALSE;
2881  }
2882 
2883  ExFreePool(ed);
2884 
2885  c->used += length;
2887 
2889 
2893 
2894  ExAcquireResourceExclusiveLite(&c->changed_extents_lock, TRUE);
2895 
2897 
2898  ExReleaseResourceLite(&c->changed_extents_lock);
2899 
2901 
2902  if (data) {
2905  if (!NT_SUCCESS(Status))
2906  ERR("write_data_complete returned %08x\n", Status);
2907  }
2908 
2909  return TRUE;
2910 }
2911 
2914  BOOL success = FALSE;
2915  EXTENT_DATA* ed;
2916  EXTENT_DATA2* ed2;
2917  chunk* c;
2918  LIST_ENTRY* le;
2919  extent* ext = NULL;
2920 
2921  le = fcb->extents.Flink;
2922 
2923  while (le != &fcb->extents) {
2924  extent* nextext = CONTAINING_RECORD(le, extent, list_entry);
2925 
2926  if (!nextext->ignore) {
2927  if (nextext->offset == start_data) {
2928  ext = nextext;
2929  break;
2930  } else if (nextext->offset > start_data)
2931  break;
2932 
2933  ext = nextext;
2934  }
2935 
2936  le = le->Flink;
2937  }
2938 
2939  if (!ext)
2940  return FALSE;
2941 
2942  ed = &ext->extent_data;
2943 
2945  TRACE("not extending extent which is not regular or prealloc\n");
2946  return FALSE;
2947  }
2948 
2949  ed2 = (EXTENT_DATA2*)ed->data;
2950 
2951  if (ext->offset + ed2->num_bytes != start_data) {
2952  TRACE("last EXTENT_DATA does not run up to start_data (%llx + %llx != %llx)\n", ext->offset, ed2->num_bytes, start_data);
2953  return FALSE;
2954  }
2955 
2957 
2958  if (c->reloc || c->readonly || c->chunk_item->type != Vcb->data_flags)
2959  return FALSE;
2960 
2962 
2963  if (length > c->chunk_item->size - c->used) {
2965  return FALSE;
2966  }
2967 
2968  if (!c->cache_loaded) {
2970 
2971  if (!NT_SUCCESS(Status)) {
2972  ERR("load_cache_chunk returned %08x\n", Status);
2974  return FALSE;
2975  }
2976  }
2977 
2978  le = c->space.Flink;
2979  while (le != &c->space) {
2981 
2982  if (s->address == ed2->address + ed2->size) {
2983  UINT64 newlen = min(min(s->size, length), MAX_EXTENT_SIZE);
2984 
2985  success = insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data, Irp, rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset);
2986 
2987  if (success)
2988  *written += newlen;
2989  else
2991 
2992  return success;
2993  } else if (s->address > ed2->address + ed2->size)
2994  break;
2995 
2996  le = le->Flink;
2997  }
2998 
3000 
3001  return FALSE;
3002 }
3003 
3005  LIST_ENTRY* le;
3006  UINT64 flags = fcb->Vcb->data_flags;
3007  BOOL page_file = fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE;
3008  NTSTATUS Status;
3009  chunk* c;
3010 
3011  ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE);
3012 
3013  // first create as many chunks as we can
3014  do {
3015  Status = alloc_chunk(fcb->Vcb, flags, &c, FALSE);
3016  } while (NT_SUCCESS(Status));
3017 
3018  if (Status != STATUS_DISK_FULL) {
3019  ERR("alloc_chunk returned %08x\n", Status);
3020  ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
3021  return Status;
3022  }
3023 
3024  le = fcb->Vcb->chunks.Flink;
3025  while (le != &fcb->Vcb->chunks) {
3027 
3028  if (!c->readonly && !c->reloc) {
3030 
3031  if (c->chunk_item->type == flags) {
3032  while (!IsListEmpty(&c->space_size) && length > 0) {
3033  space* s = CONTAINING_RECORD(c->space_size.Flink, space, list_entry_size);
3034  UINT64 extlen = min(length, s->size);
3035 
3036  if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen, prealloc && !page_file, data, NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0)) {
3037  start += extlen;
3038  length -= extlen;
3039  if (data) data += extlen;
3040 
3042  }
3043  }
3044  }
3045 
3047 
3048  if (length == 0)
3049  break;
3050  }
3051 
3052  le = le->Flink;
3053  }
3054 
3055  ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
3056 
3057  return length == 0 ? STATUS_SUCCESS : STATUS_DISK_FULL;
3058 }
3059 
3061  LIST_ENTRY* le;
3062  chunk* c;
3063  UINT64 flags;
3064  NTSTATUS Status;
3065  BOOL page_file = fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE;
3066 
3067  flags = fcb->Vcb->data_flags;
3068 
3069  do {
3070  UINT64 extlen = min(MAX_EXTENT_SIZE, length);
3071 
3072  ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE);
3073 
3074  le = fcb->Vcb->chunks.Flink;
3075  while (le != &fcb->Vcb->chunks) {
3077 
3078  if (!c->readonly && !c->reloc) {
3080 
3081  if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= extlen) {
3082  if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen, !page_file, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0)) {
3083  ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
3084  goto cont;
3085  }
3086  }
3087 
3089  }
3090 
3091  le = le->Flink;
3092  }
3093 
3094  ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
3095 
3096  ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE);
3097 
3098  Status = alloc_chunk(fcb->Vcb, flags, &c, FALSE);
3099 
3100  ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
3101 
3102  if (!NT_SUCCESS(Status)) {
3103  ERR("alloc_chunk returned %08x\n", Status);
3104  goto end;
3105  }
3106 
3108 
3109  if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= extlen) {
3110  if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen, !page_file, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0))
3111  goto cont;
3112  }
3113 
3115 
3117  if (!NT_SUCCESS(Status))
3118  ERR("insert_chunk_fragmented returned %08x\n", Status);
3119 
3120  goto end;
3121 
3122 cont:
3123  length -= extlen;
3124  start += extlen;
3125  } while (length > 0);
3126 
3128 
3129 end:
3130  return Status;
3131 }
3132 
3135  NTSTATUS Status;
3136  LIST_ENTRY* le;
3137  chunk* c;
3138  UINT64 flags, orig_length = length, written = 0;
3139 
3140  TRACE("(%p, (%llx, %llx), %llx, %llx, %p)\n", Vcb, fcb->subvol->id, fcb->inode, start_data, length, data);
3141 
3142  if (start_data > 0) {
3144 
3145  if (written == length)
3146  return STATUS_SUCCESS;
3147  else if (written > 0) {
3148  start_data += written;
3149  irp_offset += written;
3150  length -= written;
3151  data = &((UINT8*)data)[written];
3152  }
3153  }
3154 
3155  flags = Vcb->data_flags;
3156 
3157  while (written < orig_length) {
3158  UINT64 newlen = min(length, MAX_EXTENT_SIZE);
3159  BOOL done = FALSE;
3160 
3161  // Rather than necessarily writing the whole extent at once, we deal with it in blocks of 128 MB.
3162  // First, see if we can write the extent part to an existing chunk.
3163 
3164  ExAcquireResourceSharedLite(&Vcb->chunk_lock, TRUE);
3165 
3166  le = Vcb->chunks.Flink;
3167  while (le != &Vcb->chunks) {
3169 
3170  if (!c->readonly && !c->reloc) {
3172 
3173  if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= newlen &&
3174  insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data, Irp, rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset)) {
3175  written += newlen;
3176 
3177  if (written == orig_length) {
3178  ExReleaseResourceLite(&Vcb->chunk_lock);
3179  return STATUS_SUCCESS;
3180  } else {
3181  done = TRUE;
3182  start_data += newlen;
3183  irp_offset += newlen;
3184  length -= newlen;
3185  data = &((UINT8*)data)[newlen];
3186  break;
3187  }
3188  } else
3190  }
3191 
3192  le = le->Flink;
3193  }
3194 
3195  ExReleaseResourceLite(&Vcb->chunk_lock);
3196 
3197  if (done) continue;
3198 
3199  // Otherwise, see if we can put it in a new chunk.
3200 
3201  ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, TRUE);
3202 
3203  Status = alloc_chunk(Vcb, flags, &c, FALSE);
3204 
3205  ExReleaseResourceLite(&Vcb->chunk_lock);
3206 
3207  if (!NT_SUCCESS(Status)) {
3208  ERR("alloc_chunk returned %08x\n", Status);
3209  return Status;
3210  }
3211 
3212  if (c) {
3214 
3215  if (c->chunk_item->type == flags && (c->chunk_item->size - c->used) >= newlen &&
3216  insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data, Irp, rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset)) {
3217  written += newlen;
3218 
3219  if (written == orig_length)
3220  return STATUS_SUCCESS;
3221  else {
3222  done = TRUE;
3223  start_data += newlen;
3224  irp_offset += newlen;
3225  length -= newlen;
3226  data = &((UINT8*)data)[newlen];
3227  }
3228  } else
3230  }
3231 
3232  if (!done) {
3234  if (!NT_SUCCESS(Status))
3235  ERR("insert_chunk_fragmented returned %08x\n", Status);
3236 
3237  return Status;
3238  }
3239  }
3240 
3241  return STATUS_DISK_FULL;
3242 }
3243 
3245  NTSTATUS Status;
3246 
3247  // FIXME - convert into inline extent if short enough
3248 
3249  if (end > 0 && fcb_is_inline(fcb)) {
3250  UINT8* buf;
3251  BOOL make_inline = end <= fcb->Vcb->options.max_inline;
3252 
3253  buf = ExAllocatePoolWithTag(PagedPool, (ULONG)(make_inline ? (offsetof(EXTENT_DATA, data[0]) + end) : sector_align(end, fcb->Vcb->superblock.sector_size)), ALLOC_TAG);
3254  if (!buf) {
3255  ERR("out of memory\n");
3257  }
3258 
3259  Status = read_file(fcb, make_inline ? (buf + offsetof(EXTENT_DATA, data[0])) : buf, 0, end, NULL, Irp);
3260  if (!NT_SUCCESS(Status)) {
3261  ERR("read_file returned %08x\n", Status);
3262  ExFreePool(buf);
3263  return Status;
3264  }
3265 
3267  if (!NT_SUCCESS(Status)) {
3268  ERR("excise_extents returned %08x\n", Status);
3269  ExFreePool(buf);
3270  return Status;
3271  }
3272 
3273  if (!make_inline) {
3274  RtlZeroMemory(buf + end, (ULONG)(sector_align(end, fcb->Vcb->superblock.sector_size) - end));
3275 
3276  Status = do_write_file(fcb, 0, sector_align(end, fcb->Vcb->superblock.sector_size), buf, Irp, FALSE, 0, rollback);
3277  if (!NT_SUCCESS(Status)) {
3278  ERR("do_write_file returned %08x\n", Status);
3279  ExFreePool(buf);
3280  return Status;
3281  }
3282  } else {
3284 
3285  ed->generation = fcb->Vcb->superblock.generation;
3286  ed->decoded_size = end;
3291 
3293  if (!NT_SUCCESS(Status)) {
3294  ERR("add_extent_to_fcb returned %08x\n", Status);
3295  ExFreePool(buf);
3296  return Status;
3297  }
3298 
3300  }
3301 
3302  ExFreePool(buf);
3303  return STATUS_SUCCESS;
3304  }
3305 
3306  Status = excise_extents(fcb->Vcb, fcb, sector_align(end, fcb->Vcb->superblock.sector_size),
3307  sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size), Irp, rollback);
3308  if (!NT_SUCCESS(Status)) {
3309  ERR("excise_extents returned %08x\n", Status);
3310  return Status;
3311  }
3312 
3315  TRACE("setting st_size to %llx\n", end);
3316 
3317  fcb->Header.AllocationSize.QuadPart = sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
3318  fcb->Header.FileSize.QuadPart = fcb->inode_item.st_size;
3319  fcb->Header.ValidDataLength.QuadPart = fcb->inode_item.st_size;
3320  // FIXME - inform cache manager of this
3321 
3322  TRACE("fcb %p FileSize = %llx\n", fcb, fcb->Header.FileSize.QuadPart);
3323 
3324  return STATUS_SUCCESS;
3325 }
3326 
3328  UINT64 oldalloc, newalloc;
3329  BOOL cur_inline;
3330  NTSTATUS Status;
3331 
3332  TRACE("(%p, %p, %x, %u)\n", fcb, fileref, end, prealloc);
3333 
3334  if (fcb->ads) {
3335  if (end > 0xffff)
3336  return STATUS_DISK_FULL;
3337 
3339  } else {
3340  extent* ext = NULL;
3341  LIST_ENTRY* le;
3342 
3343  le = fcb->extents.Blink;
3344  while (le != &fcb->extents) {
3346 
3347  if (!ext2->ignore) {
3348  ext = ext2;
3349  break;
3350  }
3351 
3352  le = le->Blink;
3353  }
3354 
3355  oldalloc = 0;
3356  if (ext) {
3357  EXTENT_DATA* ed = &ext->extent_data;
3359 
3360  oldalloc = ext->offset + (ed->type == EXTENT_TYPE_INLINE ? ed->decoded_size : ed2->num_bytes);
3361  cur_inline = ed->type == EXTENT_TYPE_INLINE;
3362 
3363  if (cur_inline && end > fcb->Vcb->options.max_inline) {
3364  UINT64 origlength, length;
3365  UINT8* data;
3366 
3367  TRACE("giving inline file proper extents\n");
3368 
3369  origlength = ed->decoded_size;
3370 
3371  cur_inline = FALSE;
3372 
3373  length = sector_align(origlength, fcb->Vcb->superblock.sector_size);
3374 
3376  if (!data) {
3377  ERR("could not allocate %llx bytes for data\n", length);
3379  }
3380 
3381  Status = read_file(fcb, data, 0, origlength, NULL, Irp);
3382  if (!NT_SUCCESS(Status)) {
3383  ERR("read_file returned %08x\n", Status);
3384  ExFreePool(data);
3385  return Status;
3386  }
3387 
3388  RtlZeroMemory(data + origlength, (ULONG)(length - origlength));
3389 
3391  if (!NT_SUCCESS(Status)) {
3392  ERR("excise_extents returned %08x\n", Status);
3393  ExFreePool(data);
3394  return Status;
3395  }
3396 
3398  if (!NT_SUCCESS(Status)) {
3399  ERR("do_write_file returned %08x\n", Status);
3400  ExFreePool(data);
3401  return Status;
3402  }
3403 
3404  oldalloc = ext->offset + length;
3405 
3406  ExFreePool(data);
3407  }
3408 
3409  if (cur_inline) {
3410  UINT16 edsize;
3411 
3412  if (end > oldalloc) {
3413  edsize = (UINT16)(offsetof(EXTENT_DATA, data[0]) + end - ext->offset);
3415 
3416  if (!ed) {
3417  ERR("out of memory\n");
3419  }
3420 
3421  ed->generation = fcb->Vcb->superblock.generation;
3422  ed->decoded_size = end - ext->offset;
3427 
3428  Status = read_file(fcb, ed->data, ext->offset, oldalloc, NULL, Irp);
3429  if (!NT_SUCCESS(Status)) {
3430  ERR("read_file returned %08x\n", Status);
3431  ExFreePool(ed);
3432  return Status;
3433  }
3434 
3435  RtlZeroMemory(ed->data + oldalloc - ext->offset, (ULONG)(end - oldalloc));
3436 
3438 
3439  Status = add_extent_to_fcb(fcb, ext->offset, ed, edsize, ext->unique, NULL, rollback);
3440  if (!NT_SUCCESS(Status)) {
3441  ERR("add_extent_to_fcb returned %08x\n", Status);
3442  ExFreePool(ed);
3443  return Status;
3444  }
3445 
3446  ExFreePool(ed);
3447 
3450  }
3451 
3452  TRACE("extending inline file (oldalloc = %llx, end = %llx)\n", oldalloc, end);
3453 
3455  TRACE("setting st_size to %llx\n", end);
3456 
3458 
3459  fcb->Header.AllocationSize.QuadPart = fcb->Header.FileSize.QuadPart = fcb->Header.ValidDataLength.QuadPart = end;
3460  } else {
3461  newalloc = sector_align(end, fcb->Vcb->superblock.sector_size);
3462 
3463  if (newalloc > oldalloc) {
3464  if (prealloc) {
3465  // FIXME - try and extend previous extent first
3466 
3467  Status = insert_prealloc_extent(fcb, oldalloc, newalloc - oldalloc, rollback);
3468 
3469  if (!NT_SUCCESS(Status)) {
3470  ERR("insert_prealloc_extent returned %08x\n", Status);
3471  return Status;
3472  }
3473  }
3474 
3476  }
3477 
3481 
3482  TRACE("setting st_size to %llx\n", end);
3483 
3484  TRACE("newalloc = %llx\n", newalloc);
3485 
3486  fcb->Header.AllocationSize.QuadPart = newalloc;
3487  fcb->Header.FileSize.QuadPart = fcb->Header.ValidDataLength.QuadPart = end;
3488  }
3489  } else {
3490  if (end > fcb->Vcb->options.max_inline) {
3491  newalloc = sector_align(end, fcb->Vcb->superblock.sector_size);
3492 
3493  if (prealloc) {
3494  Status = insert_prealloc_extent(fcb, 0, newalloc, rollback);
3495 
3496  if (!NT_SUCCESS(Status)) {
3497  ERR("insert_prealloc_extent returned %08x\n", Status);
3498  return Status;
3499  }
3500  }
3501 
3505 
3507  TRACE("setting st_size to %llx\n", end);
3508 
3509  TRACE("newalloc = %llx\n", newalloc);
3510 
3511  fcb->Header.AllocationSize.QuadPart = newalloc;
3512  fcb->Header.FileSize.QuadPart = fcb->Header.ValidDataLength.QuadPart = end;
3513  } else {
3514  EXTENT_DATA* ed;
3515  UINT16 edsize;
3516 
3517  edsize = (UINT16)(offsetof(EXTENT_DATA, data[0]) + end);
3519 
3520  if (!ed) {
3521  ERR("out of memory\n");
3523  }
3524 
3525  ed->generation = fcb->Vcb->superblock.generation;
3526  ed->decoded_size = end;
3531 
3533 
3535  if (!NT_SUCCESS(Status)) {
3536  ERR("add_extent_to_fcb returned %08x\n", Status);
3537  ExFreePool(ed);
3538  return Status;
3539  }
3540 
3541  ExFreePool(ed);
3542 
3546 
3548  TRACE("setting st_size to %llx\n", end);
3549 
3551 
3552  fcb->Header.AllocationSize.QuadPart = fcb->Header.FileSize.QuadPart = fcb->Header.ValidDataLength.QuadPart = end;
3553  }
3554  }
3555  }
3556 
3557  return STATUS_SUCCESS;
3558 }
3559 
3562  EXTENT_DATA* ed = &ext->extent_data;
3564  NTSTATUS Status;
3565  chunk* c = NULL;
3566 
3567  if (start_data <= ext->offset && end_data >= ext->offset + ed2->num_bytes) { // replace all
3568  extent* newext;
3569 
3570  newext = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + ext->datalen, ALLOC_TAG);
3571  if (!newext) {
3572  ERR("out of memory\n");
3574  }
3575 
3576  RtlCopyMemory(&newext->extent_data, &ext->extent_data, ext->datalen);
3577 
3579 
3581  NULL, file_write, irp_offset + ext->offset - start_data, priority);
3582  if (!NT_SUCCESS(Status)) {
3583  ERR("write_data_complete returned %08x\n", Status);
3584  return Status;
3585  }
3586 
3588  ULONG sl = (ULONG)(ed2->num_bytes / fcb->Vcb->superblock.sector_size);
3590 
3591  if (!csum) {
3592  ERR("out of memory\n");
3593  ExFreePool(newext);
3595  }
3596 
3597  Status = calc_csum(fcb->Vcb, (UINT8*)data + ext->offset - start_data, sl, csum);
3598  if (!NT_SUCCESS(Status)) {
3599  ERR("calc_csum returned %08x\n", Status);
3600  ExFreePool(csum);
3601  ExFreePool(newext);
3602  return Status;
3603  }
3604 
3605  newext->csum = csum;
3606  } else
3607  newext->csum = NULL;
3608 
3609  *written = ed2->num_bytes;
3610 
3611  newext->offset = ext->offset;
3612  newext->datalen = ext->datalen;
3613  newext->unique = ext->unique;
3614  newext->ignore = FALSE;
3615  newext->inserted = TRUE;
3616  InsertHeadList(&ext->list_entry, &newext->list_entry);
3617 
3619 
3621 
3623  } else if (start_data <= ext->offset && end_data < ext->offset + ed2->num_bytes) { // replace beginning
3624  EXTENT_DATA2* ned2;
3625  extent *newext1, *newext2;
3626 
3627  newext1 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + ext->datalen, ALLOC_TAG);
3628  if (!newext1) {
3629  ERR("out of memory\n");
3631  }
3632 
3633  newext2 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + ext->datalen, ALLOC_TAG);
3634  if (!newext2) {
3635  ERR("out of memory\n");
3636  ExFreePool(newext1);
3638  }
3639 
3640  RtlCopyMemory(&newext1->extent_data, &ext->extent_data, ext->datalen);
3642  ned2 = (EXTENT_DATA2*)newext1->extent_data.data;
3643  ned2->num_bytes = end_data - ext->offset;
3644 
3645  RtlCopyMemory(&newext2->extent_data, &ext->extent_data, ext->datalen);
3646  ned2 = (EXTENT_DATA2*)newext2->extent_data.data;
3647  ned2->