/*
@Author: Ayush Shah :)
@Institution: BIT Mesra :)
*/

#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/pb_ds/tree_policy.hpp> 
using namespace __gnu_pbds;
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;


template <typename T>
using min_pq = priority_queue<T, vector<T>, greater<T>>;

#define deb(x) cout << #x << " " << x << endl;
#define deb1(x, y) cout << #x << " " << x << " " << #y << " " << y << endl;
#define deb2(x, y, z) cout << #x << " " << x << " " << #y << " " << y << " " << #z << " " << z << endl;
#define fast  ios_base::sync_with_stdio(false), cin.tie(NULL) , cout.tie(NULL)
#define test int T1; cin >> T1; while(T1--)
#define ui  unsigned int
#define ll  long long int 
#define ld  long double
#define pb  push_back
#define mp  make_pair
#define all(v) (v).begin(),(v).end()
#define rall(v) (v).rbegin(),(v).rend()
#define vll vector<ll>
#define pi pair<int, int>
#define pll pair<ll, ll>
#define vpll vector< pll >
#define bigint int64_t
#define mod 1000000007
#define endl '\n'

#define forn(i,a,n) for(ll (i) = a;(i) <= (n); (i)++)
#define forr(i,a,n) for(ll (i) = n; (i) >= (a); (i)--)

typedef tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

/////////////////////////////////////////////***NUMBER THEORY***///////////////////////////////////////////////////////////////

vll seive;
void Seive (ll N) {
    seive.resize(N+1);
    forn (i, 1, N)
    seive[i] = i;
    for (ll i = 4; i <= N; i += 2)
    seive[i] = 2;
    for (ll i = 3; i*i <= N; i++) {
        if (seive[i] == i) {
            for (ll j = i*i; j <= N; j += i) {
                if (seive[j] == j)
                seive[j] = i;
            }
        }
    }
}

ll Power(ll x, ll n){
    if(n==0)
    return 1;
    
    if(n%2)
    return x*Power(x*x, (n-1)/2);
    else
    return Power(x*x, n/2);
}

ll Power_with_mod(ll x, ll n, ll m = mod){
    if(n==0)
    return 1;
    
    if(n%2)
    return (x*Power_with_mod((x*x)%m, (n-1)/2))%m;
    else
    return Power_with_mod((x*x)%m, n/2);
}

ll gcd(ll a, ll b){
    if(b == 0)
    return a;

    return gcd(b, a%b);
}

ll x, y, d;
void extended_euclid(ll a, ll b){
    if(b == 0){
        x = 1;
        y = 0;
        d = a;
    }
    else{
        extended_euclid(b, a%b);
        ll temp = x;
        x = y;
        y = temp - (a/b)*y;
    }
}

ll mod_inverse(ll a, ll m = mod){
    extended_euclid(a, m);
    return((x+m)%m);
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template<typename T>
class DSU{
    public:
      T parent [200005];
      T size [200005];
      DSU(ll n) {
          forn (i, 1, n) {
              parent[i] = i;
              size[i] = 1;
          }
      }
      T root(T x){
          if(parent[x] == x)
          return x;
          return parent[x] = root(parent[x]);
      }
      void Union(T x, T y){
          x = root(x);
          y = root(y);
          if(x != y){
              if(size[x] < size[y])
              swap(x, y);
              parent[y] = x;
              size[x] += size[y];
          }
      }
};

template <typename T>
class Segment_Tree{
    public:
      ll tree[4*100005 + 3];

      Segment_Tree() {
          memset(tree, 0, sizeof tree);
      }

      void build(ll node, ll s, ll e){
          if(s == e)
          tree[node] = 0;
          else{
              ll mid = (s + e)/2;
              build(2*node, s, mid);
              build(2*node+1, mid+1, e);
              tree[node] = (tree[2*node] + tree[2*node+1]);
          }
      }

      void update(ll node, ll s, ll e, ll pos, ll val){
          if(s == e){
              tree[node] += val;
          }
          else{
              ll mid = (s + e) >> 1;
              if(pos <= mid)
              update(2*node+1, s, mid, pos, val);
              else
              update(2*node+2, mid+1, e, pos, val);
              tree[node] = (tree[2*node+1] + tree[2*node+2]);
          }
      }

      ll query(ll node, ll s, ll e, ll l, ll r){
          if (s > e || s > r || e < l)
          return 0ll;
          if(s >= l && e <= r) {
              return tree[node];
          }
          else{
              ll mid = (s + e) >> 1;
              ll left = query(2*node+1, s, mid, l, r);
              ll right = query(2*node+2, mid+1, e, l, r);
              return (left + right);
          }
      }
};  

const int N = 100005;
vll g[N];
bool vis[N];
ll dp[N];

void dfs(ll s) {
    vis[s] = true;
    for (auto it: g[s]) {
        if (!vis[it]) {
            dfs(it);
            dp[s] = max(dp[s], 1 + dp[it]);
        } else
        {
            dp[s] = max(dp[s], 1 + dp[it]);
        }
        
    }
}

int main()
{

     fast;
  
    ll n, m;
    cin >> n >> m;
    ll x, y;
    while (m--) {
        cin >> x >> y;
        g[x].pb(y);
    }
    memset(dp, 0, sizeof dp);
    memset(vis, false, sizeof vis);
    forn (i, 1, n) {
        if (!vis[i]) {
            dfs(i);
        }
    }
    ll ans = 0;
    forn (i, 1, n)
    ans = max(ans, dp[i]);
    cout << ans;

    return 0;

}


Measured memory_bytes: 8704