/*
 * Zwolnij nagłówek bufora
 */
void __brelse(struct buffer_head * buf)
{
 /*czekaj na bufor*/
 wait_on_buffer(buf);

 /* Jeżeli bufor przeznaczony do zapisu, zaznacz czas, w którym powinien zostać zapisany*/
 set_writetime(buf, 0);
 /*uporządkuj pola nagłówka bufora*/
 refile_buffer(buf);

/*zmniejsz licznik odwołań do bufora*/
if (buf->b_count) { /*jeżeli w ogóle jest co zmniejszać*/
  buf->b_count--;
  return;
 }
 printk("VFS: brelse: Trying to free free buffer\n"); /*jeżeli nie ma co zmniejszać to błąd*/
}

/*czekanie na ewentualne zwolnienie bufora z blokady*/
void __wait_on_buffer(struct buffer_head * bh)
{
 struct wait_queue wait = { current, NULL };

 bh->b_count++;      /*zwiększ liczbę odwołań do bufora*/
 add_wait_queue(&bh->b_wait, &wait);
repeat:
 run_task_queue(&tq_disk);
 current->state = TASK_UNINTERRUPTIBLE;  /*wyłącz przerwania*/
 if (buffer_locked(bh)) { /*jeżeli bufor zablokowany*/
  schedule();                   /*zapisz się do kolejki czekających*/
  goto repeat;
 }
 remove_wait_queue(&bh->b_wait, &wait); /*usuń kolejkę do czekania*/
 bh->b_count--; /*zmniejsz liczbę odwołań do bufora*/
 current->state = TASK_RUNNING;  /*przywróć normalny stan obecnego zadania*/
}
 

void set_writetime(struct buffer_head * buf, int flag)
{
 int newtime;

 if (buffer_dirty(buf)) {
  /* Move buffer to dirty list if jiffies is clear */
  /*obliczenie nowego czasu opóźnionego zapisu*/
  /*na podstawie obecnego czasu oraz czasu, po którym superblok/bufor starzeje się
    (zależnie od zmiennej flag)*/
  newtime = jiffies + (flag ? bdf_prm.b_un.age_super :
         bdf_prm.b_un.age_buffer);
  /*jeżeli czas opóźnionego zapisu bufora nie jest zerem, to nie można go zwiększyć*/
  if(!buf->b_flushtime || buf->b_flushtime > newtime)
    buf->b_flushtime = newtime;
 } else {
  buf->b_flushtime = 0;
 }
}
 

/*
 * A buffer may need to be moved from one buffer list to another
 * (e.g. in case it is not shared any more). Handle this.
 */
/* Być może bufor musi zostać przeniesiony z jednej listy buforów do drugiej
 * (np. gdy przestał już być dzielony) */
void refile_buffer(struct buffer_head * buf)
{
 int dispose; /*zmienna pomocnicza - gdzie przesuniemy ten bufor*/

 if(buf->b_dev == B_FREE) {  /*błąd - próbujemy wykonać tą funkcję na wolnym buforze*/
  printk("Attempt to refile free buffer\n");
  return;
 }
 /*bity w polu b_list nie zawsze odpowiadają rzeczywistym kolejkom LRU, w których znajduje się bufor*/
 /*trzeba to uaktualnić*/
 if (buffer_dirty(buf)) /*sprawdzenie bitu BH_Dirty pola b_state*/
  dispose = BUF_DIRTY;
 else if (buffer_locked(buf)) /*jeżeli bit BH_Lock pola b_state jest ustawiony na 1 (czyli gdy bufor jest zablokowany)*/
  dispose = BUF_LOCKED;
 else
  dispose = BUF_CLEAN;
 if(dispose == BUF_CLEAN) buf->b_lru_time = jiffies;  /*zaznaczamy czas ostatniego użycia*/
 if(dispose != buf->b_list)  {
  if(dispose == BUF_DIRTY)
    buf->b_lru_time = jiffies;
  if(dispose == BUF_LOCKED &&
     (buf->b_flushtime - buf->b_lru_time) <= bdf_prm.b_un.age_super)
    dispose = BUF_LOCKED1; /*jeżeli różnica między czasem zapisu a czasem ost. użycia <= czasu starzenia superbloku*/
  remove_from_queues(buf); /*usuń bufor z dotychczasowej kolejki LRU*/
  buf->b_list = dispose;        /*to będzie nowa kolejka dla tego bufora*/
  insert_into_queues(buf);     /*włóż bufor do nowej kolejki*/
  if (dispose == BUF_DIRTY) {
  /* This buffer is dirty, maybe we need to start flushing. */
  /* If too high a percentage of the buffers are dirty... */
  /* Jeżeli ten bufor jest przeznaczony do zapisu, to może trzeba zacząć zapisywać wszystkie takie bufory na dysk*/
  /* Gdy zbyt duży procent buforów jest przeznaczony do zapisu...*/
  if (nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100)
    wakeup_bdflush(0);  /*obudź demona zapisującego bufory*/
  /* If this is a loop device, and
   * more than half of the buffers are dirty... */
  /* (Prevents no-free-buffers deadlock with loop device.) */
  /* jeżeli urządzenie wskazywane przez bufor jest urządzeniem cyklicznym
 /* oraz więcej niż połowa buforów jest przeznaczona do zapisu*/
 /* (zapobiega blokadzie z powodu braku wolnych buforów na urządzeniu cyklicznym)*/
if (MAJOR(buf->b_dev) == LOOP_MAJOR &&
      nr_buffers_type[BUF_DIRTY]*2>nr_buffers)
   wakeup_bdflush(1);
  }
 }
}

/*zmienna globalna zwierająca dane dot. opóźnionego zapisu buforów na dysk*/
/* the dummy values in this structure are left in there for compatibility
   with old programs that play with the /proc entries */
/* zmienne "dummy" zostały zachowane ze względu na kompatybilnos'ć
    ze starszymi programami, które używają /proc*/
union bdflush_param{
 struct {
  /*procent pamięci buforowej, który zajmują bufory przeznaczone do zapisu*/
  int nfract;  /* Percentage of buffer cache dirty to
    activate bdflush */
  /*maksymalna liczba bloków, którą można zapisać za jednym razem po obudzeniu demona bd_flush*/
  int ndirty;  /* Maximum number of dirty blocks to write out per
    wake-cycle */
  /*liczba czystych buforów (czyli nie przeznaczonych do zapisu), które próbujemy uzyskać
     za każdym razem, gdy wywołujemy refill*/
  int nrefill; /* Number of clean buffers to try to obtain
    each time we call refill */
  int nref_dirt; /* Dirty buffer threshold for activating bdflush
      when trying to refill buffers. */
  int dummy1;    /* unused */
  /*czas, po którym normalny bufor się starzeje i trzeba go zapisać*/
  int age_buffer;  /* Time for normal buffer to age before
        we flush it */
  /*czas, po którym superblok się starzeje i trzeba go zapisać*/
  int age_super;  /* Time for superblock to age before we
       flush it */
  int dummy2;    /* unused */
  int dummy3;    /* unused */
 } b_un;
 unsigned int data[N_PARAM];
} bdf_prm = {{40, 500, 64, 64, 15, 30*HZ, 5*HZ, 1884, 2}};