LCOV - code coverage report
Current view: top level - fs - seq_file.c (source / functions) Hit Total Coverage
Test: Real Lines: 283 391 72.4 %
Date: 2020-10-17 15:46:43 Functions: 0 44 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * linux/fs/seq_file.c
       4                 :            :  *
       5                 :            :  * helper functions for making synthetic files from sequences of records.
       6                 :            :  * initial implementation -- AV, Oct 2001.
       7                 :            :  */
       8                 :            : 
       9                 :            : #include <linux/cache.h>
      10                 :            : #include <linux/fs.h>
      11                 :            : #include <linux/export.h>
      12                 :            : #include <linux/seq_file.h>
      13                 :            : #include <linux/vmalloc.h>
      14                 :            : #include <linux/slab.h>
      15                 :            : #include <linux/cred.h>
      16                 :            : #include <linux/mm.h>
      17                 :            : #include <linux/printk.h>
      18                 :            : #include <linux/string_helpers.h>
      19                 :            : 
      20                 :            : #include <linux/uaccess.h>
      21                 :            : #include <asm/page.h>
      22                 :            : 
      23                 :            : static struct kmem_cache *seq_file_cache __ro_after_init;
      24                 :            : 
      25                 :            : static void seq_set_overflow(struct seq_file *m)
      26                 :            : {
      27                 :          3 :         m->count = m->size;
      28                 :            : }
      29                 :            : 
      30                 :            : static void *seq_buf_alloc(unsigned long size)
      31                 :            : {
      32                 :            :         return kvmalloc(size, GFP_KERNEL_ACCOUNT);
      33                 :            : }
      34                 :            : 
      35                 :            : /**
      36                 :            :  *      seq_open -      initialize sequential file
      37                 :            :  *      @file: file we initialize
      38                 :            :  *      @op: method table describing the sequence
      39                 :            :  *
      40                 :            :  *      seq_open() sets @file, associating it with a sequence described
      41                 :            :  *      by @op.  @op->start() sets the iterator up and returns the first
      42                 :            :  *      element of sequence. @op->stop() shuts it down.  @op->next()
      43                 :            :  *      returns the next element of sequence.  @op->show() prints element
      44                 :            :  *      into the buffer.  In case of error ->start() and ->next() return
      45                 :            :  *      ERR_PTR(error).  In the end of sequence they return %NULL. ->show()
      46                 :            :  *      returns 0 in case of success and negative number in case of error.
      47                 :            :  *      Returning SEQ_SKIP means "discard this element and move on".
      48                 :            :  *      Note: seq_open() will allocate a struct seq_file and store its
      49                 :            :  *      pointer in @file->private_data. This pointer should not be modified.
      50                 :            :  */
      51                 :          3 : int seq_open(struct file *file, const struct seq_operations *op)
      52                 :            : {
      53                 :            :         struct seq_file *p;
      54                 :            : 
      55                 :          3 :         WARN_ON(file->private_data);
      56                 :            : 
      57                 :          3 :         p = kmem_cache_zalloc(seq_file_cache, GFP_KERNEL);
      58                 :          3 :         if (!p)
      59                 :            :                 return -ENOMEM;
      60                 :            : 
      61                 :          3 :         file->private_data = p;
      62                 :            : 
      63                 :          3 :         mutex_init(&p->lock);
      64                 :          3 :         p->op = op;
      65                 :            : 
      66                 :            :         // No refcounting: the lifetime of 'p' is constrained
      67                 :            :         // to the lifetime of the file.
      68                 :          3 :         p->file = file;
      69                 :            : 
      70                 :            :         /*
      71                 :            :          * Wrappers around seq_open(e.g. swaps_open) need to be
      72                 :            :          * aware of this. If they set f_version themselves, they
      73                 :            :          * should call seq_open first and then set f_version.
      74                 :            :          */
      75                 :          3 :         file->f_version = 0;
      76                 :            : 
      77                 :            :         /*
      78                 :            :          * seq_files support lseek() and pread().  They do not implement
      79                 :            :          * write() at all, but we clear FMODE_PWRITE here for historical
      80                 :            :          * reasons.
      81                 :            :          *
      82                 :            :          * If a client of seq_files a) implements file.write() and b) wishes to
      83                 :            :          * support pwrite() then that client will need to implement its own
      84                 :            :          * file.open() which calls seq_open() and then sets FMODE_PWRITE.
      85                 :            :          */
      86                 :          3 :         file->f_mode &= ~FMODE_PWRITE;
      87                 :          3 :         return 0;
      88                 :            : }
      89                 :            : EXPORT_SYMBOL(seq_open);
      90                 :            : 
      91                 :          3 : static int traverse(struct seq_file *m, loff_t offset)
      92                 :            : {
      93                 :            :         loff_t pos = 0;
      94                 :            :         int error = 0;
      95                 :            :         void *p;
      96                 :            : 
      97                 :          3 :         m->version = 0;
      98                 :          3 :         m->index = 0;
      99                 :          3 :         m->count = m->from = 0;
     100                 :          3 :         if (!offset)
     101                 :            :                 return 0;
     102                 :            : 
     103                 :          0 :         if (!m->buf) {
     104                 :          0 :                 m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
     105                 :          0 :                 if (!m->buf)
     106                 :            :                         return -ENOMEM;
     107                 :            :         }
     108                 :          0 :         p = m->op->start(m, &m->index);
     109                 :          0 :         while (p) {
     110                 :            :                 error = PTR_ERR(p);
     111                 :          0 :                 if (IS_ERR(p))
     112                 :            :                         break;
     113                 :          0 :                 error = m->op->show(m, p);
     114                 :          0 :                 if (error < 0)
     115                 :            :                         break;
     116                 :          0 :                 if (unlikely(error)) {
     117                 :            :                         error = 0;
     118                 :          0 :                         m->count = 0;
     119                 :            :                 }
     120                 :          0 :                 if (seq_has_overflowed(m))
     121                 :            :                         goto Eoverflow;
     122                 :          0 :                 p = m->op->next(m, p, &m->index);
     123                 :          0 :                 if (pos + m->count > offset) {
     124                 :          0 :                         m->from = offset - pos;
     125                 :          0 :                         m->count -= m->from;
     126                 :          0 :                         break;
     127                 :            :                 }
     128                 :            :                 pos += m->count;
     129                 :          0 :                 m->count = 0;
     130                 :          0 :                 if (pos == offset)
     131                 :            :                         break;
     132                 :            :         }
     133                 :          0 :         m->op->stop(m, p);
     134                 :          0 :         return error;
     135                 :            : 
     136                 :            : Eoverflow:
     137                 :          0 :         m->op->stop(m, p);
     138                 :          0 :         kvfree(m->buf);
     139                 :          0 :         m->count = 0;
     140                 :          0 :         m->buf = seq_buf_alloc(m->size <<= 1);
     141                 :          0 :         return !m->buf ? -ENOMEM : -EAGAIN;
     142                 :            : }
     143                 :            : 
     144                 :            : /**
     145                 :            :  *      seq_read -      ->read() method for sequential files.
     146                 :            :  *      @file: the file to read from
     147                 :            :  *      @buf: the buffer to read to
     148                 :            :  *      @size: the maximum number of bytes to read
     149                 :            :  *      @ppos: the current position in the file
     150                 :            :  *
     151                 :            :  *      Ready-made ->f_op->read()
     152                 :            :  */
     153                 :          3 : ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     154                 :            : {
     155                 :          3 :         struct seq_file *m = file->private_data;
     156                 :            :         size_t copied = 0;
     157                 :            :         size_t n;
     158                 :            :         void *p;
     159                 :            :         int err = 0;
     160                 :            : 
     161                 :          3 :         mutex_lock(&m->lock);
     162                 :            : 
     163                 :            :         /*
     164                 :            :          * seq_file->op->..m_start/m_stop/m_next may do special actions
     165                 :            :          * or optimisations based on the file->f_version, so we want to
     166                 :            :          * pass the file->f_version to those methods.
     167                 :            :          *
     168                 :            :          * seq_file->version is just copy of f_version, and seq_file
     169                 :            :          * methods can treat it simply as file version.
     170                 :            :          * It is copied in first and copied out after all operations.
     171                 :            :          * It is convenient to have it as  part of structure to avoid the
     172                 :            :          * need of passing another argument to all the seq_file methods.
     173                 :            :          */
     174                 :          3 :         m->version = file->f_version;
     175                 :            : 
     176                 :            :         /*
     177                 :            :          * if request is to read from zero offset, reset iterator to first
     178                 :            :          * record as it might have been already advanced by previous requests
     179                 :            :          */
     180                 :          3 :         if (*ppos == 0) {
     181                 :          3 :                 m->index = 0;
     182                 :          3 :                 m->version = 0;
     183                 :          3 :                 m->count = 0;
     184                 :            :         }
     185                 :            : 
     186                 :            :         /* Don't assume *ppos is where we left it */
     187                 :          3 :         if (unlikely(*ppos != m->read_pos)) {
     188                 :          3 :                 while ((err = traverse(m, *ppos)) == -EAGAIN)
     189                 :            :                         ;
     190                 :          3 :                 if (err) {
     191                 :            :                         /* With prejudice... */
     192                 :          0 :                         m->read_pos = 0;
     193                 :          0 :                         m->version = 0;
     194                 :          0 :                         m->index = 0;
     195                 :          0 :                         m->count = 0;
     196                 :          0 :                         goto Done;
     197                 :            :                 } else {
     198                 :          3 :                         m->read_pos = *ppos;
     199                 :            :                 }
     200                 :            :         }
     201                 :            : 
     202                 :            :         /* grab buffer if we didn't have one */
     203                 :          3 :         if (!m->buf) {
     204                 :          3 :                 m->buf = seq_buf_alloc(m->size = PAGE_SIZE);
     205                 :          3 :                 if (!m->buf)
     206                 :            :                         goto Enomem;
     207                 :            :         }
     208                 :            :         /* if not empty - flush it first */
     209                 :          3 :         if (m->count) {
     210                 :          3 :                 n = min(m->count, size);
     211                 :          3 :                 err = copy_to_user(buf, m->buf + m->from, n);
     212                 :          3 :                 if (err)
     213                 :            :                         goto Efault;
     214                 :          3 :                 m->count -= n;
     215                 :          3 :                 m->from += n;
     216                 :          3 :                 size -= n;
     217                 :          3 :                 buf += n;
     218                 :            :                 copied += n;
     219                 :          3 :                 if (!size)
     220                 :            :                         goto Done;
     221                 :            :         }
     222                 :            :         /* we need at least one record in buffer */
     223                 :          3 :         m->from = 0;
     224                 :          3 :         p = m->op->start(m, &m->index);
     225                 :            :         while (1) {
     226                 :            :                 err = PTR_ERR(p);
     227                 :          3 :                 if (!p || IS_ERR(p))
     228                 :            :                         break;
     229                 :          3 :                 err = m->op->show(m, p);
     230                 :          3 :                 if (err < 0)
     231                 :            :                         break;
     232                 :          3 :                 if (unlikely(err))
     233                 :          3 :                         m->count = 0;
     234                 :          3 :                 if (unlikely(!m->count)) {
     235                 :          3 :                         p = m->op->next(m, p, &m->index);
     236                 :          3 :                         continue;
     237                 :            :                 }
     238                 :          3 :                 if (m->count < m->size)
     239                 :            :                         goto Fill;
     240                 :          3 :                 m->op->stop(m, p);
     241                 :          3 :                 kvfree(m->buf);
     242                 :          3 :                 m->count = 0;
     243                 :          3 :                 m->buf = seq_buf_alloc(m->size <<= 1);
     244                 :          3 :                 if (!m->buf)
     245                 :            :                         goto Enomem;
     246                 :          3 :                 m->version = 0;
     247                 :          3 :                 p = m->op->start(m, &m->index);
     248                 :            :         }
     249                 :          3 :         m->op->stop(m, p);
     250                 :          3 :         m->count = 0;
     251                 :          3 :         goto Done;
     252                 :            : Fill:
     253                 :            :         /* they want more? let's try to get some more */
     254                 :            :         while (1) {
     255                 :          3 :                 size_t offs = m->count;
     256                 :          3 :                 loff_t pos = m->index;
     257                 :            : 
     258                 :          3 :                 p = m->op->next(m, p, &m->index);
     259                 :          3 :                 if (pos == m->index)
     260                 :            :                         /* Buggy ->next function */
     261                 :          3 :                         m->index++;
     262                 :          3 :                 if (!p || IS_ERR(p)) {
     263                 :            :                         err = PTR_ERR(p);
     264                 :            :                         break;
     265                 :            :                 }
     266                 :          3 :                 if (m->count >= size)
     267                 :            :                         break;
     268                 :          3 :                 err = m->op->show(m, p);
     269                 :          3 :                 if (seq_has_overflowed(m) || err) {
     270                 :          3 :                         m->count = offs;
     271                 :          3 :                         if (likely(err <= 0))
     272                 :            :                                 break;
     273                 :            :                 }
     274                 :            :         }
     275                 :          3 :         m->op->stop(m, p);
     276                 :          3 :         n = min(m->count, size);
     277                 :          3 :         err = copy_to_user(buf, m->buf, n);
     278                 :          3 :         if (err)
     279                 :            :                 goto Efault;
     280                 :          3 :         copied += n;
     281                 :          3 :         m->count -= n;
     282                 :          3 :         m->from = n;
     283                 :            : Done:
     284                 :          3 :         if (!copied)
     285                 :          3 :                 copied = err;
     286                 :            :         else {
     287                 :          3 :                 *ppos += copied;
     288                 :          3 :                 m->read_pos += copied;
     289                 :            :         }
     290                 :          3 :         file->f_version = m->version;
     291                 :          3 :         mutex_unlock(&m->lock);
     292                 :          3 :         return copied;
     293                 :            : Enomem:
     294                 :            :         err = -ENOMEM;
     295                 :            :         goto Done;
     296                 :            : Efault:
     297                 :            :         err = -EFAULT;
     298                 :            :         goto Done;
     299                 :            : }
     300                 :            : EXPORT_SYMBOL(seq_read);
     301                 :            : 
     302                 :            : /**
     303                 :            :  *      seq_lseek -     ->llseek() method for sequential files.
     304                 :            :  *      @file: the file in question
     305                 :            :  *      @offset: new position
     306                 :            :  *      @whence: 0 for absolute, 1 for relative position
     307                 :            :  *
     308                 :            :  *      Ready-made ->f_op->llseek()
     309                 :            :  */
     310                 :          3 : loff_t seq_lseek(struct file *file, loff_t offset, int whence)
     311                 :            : {
     312                 :          3 :         struct seq_file *m = file->private_data;
     313                 :            :         loff_t retval = -EINVAL;
     314                 :            : 
     315                 :          3 :         mutex_lock(&m->lock);
     316                 :          3 :         m->version = file->f_version;
     317                 :          3 :         switch (whence) {
     318                 :            :         case SEEK_CUR:
     319                 :          3 :                 offset += file->f_pos;
     320                 :            :                 /* fall through */
     321                 :            :         case SEEK_SET:
     322                 :          3 :                 if (offset < 0)
     323                 :            :                         break;
     324                 :            :                 retval = offset;
     325                 :          3 :                 if (offset != m->read_pos) {
     326                 :          3 :                         while ((retval = traverse(m, offset)) == -EAGAIN)
     327                 :            :                                 ;
     328                 :          3 :                         if (retval) {
     329                 :            :                                 /* with extreme prejudice... */
     330                 :          0 :                                 file->f_pos = 0;
     331                 :          0 :                                 m->read_pos = 0;
     332                 :          0 :                                 m->version = 0;
     333                 :          0 :                                 m->index = 0;
     334                 :          0 :                                 m->count = 0;
     335                 :            :                         } else {
     336                 :          3 :                                 m->read_pos = offset;
     337                 :          3 :                                 retval = file->f_pos = offset;
     338                 :            :                         }
     339                 :            :                 } else {
     340                 :          3 :                         file->f_pos = offset;
     341                 :            :                 }
     342                 :            :         }
     343                 :          3 :         file->f_version = m->version;
     344                 :          3 :         mutex_unlock(&m->lock);
     345                 :          3 :         return retval;
     346                 :            : }
     347                 :            : EXPORT_SYMBOL(seq_lseek);
     348                 :            : 
     349                 :            : /**
     350                 :            :  *      seq_release -   free the structures associated with sequential file.
     351                 :            :  *      @file: file in question
     352                 :            :  *      @inode: its inode
     353                 :            :  *
     354                 :            :  *      Frees the structures associated with sequential file; can be used
     355                 :            :  *      as ->f_op->release() if you don't have private data to destroy.
     356                 :            :  */
     357                 :          3 : int seq_release(struct inode *inode, struct file *file)
     358                 :            : {
     359                 :          3 :         struct seq_file *m = file->private_data;
     360                 :          3 :         kvfree(m->buf);
     361                 :          3 :         kmem_cache_free(seq_file_cache, m);
     362                 :          3 :         return 0;
     363                 :            : }
     364                 :            : EXPORT_SYMBOL(seq_release);
     365                 :            : 
     366                 :            : /**
     367                 :            :  *      seq_escape -    print string into buffer, escaping some characters
     368                 :            :  *      @m:     target buffer
     369                 :            :  *      @s:     string
     370                 :            :  *      @esc:   set of characters that need escaping
     371                 :            :  *
     372                 :            :  *      Puts string into buffer, replacing each occurrence of character from
     373                 :            :  *      @esc with usual octal escape.
     374                 :            :  *      Use seq_has_overflowed() to check for errors.
     375                 :            :  */
     376                 :          3 : void seq_escape(struct seq_file *m, const char *s, const char *esc)
     377                 :            : {
     378                 :            :         char *buf;
     379                 :          3 :         size_t size = seq_get_buf(m, &buf);
     380                 :            :         int ret;
     381                 :            : 
     382                 :          3 :         ret = string_escape_str(s, buf, size, ESCAPE_OCTAL, esc);
     383                 :          3 :         seq_commit(m, ret < size ? ret : -1);
     384                 :          3 : }
     385                 :            : EXPORT_SYMBOL(seq_escape);
     386                 :            : 
     387                 :          0 : void seq_escape_mem_ascii(struct seq_file *m, const char *src, size_t isz)
     388                 :            : {
     389                 :            :         char *buf;
     390                 :          0 :         size_t size = seq_get_buf(m, &buf);
     391                 :            :         int ret;
     392                 :            : 
     393                 :          0 :         ret = string_escape_mem_ascii(src, isz, buf, size);
     394                 :          0 :         seq_commit(m, ret < size ? ret : -1);
     395                 :          0 : }
     396                 :            : EXPORT_SYMBOL(seq_escape_mem_ascii);
     397                 :            : 
     398                 :          3 : void seq_vprintf(struct seq_file *m, const char *f, va_list args)
     399                 :            : {
     400                 :            :         int len;
     401                 :            : 
     402                 :          3 :         if (m->count < m->size) {
     403                 :          3 :                 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
     404                 :          3 :                 if (m->count + len < m->size) {
     405                 :          3 :                         m->count += len;
     406                 :          3 :                         return;
     407                 :            :                 }
     408                 :            :         }
     409                 :            :         seq_set_overflow(m);
     410                 :            : }
     411                 :            : EXPORT_SYMBOL(seq_vprintf);
     412                 :            : 
     413                 :          3 : void seq_printf(struct seq_file *m, const char *f, ...)
     414                 :            : {
     415                 :            :         va_list args;
     416                 :            : 
     417                 :          3 :         va_start(args, f);
     418                 :          3 :         seq_vprintf(m, f, args);
     419                 :          3 :         va_end(args);
     420                 :          3 : }
     421                 :            : EXPORT_SYMBOL(seq_printf);
     422                 :            : 
     423                 :            : /**
     424                 :            :  *      mangle_path -   mangle and copy path to buffer beginning
     425                 :            :  *      @s: buffer start
     426                 :            :  *      @p: beginning of path in above buffer
     427                 :            :  *      @esc: set of characters that need escaping
     428                 :            :  *
     429                 :            :  *      Copy the path from @p to @s, replacing each occurrence of character from
     430                 :            :  *      @esc with usual octal escape.
     431                 :            :  *      Returns pointer past last written character in @s, or NULL in case of
     432                 :            :  *      failure.
     433                 :            :  */
     434                 :          3 : char *mangle_path(char *s, const char *p, const char *esc)
     435                 :            : {
     436                 :          3 :         while (s <= p) {
     437                 :          3 :                 char c = *p++;
     438                 :          3 :                 if (!c) {
     439                 :          3 :                         return s;
     440                 :          3 :                 } else if (!strchr(esc, c)) {
     441                 :          3 :                         *s++ = c;
     442                 :          0 :                 } else if (s + 4 > p) {
     443                 :            :                         break;
     444                 :            :                 } else {
     445                 :          0 :                         *s++ = '\\';
     446                 :          0 :                         *s++ = '0' + ((c & 0300) >> 6);
     447                 :          0 :                         *s++ = '0' + ((c & 070) >> 3);
     448                 :          0 :                         *s++ = '0' + (c & 07);
     449                 :            :                 }
     450                 :            :         }
     451                 :            :         return NULL;
     452                 :            : }
     453                 :            : EXPORT_SYMBOL(mangle_path);
     454                 :            : 
     455                 :            : /**
     456                 :            :  * seq_path - seq_file interface to print a pathname
     457                 :            :  * @m: the seq_file handle
     458                 :            :  * @path: the struct path to print
     459                 :            :  * @esc: set of characters to escape in the output
     460                 :            :  *
     461                 :            :  * return the absolute path of 'path', as represented by the
     462                 :            :  * dentry / mnt pair in the path parameter.
     463                 :            :  */
     464                 :          3 : int seq_path(struct seq_file *m, const struct path *path, const char *esc)
     465                 :            : {
     466                 :            :         char *buf;
     467                 :          3 :         size_t size = seq_get_buf(m, &buf);
     468                 :            :         int res = -1;
     469                 :            : 
     470                 :          3 :         if (size) {
     471                 :          3 :                 char *p = d_path(path, buf, size);
     472                 :          3 :                 if (!IS_ERR(p)) {
     473                 :          3 :                         char *end = mangle_path(buf, p, esc);
     474                 :          3 :                         if (end)
     475                 :          3 :                                 res = end - buf;
     476                 :            :                 }
     477                 :            :         }
     478                 :          3 :         seq_commit(m, res);
     479                 :            : 
     480                 :          3 :         return res;
     481                 :            : }
     482                 :            : EXPORT_SYMBOL(seq_path);
     483                 :            : 
     484                 :            : /**
     485                 :            :  * seq_file_path - seq_file interface to print a pathname of a file
     486                 :            :  * @m: the seq_file handle
     487                 :            :  * @file: the struct file to print
     488                 :            :  * @esc: set of characters to escape in the output
     489                 :            :  *
     490                 :            :  * return the absolute path to the file.
     491                 :            :  */
     492                 :          3 : int seq_file_path(struct seq_file *m, struct file *file, const char *esc)
     493                 :            : {
     494                 :          3 :         return seq_path(m, &file->f_path, esc);
     495                 :            : }
     496                 :            : EXPORT_SYMBOL(seq_file_path);
     497                 :            : 
     498                 :            : /*
     499                 :            :  * Same as seq_path, but relative to supplied root.
     500                 :            :  */
     501                 :          3 : int seq_path_root(struct seq_file *m, const struct path *path,
     502                 :            :                   const struct path *root, const char *esc)
     503                 :            : {
     504                 :            :         char *buf;
     505                 :          3 :         size_t size = seq_get_buf(m, &buf);
     506                 :            :         int res = -ENAMETOOLONG;
     507                 :            : 
     508                 :          3 :         if (size) {
     509                 :            :                 char *p;
     510                 :            : 
     511                 :          3 :                 p = __d_path(path, root, buf, size);
     512                 :          3 :                 if (!p)
     513                 :            :                         return SEQ_SKIP;
     514                 :            :                 res = PTR_ERR(p);
     515                 :          3 :                 if (!IS_ERR(p)) {
     516                 :          3 :                         char *end = mangle_path(buf, p, esc);
     517                 :          3 :                         if (end)
     518                 :          3 :                                 res = end - buf;
     519                 :            :                         else
     520                 :            :                                 res = -ENAMETOOLONG;
     521                 :            :                 }
     522                 :            :         }
     523                 :          3 :         seq_commit(m, res);
     524                 :            : 
     525                 :          3 :         return res < 0 && res != -ENAMETOOLONG ? res : 0;
     526                 :            : }
     527                 :            : 
     528                 :            : /*
     529                 :            :  * returns the path of the 'dentry' from the root of its filesystem.
     530                 :            :  */
     531                 :          3 : int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)
     532                 :            : {
     533                 :            :         char *buf;
     534                 :          3 :         size_t size = seq_get_buf(m, &buf);
     535                 :            :         int res = -1;
     536                 :            : 
     537                 :          3 :         if (size) {
     538                 :          3 :                 char *p = dentry_path(dentry, buf, size);
     539                 :          3 :                 if (!IS_ERR(p)) {
     540                 :          3 :                         char *end = mangle_path(buf, p, esc);
     541                 :          3 :                         if (end)
     542                 :          3 :                                 res = end - buf;
     543                 :            :                 }
     544                 :            :         }
     545                 :          3 :         seq_commit(m, res);
     546                 :            : 
     547                 :          3 :         return res;
     548                 :            : }
     549                 :            : EXPORT_SYMBOL(seq_dentry);
     550                 :            : 
     551                 :          3 : static void *single_start(struct seq_file *p, loff_t *pos)
     552                 :            : {
     553                 :          3 :         return NULL + (*pos == 0);
     554                 :            : }
     555                 :            : 
     556                 :          3 : static void *single_next(struct seq_file *p, void *v, loff_t *pos)
     557                 :            : {
     558                 :          3 :         ++*pos;
     559                 :          3 :         return NULL;
     560                 :            : }
     561                 :            : 
     562                 :          3 : static void single_stop(struct seq_file *p, void *v)
     563                 :            : {
     564                 :          3 : }
     565                 :            : 
     566                 :          3 : int single_open(struct file *file, int (*show)(struct seq_file *, void *),
     567                 :            :                 void *data)
     568                 :            : {
     569                 :            :         struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL_ACCOUNT);
     570                 :            :         int res = -ENOMEM;
     571                 :            : 
     572                 :          3 :         if (op) {
     573                 :          3 :                 op->start = single_start;
     574                 :          3 :                 op->next = single_next;
     575                 :          3 :                 op->stop = single_stop;
     576                 :          3 :                 op->show = show;
     577                 :          3 :                 res = seq_open(file, op);
     578                 :          3 :                 if (!res)
     579                 :          3 :                         ((struct seq_file *)file->private_data)->private = data;
     580                 :            :                 else
     581                 :          0 :                         kfree(op);
     582                 :            :         }
     583                 :          3 :         return res;
     584                 :            : }
     585                 :            : EXPORT_SYMBOL(single_open);
     586                 :            : 
     587                 :          1 : int single_open_size(struct file *file, int (*show)(struct seq_file *, void *),
     588                 :            :                 void *data, size_t size)
     589                 :            : {
     590                 :            :         char *buf = seq_buf_alloc(size);
     591                 :            :         int ret;
     592                 :          1 :         if (!buf)
     593                 :            :                 return -ENOMEM;
     594                 :          1 :         ret = single_open(file, show, data);
     595                 :          1 :         if (ret) {
     596                 :          0 :                 kvfree(buf);
     597                 :          0 :                 return ret;
     598                 :            :         }
     599                 :          1 :         ((struct seq_file *)file->private_data)->buf = buf;
     600                 :          1 :         ((struct seq_file *)file->private_data)->size = size;
     601                 :          1 :         return 0;
     602                 :            : }
     603                 :            : EXPORT_SYMBOL(single_open_size);
     604                 :            : 
     605                 :          3 : int single_release(struct inode *inode, struct file *file)
     606                 :            : {
     607                 :          3 :         const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
     608                 :          3 :         int res = seq_release(inode, file);
     609                 :          3 :         kfree(op);
     610                 :          3 :         return res;
     611                 :            : }
     612                 :            : EXPORT_SYMBOL(single_release);
     613                 :            : 
     614                 :          3 : int seq_release_private(struct inode *inode, struct file *file)
     615                 :            : {
     616                 :          3 :         struct seq_file *seq = file->private_data;
     617                 :            : 
     618                 :          3 :         kfree(seq->private);
     619                 :          3 :         seq->private = NULL;
     620                 :          3 :         return seq_release(inode, file);
     621                 :            : }
     622                 :            : EXPORT_SYMBOL(seq_release_private);
     623                 :            : 
     624                 :          3 : void *__seq_open_private(struct file *f, const struct seq_operations *ops,
     625                 :            :                 int psize)
     626                 :            : {
     627                 :            :         int rc;
     628                 :            :         void *private;
     629                 :            :         struct seq_file *seq;
     630                 :            : 
     631                 :          3 :         private = kzalloc(psize, GFP_KERNEL_ACCOUNT);
     632                 :          3 :         if (private == NULL)
     633                 :            :                 goto out;
     634                 :            : 
     635                 :          3 :         rc = seq_open(f, ops);
     636                 :          3 :         if (rc < 0)
     637                 :            :                 goto out_free;
     638                 :            : 
     639                 :          3 :         seq = f->private_data;
     640                 :          3 :         seq->private = private;
     641                 :          3 :         return private;
     642                 :            : 
     643                 :            : out_free:
     644                 :          0 :         kfree(private);
     645                 :            : out:
     646                 :            :         return NULL;
     647                 :            : }
     648                 :            : EXPORT_SYMBOL(__seq_open_private);
     649                 :            : 
     650                 :          3 : int seq_open_private(struct file *filp, const struct seq_operations *ops,
     651                 :            :                 int psize)
     652                 :            : {
     653                 :          3 :         return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
     654                 :            : }
     655                 :            : EXPORT_SYMBOL(seq_open_private);
     656                 :            : 
     657                 :          3 : void seq_putc(struct seq_file *m, char c)
     658                 :            : {
     659                 :          3 :         if (m->count >= m->size)
     660                 :          3 :                 return;
     661                 :            : 
     662                 :          3 :         m->buf[m->count++] = c;
     663                 :            : }
     664                 :            : EXPORT_SYMBOL(seq_putc);
     665                 :            : 
     666                 :          3 : void seq_puts(struct seq_file *m, const char *s)
     667                 :            : {
     668                 :          3 :         int len = strlen(s);
     669                 :            : 
     670                 :          3 :         if (m->count + len >= m->size) {
     671                 :            :                 seq_set_overflow(m);
     672                 :          3 :                 return;
     673                 :            :         }
     674                 :          3 :         memcpy(m->buf + m->count, s, len);
     675                 :          3 :         m->count += len;
     676                 :            : }
     677                 :            : EXPORT_SYMBOL(seq_puts);
     678                 :            : 
     679                 :            : /**
     680                 :            :  * A helper routine for putting decimal numbers without rich format of printf().
     681                 :            :  * only 'unsigned long long' is supported.
     682                 :            :  * @m: seq_file identifying the buffer to which data should be written
     683                 :            :  * @delimiter: a string which is printed before the number
     684                 :            :  * @num: the number
     685                 :            :  * @width: a minimum field width
     686                 :            :  *
     687                 :            :  * This routine will put strlen(delimiter) + number into seq_filed.
     688                 :            :  * This routine is very quick when you show lots of numbers.
     689                 :            :  * In usual cases, it will be better to use seq_printf(). It's easier to read.
     690                 :            :  */
     691                 :          3 : void seq_put_decimal_ull_width(struct seq_file *m, const char *delimiter,
     692                 :            :                          unsigned long long num, unsigned int width)
     693                 :            : {
     694                 :            :         int len;
     695                 :            : 
     696                 :          3 :         if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */
     697                 :            :                 goto overflow;
     698                 :            : 
     699                 :          3 :         if (delimiter && delimiter[0]) {
     700                 :          3 :                 if (delimiter[1] == 0)
     701                 :            :                         seq_putc(m, delimiter[0]);
     702                 :            :                 else
     703                 :          3 :                         seq_puts(m, delimiter);
     704                 :            :         }
     705                 :            : 
     706                 :          3 :         if (!width)
     707                 :            :                 width = 1;
     708                 :            : 
     709                 :          3 :         if (m->count + width >= m->size)
     710                 :            :                 goto overflow;
     711                 :            : 
     712                 :          3 :         len = num_to_str(m->buf + m->count, m->size - m->count, num, width);
     713                 :          3 :         if (!len)
     714                 :            :                 goto overflow;
     715                 :            : 
     716                 :          3 :         m->count += len;
     717                 :          3 :         return;
     718                 :            : 
     719                 :            : overflow:
     720                 :            :         seq_set_overflow(m);
     721                 :            : }
     722                 :            : 
     723                 :          3 : void seq_put_decimal_ull(struct seq_file *m, const char *delimiter,
     724                 :            :                          unsigned long long num)
     725                 :            : {
     726                 :          3 :         return seq_put_decimal_ull_width(m, delimiter, num, 0);
     727                 :            : }
     728                 :            : EXPORT_SYMBOL(seq_put_decimal_ull);
     729                 :            : 
     730                 :            : /**
     731                 :            :  * seq_put_hex_ll - put a number in hexadecimal notation
     732                 :            :  * @m: seq_file identifying the buffer to which data should be written
     733                 :            :  * @delimiter: a string which is printed before the number
     734                 :            :  * @v: the number
     735                 :            :  * @width: a minimum field width
     736                 :            :  *
     737                 :            :  * seq_put_hex_ll(m, "", v, 8) is equal to seq_printf(m, "%08llx", v)
     738                 :            :  *
     739                 :            :  * This routine is very quick when you show lots of numbers.
     740                 :            :  * In usual cases, it will be better to use seq_printf(). It's easier to read.
     741                 :            :  */
     742                 :          3 : void seq_put_hex_ll(struct seq_file *m, const char *delimiter,
     743                 :            :                                 unsigned long long v, unsigned int width)
     744                 :            : {
     745                 :            :         unsigned int len;
     746                 :            :         int i;
     747                 :            : 
     748                 :          3 :         if (delimiter && delimiter[0]) {
     749                 :          3 :                 if (delimiter[1] == 0)
     750                 :            :                         seq_putc(m, delimiter[0]);
     751                 :            :                 else
     752                 :          0 :                         seq_puts(m, delimiter);
     753                 :            :         }
     754                 :            : 
     755                 :            :         /* If x is 0, the result of __builtin_clzll is undefined */
     756                 :          3 :         if (v == 0)
     757                 :            :                 len = 1;
     758                 :            :         else
     759                 :          3 :                 len = (sizeof(v) * 8 - __builtin_clzll(v) + 3) / 4;
     760                 :            : 
     761                 :          3 :         if (len < width)
     762                 :            :                 len = width;
     763                 :            : 
     764                 :          3 :         if (m->count + len > m->size) {
     765                 :            :                 seq_set_overflow(m);
     766                 :          3 :                 return;
     767                 :            :         }
     768                 :            : 
     769                 :          3 :         for (i = len - 1; i >= 0; i--) {
     770                 :          3 :                 m->buf[m->count + i] = hex_asc[0xf & v];
     771                 :          3 :                 v = v >> 4;
     772                 :            :         }
     773                 :          3 :         m->count += len;
     774                 :            : }
     775                 :            : 
     776                 :          3 : void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num)
     777                 :            : {
     778                 :            :         int len;
     779                 :            : 
     780                 :          3 :         if (m->count + 3 >= m->size) /* we'll write 2 bytes at least */
     781                 :            :                 goto overflow;
     782                 :            : 
     783                 :          3 :         if (delimiter && delimiter[0]) {
     784                 :          3 :                 if (delimiter[1] == 0)
     785                 :            :                         seq_putc(m, delimiter[0]);
     786                 :            :                 else
     787                 :          0 :                         seq_puts(m, delimiter);
     788                 :            :         }
     789                 :            : 
     790                 :          3 :         if (m->count + 2 >= m->size)
     791                 :            :                 goto overflow;
     792                 :            : 
     793                 :          3 :         if (num < 0) {
     794                 :          3 :                 m->buf[m->count++] = '-';
     795                 :          3 :                 num = -num;
     796                 :            :         }
     797                 :            : 
     798                 :          3 :         if (num < 10) {
     799                 :          3 :                 m->buf[m->count++] = num + '0';
     800                 :          3 :                 return;
     801                 :            :         }
     802                 :            : 
     803                 :          3 :         len = num_to_str(m->buf + m->count, m->size - m->count, num, 0);
     804                 :          3 :         if (!len)
     805                 :            :                 goto overflow;
     806                 :            : 
     807                 :          3 :         m->count += len;
     808                 :          3 :         return;
     809                 :            : 
     810                 :            : overflow:
     811                 :            :         seq_set_overflow(m);
     812                 :            : }
     813                 :            : EXPORT_SYMBOL(seq_put_decimal_ll);
     814                 :            : 
     815                 :            : /**
     816                 :            :  * seq_write - write arbitrary data to buffer
     817                 :            :  * @seq: seq_file identifying the buffer to which data should be written
     818                 :            :  * @data: data address
     819                 :            :  * @len: number of bytes
     820                 :            :  *
     821                 :            :  * Return 0 on success, non-zero otherwise.
     822                 :            :  */
     823                 :          3 : int seq_write(struct seq_file *seq, const void *data, size_t len)
     824                 :            : {
     825                 :          3 :         if (seq->count + len < seq->size) {
     826                 :          3 :                 memcpy(seq->buf + seq->count, data, len);
     827                 :          3 :                 seq->count += len;
     828                 :          3 :                 return 0;
     829                 :            :         }
     830                 :            :         seq_set_overflow(seq);
     831                 :          3 :         return -1;
     832                 :            : }
     833                 :            : EXPORT_SYMBOL(seq_write);
     834                 :            : 
     835                 :            : /**
     836                 :            :  * seq_pad - write padding spaces to buffer
     837                 :            :  * @m: seq_file identifying the buffer to which data should be written
     838                 :            :  * @c: the byte to append after padding if non-zero
     839                 :            :  */
     840                 :          3 : void seq_pad(struct seq_file *m, char c)
     841                 :            : {
     842                 :          3 :         int size = m->pad_until - m->count;
     843                 :          3 :         if (size > 0) {
     844                 :          3 :                 if (size + m->count > m->size) {
     845                 :            :                         seq_set_overflow(m);
     846                 :          3 :                         return;
     847                 :            :                 }
     848                 :          3 :                 memset(m->buf + m->count, ' ', size);
     849                 :          3 :                 m->count += size;
     850                 :            :         }
     851                 :          3 :         if (c)
     852                 :            :                 seq_putc(m, c);
     853                 :            : }
     854                 :            : EXPORT_SYMBOL(seq_pad);
     855                 :            : 
     856                 :            : /* A complete analogue of print_hex_dump() */
     857                 :          0 : void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
     858                 :            :                   int rowsize, int groupsize, const void *buf, size_t len,
     859                 :            :                   bool ascii)
     860                 :            : {
     861                 :            :         const u8 *ptr = buf;
     862                 :          0 :         int i, linelen, remaining = len;
     863                 :            :         char *buffer;
     864                 :            :         size_t size;
     865                 :            :         int ret;
     866                 :            : 
     867                 :          0 :         if (rowsize != 16 && rowsize != 32)
     868                 :            :                 rowsize = 16;
     869                 :            : 
     870                 :          0 :         for (i = 0; i < len && !seq_has_overflowed(m); i += rowsize) {
     871                 :          0 :                 linelen = min(remaining, rowsize);
     872                 :          0 :                 remaining -= rowsize;
     873                 :            : 
     874                 :          0 :                 switch (prefix_type) {
     875                 :            :                 case DUMP_PREFIX_ADDRESS:
     876                 :          0 :                         seq_printf(m, "%s%p: ", prefix_str, ptr + i);
     877                 :          0 :                         break;
     878                 :            :                 case DUMP_PREFIX_OFFSET:
     879                 :          0 :                         seq_printf(m, "%s%.8x: ", prefix_str, i);
     880                 :          0 :                         break;
     881                 :            :                 default:
     882                 :          0 :                         seq_printf(m, "%s", prefix_str);
     883                 :          0 :                         break;
     884                 :            :                 }
     885                 :            : 
     886                 :          0 :                 size = seq_get_buf(m, &buffer);
     887                 :          0 :                 ret = hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
     888                 :            :                                          buffer, size, ascii);
     889                 :          0 :                 seq_commit(m, ret < size ? ret : -1);
     890                 :            : 
     891                 :            :                 seq_putc(m, '\n');
     892                 :            :         }
     893                 :          0 : }
     894                 :            : EXPORT_SYMBOL(seq_hex_dump);
     895                 :            : 
     896                 :          3 : struct list_head *seq_list_start(struct list_head *head, loff_t pos)
     897                 :            : {
     898                 :            :         struct list_head *lh;
     899                 :            : 
     900                 :          3 :         list_for_each(lh, head)
     901                 :          3 :                 if (pos-- == 0)
     902                 :          3 :                         return lh;
     903                 :            : 
     904                 :            :         return NULL;
     905                 :            : }
     906                 :            : EXPORT_SYMBOL(seq_list_start);
     907                 :            : 
     908                 :          0 : struct list_head *seq_list_start_head(struct list_head *head, loff_t pos)
     909                 :            : {
     910                 :          0 :         if (!pos)
     911                 :            :                 return head;
     912                 :            : 
     913                 :          0 :         return seq_list_start(head, pos - 1);
     914                 :            : }
     915                 :            : EXPORT_SYMBOL(seq_list_start_head);
     916                 :            : 
     917                 :          3 : struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos)
     918                 :            : {
     919                 :            :         struct list_head *lh;
     920                 :            : 
     921                 :          3 :         lh = ((struct list_head *)v)->next;
     922                 :          3 :         ++*ppos;
     923                 :          3 :         return lh == head ? NULL : lh;
     924                 :            : }
     925                 :            : EXPORT_SYMBOL(seq_list_next);
     926                 :            : 
     927                 :            : /**
     928                 :            :  * seq_hlist_start - start an iteration of a hlist
     929                 :            :  * @head: the head of the hlist
     930                 :            :  * @pos:  the start position of the sequence
     931                 :            :  *
     932                 :            :  * Called at seq_file->op->start().
     933                 :            :  */
     934                 :          0 : struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos)
     935                 :            : {
     936                 :            :         struct hlist_node *node;
     937                 :            : 
     938                 :          0 :         hlist_for_each(node, head)
     939                 :          0 :                 if (pos-- == 0)
     940                 :          0 :                         return node;
     941                 :            :         return NULL;
     942                 :            : }
     943                 :            : EXPORT_SYMBOL(seq_hlist_start);
     944                 :            : 
     945                 :            : /**
     946                 :            :  * seq_hlist_start_head - start an iteration of a hlist
     947                 :            :  * @head: the head of the hlist
     948                 :            :  * @pos:  the start position of the sequence
     949                 :            :  *
     950                 :            :  * Called at seq_file->op->start(). Call this function if you want to
     951                 :            :  * print a header at the top of the output.
     952                 :            :  */
     953                 :          0 : struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos)
     954                 :            : {
     955                 :          0 :         if (!pos)
     956                 :            :                 return SEQ_START_TOKEN;
     957                 :            : 
     958                 :          0 :         return seq_hlist_start(head, pos - 1);
     959                 :            : }
     960                 :            : EXPORT_SYMBOL(seq_hlist_start_head);
     961                 :            : 
     962                 :            : /**
     963                 :            :  * seq_hlist_next - move to the next position of the hlist
     964                 :            :  * @v:    the current iterator
     965                 :            :  * @head: the head of the hlist
     966                 :            :  * @ppos: the current position
     967                 :            :  *
     968                 :            :  * Called at seq_file->op->next().
     969                 :            :  */
     970                 :          0 : struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
     971                 :            :                                   loff_t *ppos)
     972                 :            : {
     973                 :            :         struct hlist_node *node = v;
     974                 :            : 
     975                 :          0 :         ++*ppos;
     976                 :          0 :         if (v == SEQ_START_TOKEN)
     977                 :          0 :                 return head->first;
     978                 :            :         else
     979                 :          0 :                 return node->next;
     980                 :            : }
     981                 :            : EXPORT_SYMBOL(seq_hlist_next);
     982                 :            : 
     983                 :            : /**
     984                 :            :  * seq_hlist_start_rcu - start an iteration of a hlist protected by RCU
     985                 :            :  * @head: the head of the hlist
     986                 :            :  * @pos:  the start position of the sequence
     987                 :            :  *
     988                 :            :  * Called at seq_file->op->start().
     989                 :            :  *
     990                 :            :  * This list-traversal primitive may safely run concurrently with
     991                 :            :  * the _rcu list-mutation primitives such as hlist_add_head_rcu()
     992                 :            :  * as long as the traversal is guarded by rcu_read_lock().
     993                 :            :  */
     994                 :          0 : struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
     995                 :            :                                        loff_t pos)
     996                 :            : {
     997                 :            :         struct hlist_node *node;
     998                 :            : 
     999                 :          0 :         __hlist_for_each_rcu(node, head)
    1000                 :          0 :                 if (pos-- == 0)
    1001                 :          0 :                         return node;
    1002                 :            :         return NULL;
    1003                 :            : }
    1004                 :            : EXPORT_SYMBOL(seq_hlist_start_rcu);
    1005                 :            : 
    1006                 :            : /**
    1007                 :            :  * seq_hlist_start_head_rcu - start an iteration of a hlist protected by RCU
    1008                 :            :  * @head: the head of the hlist
    1009                 :            :  * @pos:  the start position of the sequence
    1010                 :            :  *
    1011                 :            :  * Called at seq_file->op->start(). Call this function if you want to
    1012                 :            :  * print a header at the top of the output.
    1013                 :            :  *
    1014                 :            :  * This list-traversal primitive may safely run concurrently with
    1015                 :            :  * the _rcu list-mutation primitives such as hlist_add_head_rcu()
    1016                 :            :  * as long as the traversal is guarded by rcu_read_lock().
    1017                 :            :  */
    1018                 :          0 : struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
    1019                 :            :                                             loff_t pos)
    1020                 :            : {
    1021                 :          0 :         if (!pos)
    1022                 :            :                 return SEQ_START_TOKEN;
    1023                 :            : 
    1024                 :          0 :         return seq_hlist_start_rcu(head, pos - 1);
    1025                 :            : }
    1026                 :            : EXPORT_SYMBOL(seq_hlist_start_head_rcu);
    1027                 :            : 
    1028                 :            : /**
    1029                 :            :  * seq_hlist_next_rcu - move to the next position of the hlist protected by RCU
    1030                 :            :  * @v:    the current iterator
    1031                 :            :  * @head: the head of the hlist
    1032                 :            :  * @ppos: the current position
    1033                 :            :  *
    1034                 :            :  * Called at seq_file->op->next().
    1035                 :            :  *
    1036                 :            :  * This list-traversal primitive may safely run concurrently with
    1037                 :            :  * the _rcu list-mutation primitives such as hlist_add_head_rcu()
    1038                 :            :  * as long as the traversal is guarded by rcu_read_lock().
    1039                 :            :  */
    1040                 :          0 : struct hlist_node *seq_hlist_next_rcu(void *v,
    1041                 :            :                                       struct hlist_head *head,
    1042                 :            :                                       loff_t *ppos)
    1043                 :            : {
    1044                 :            :         struct hlist_node *node = v;
    1045                 :            : 
    1046                 :          0 :         ++*ppos;
    1047                 :          0 :         if (v == SEQ_START_TOKEN)
    1048                 :          0 :                 return rcu_dereference(head->first);
    1049                 :            :         else
    1050                 :          0 :                 return rcu_dereference(node->next);
    1051                 :            : }
    1052                 :            : EXPORT_SYMBOL(seq_hlist_next_rcu);
    1053                 :            : 
    1054                 :            : /**
    1055                 :            :  * seq_hlist_start_precpu - start an iteration of a percpu hlist array
    1056                 :            :  * @head: pointer to percpu array of struct hlist_heads
    1057                 :            :  * @cpu:  pointer to cpu "cursor"
    1058                 :            :  * @pos:  start position of sequence
    1059                 :            :  *
    1060                 :            :  * Called at seq_file->op->start().
    1061                 :            :  */
    1062                 :            : struct hlist_node *
    1063                 :          0 : seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos)
    1064                 :            : {
    1065                 :            :         struct hlist_node *node;
    1066                 :            : 
    1067                 :          0 :         for_each_possible_cpu(*cpu) {
    1068                 :          0 :                 hlist_for_each(node, per_cpu_ptr(head, *cpu)) {
    1069                 :          0 :                         if (pos-- == 0)
    1070                 :          0 :                                 return node;
    1071                 :            :                 }
    1072                 :            :         }
    1073                 :            :         return NULL;
    1074                 :            : }
    1075                 :            : EXPORT_SYMBOL(seq_hlist_start_percpu);
    1076                 :            : 
    1077                 :            : /**
    1078                 :            :  * seq_hlist_next_percpu - move to the next position of the percpu hlist array
    1079                 :            :  * @v:    pointer to current hlist_node
    1080                 :            :  * @head: pointer to percpu array of struct hlist_heads
    1081                 :            :  * @cpu:  pointer to cpu "cursor"
    1082                 :            :  * @pos:  start position of sequence
    1083                 :            :  *
    1084                 :            :  * Called at seq_file->op->next().
    1085                 :            :  */
    1086                 :            : struct hlist_node *
    1087                 :          0 : seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head,
    1088                 :            :                         int *cpu, loff_t *pos)
    1089                 :            : {
    1090                 :            :         struct hlist_node *node = v;
    1091                 :            : 
    1092                 :          0 :         ++*pos;
    1093                 :            : 
    1094                 :          0 :         if (node->next)
    1095                 :            :                 return node->next;
    1096                 :            : 
    1097                 :          0 :         for (*cpu = cpumask_next(*cpu, cpu_possible_mask); *cpu < nr_cpu_ids;
    1098                 :          0 :              *cpu = cpumask_next(*cpu, cpu_possible_mask)) {
    1099                 :          0 :                 struct hlist_head *bucket = per_cpu_ptr(head, *cpu);
    1100                 :            : 
    1101                 :          0 :                 if (!hlist_empty(bucket))
    1102                 :          0 :                         return bucket->first;
    1103                 :            :         }
    1104                 :            :         return NULL;
    1105                 :            : }
    1106                 :            : EXPORT_SYMBOL(seq_hlist_next_percpu);
    1107                 :            : 
    1108                 :          3 : void __init seq_file_init(void)
    1109                 :            : {
    1110                 :          3 :         seq_file_cache = KMEM_CACHE(seq_file, SLAB_ACCOUNT|SLAB_PANIC);
    1111                 :          3 : }
    

Generated by: LCOV version 1.14