LCOV - code coverage report
Current view: top level - fs - seq_file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 237 362 65.5 %
Date: 2014-02-18 Functions: 35 40 87.5 %
Branches: 121 220 55.0 %

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

Generated by: LCOV version 1.9